Your IP : 216.73.216.50


Current Path : /proc/1908984/root/proc/self/root/proc/self/root/proc/2411249/cwd/
Upload File :
Current File : //proc/1908984/root/proc/self/root/proc/self/root/proc/2411249/cwd/Platform.tar

Base/Filesystem.php000064400000007152152346020460010262 0ustar00<?php
/**
 * @package     FOF
 * @copyright   Copyright (c)2010-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license     GNU GPL version 2 or later
 */

namespace FOF30\Platform\Base;

use FOF30\Container\Container;
use FOF30\Platform\FilesystemInterface;

defined('_JEXEC') or die;

abstract class Filesystem implements FilesystemInterface
{
	/** @var  Container  The component container */
	protected $container = null;

	/**
	 * Public constructor.
	 *
	 * @param   \FOF30\Container\Container  $c  The component container
	 */
	public function __construct(Container $c)
	{
		$this->container = $c;
	}

	/**
	 * The list of paths where platform class files will be looked for
	 *
	 * @var  array
	 */
	protected static $paths = array();

	/**
	 * This method will crawl a starting directory and get all the valid files that will be analyzed by getInstance.
	 * Then it organizes them into an associative array.
	 *
	 * @param   string  $path               Folder where we should start looking
	 * @param   array   $ignoreFolders      Folder ignore list
	 * @param   array   $ignoreFiles        File ignore list
	 *
	 * @return  array   Associative array, where the `fullpath` key contains the path to the file,
	 *                  and the `classname` key contains the name of the class
	 */
	protected static function getFiles($path, array $ignoreFolders = array(), array $ignoreFiles = array())
	{
		$return = array();

		$files  = self::scanDirectory($path, $ignoreFolders, $ignoreFiles);

		// Ok, I got the files, now I have to organize them
		foreach($files as $file)
		{
			$clean = str_replace($path, '', $file);
			$clean = trim(str_replace('\\', '/', $clean), '/');

			$parts = explode('/', $clean);

			// If I have less than 3 fragments, it means that the file was inside the generic folder
			// (interface + abstract) so I have to skip it
			if(count($parts) < 3)
			{
				continue;
			}

			$return[] = array(
				'fullpath'  => $file,
				'classname' => 'F0FPlatform'.ucfirst($parts[0]).ucfirst(basename($parts[1], '.php'))
			);
		}

		return $return;
	}

	/**
	 * Recursive function that will scan every directory unless it's in the ignore list. Files that aren't in the
	 * ignore list are returned.
	 *
	 * @param   string  $path               Folder where we should start looking
	 * @param   array   $ignoreFolders      Folder ignore list
	 * @param   array   $ignoreFiles        File ignore list
	 *
	 * @return  array   List of all the files
	 */
	protected static function scanDirectory($path, array $ignoreFolders = array(), array $ignoreFiles = array())
	{
		$return = array();

		$handle = @opendir($path);

		if(!$handle)
		{
			return $return;
		}

		while (($file = readdir($handle)) !== false)
		{
			if($file == '.' || $file == '..')
			{
				continue;
			}

			$fullpath = $path . '/' . $file;

			if((is_dir($fullpath) && in_array($file, $ignoreFolders)) || (is_file($fullpath) && in_array($file, $ignoreFiles)))
			{
				continue;
			}

			if(is_dir($fullpath))
			{
				$return = array_merge(self::scanDirectory($fullpath, $ignoreFolders, $ignoreFiles), $return);
			}
			else
			{
				$return[] = $path . '/' . $file;
			}
		}

		return $return;
	}

	/**
	 * Gets the extension of a file name
	 *
	 * @param   string  $file  The file name
	 *
	 * @return  string  The file extension
	 */
	public function getExt($file)
	{
		$dot = strrpos($file, '.') + 1;

		return substr($file, $dot);
	}

	/**
	 * Strips the last extension off of a file name
	 *
	 * @param   string  $file  The file name
	 *
	 * @return  string  The file name without the extension
	 */
	public function stripExt($file)
	{
		return preg_replace('#\.[^.]*$#', '', $file);
	}
}
Base/Platform.php000064400000022235152346020460007721 0ustar00<?php
/**
 * @package     FOF
 * @copyright   Copyright (c)2010-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license     GNU GPL version 2 or later
 */

namespace FOF30\Platform\Base;

use Exception;
use FOF30\Container\Container;
use FOF30\Input\Input;
use FOF30\Platform\PlatformInterface;

defined('_JEXEC') or die;

/**
 * Abstract implementation of the Platform integration
 *
 * @package FOF30\Platform\Base
 */
abstract class Platform implements PlatformInterface
{
	/** @var  Container  The component container */
	protected $container = null;

	/**
	 * Public constructor.
	 *
	 * @param   \FOF30\Container\Container  $c  The component container
	 */
	public function __construct(Container $c)
	{
		$this->container = $c;
	}

	/**
	 * Returns the base (root) directories for a given component.
	 *
	 * @param   string  $component  The name of the component. For Joomla! this
	 *                              is something like "com_example"
	 *
	 * @see F0FPlatformInterface::getComponentBaseDirs()
	 *
	 * @return  array  A hash array with keys main, alt, site and admin.
	 */
	public function getComponentBaseDirs($component)
	{
		return array(
			'main'	=> '',
			'alt'	=> '',
			'site'	=> '',
			'admin'	=> '',
		);
	}

	/**
	 * Returns the application's template name
	 *
	 * @param   boolean|array  $params  An optional associative array of configuration settings
	 *
	 * @return  string  The template name. System is the fallback.
	 */
	public function getTemplate($params = false)
	{
		return 'system';
	}

	/**
	 * Get application-specific suffixes to use with template paths. This allows
	 * you to look for view template overrides based on the application version.
	 *
	 * @return  array  A plain array of suffixes to try in template names
	 */
	public function getTemplateSuffixes()
	{
		return array();
	}

	/**
	 * Return the absolute path to the application's template overrides
	 * directory for a specific component. We will use it to look for template
	 * files instead of the regular component directories. If the application
	 * does not have such a thing as template overrides return an empty string.
	 *
	 * @param   string   $component  The name of the component for which to fetch the overrides
	 * @param   boolean  $absolute   Should I return an absolute or relative path?
	 *
	 * @return  string  The path to the template overrides directory
	 */
	public function getTemplateOverridePath($component, $absolute = true)
	{
		return '';
	}

	/**
	 * Load the translation files for a given component.
	 *
	 * @param   string  $component  The name of the component. For Joomla! this
	 *                              is something like "com_example"
	 *
	 * @see F0FPlatformInterface::loadTranslations()
	 *
	 * @return  void
	 */
	public function loadTranslations($component)
	{
		return null;
	}

	/**
	 * Authorise access to the component in the back-end.
	 *
	 * @param   string  $component  The name of the component.
	 *
	 * @see F0FPlatformInterface::authorizeAdmin()
	 *
	 * @return  boolean  True to allow loading the component, false to halt loading
	 */
	public function authorizeAdmin($component)
	{
		return true;
	}

	/**
	 * Returns the JUser object for the current user
	 *
	 * @param   integer  $id  The ID of the user to fetch
	 *
	 * @see F0FPlatformInterface::getUser()
	 *
	 * @return  \JDocument
	 */
	public function getUser($id = null)
	{
		return null;
	}

	/**
	 * Returns the JDocument object which handles this component's response.
	 *
	 * @see F0FPlatformInterface::getDocument()
	 *
	 * @return  \JDocument
	 */
	public function getDocument()
	{
		return null;
	}

	/**
	 * This method will try retrieving a variable from the request (input) data.
	 *
	 * @param   string    $key           The user state key for the variable
	 * @param   string    $request       The request variable name for the variable
	 * @param   Input     $input         The Input object with the request (input) data
	 * @param   mixed     $default       The default value. Default: null
	 * @param   string    $type          The filter type for the variable data. Default: none (no filtering)
	 * @param   boolean   $setUserState  Should I set the user state with the fetched value?
	 *
	 * @see F0FPlatformInterface::getUserStateFromRequest()
	 *
	 * @return  mixed  The value of the variable
	 */
	public function getUserStateFromRequest($key, $request, $input, $default = null, $type = 'none', $setUserState = true)
	{
		return $input->get($request, $default, $type);
	}

	/**
	 * Load plugins of a specific type. Obviously this seems to only be required
	 * in the Joomla! CMS.
	 *
	 * @param   string  $type  The type of the plugins to be loaded
	 *
	 * @see F0FPlatformInterface::importPlugin()
	 *
	 * @return void
	 */
	public function importPlugin($type)
	{
	}

	/**
	 * Execute plugins (system-level triggers) and fetch back an array with
	 * their return values.
	 *
	 * @param   string  $event  The event (trigger) name, e.g. onBeforeScratchMyEar
	 * @param   array   $data   A hash array of data sent to the plugins as part of the trigger
	 *
	 * @see F0FPlatformInterface::runPlugins()
	 *
	 * @return  array  A simple array containing the results of the plugins triggered
	 */
	public function runPlugins($event, $data)
	{
		return array();
	}

	/**
	 * Perform an ACL check.
	 *
	 * @param   string  $action     The ACL privilege to check, e.g. core.edit
	 * @param   string  $assetname  The asset name to check, typically the component's name
	 *
	 * @see F0FPlatformInterface::authorise()
	 *
	 * @return  boolean  True if the user is allowed this action
	 */
	public function authorise($action, $assetname)
	{
		return true;
	}

	/**
	 * Is this the administrative section of the component?
	 *
	 * @see F0FPlatformInterface::isBackend()
	 *
	 * @return  boolean
	 */
	public function isBackend()
	{
		return true;
	}

	/**
	 * Is this the public section of the component?
	 *
	 * @see F0FPlatformInterface::isFrontend()
	 *
	 * @return  boolean
	 */
	public function isFrontend()
	{
		return true;
	}

	/**
	 * Is this a component running in a CLI application?
	 *
	 * @see F0FPlatformInterface::isCli()
	 *
	 * @return  boolean
	 */
	public function isCli()
	{
		return true;
	}

	/**
	 * Is AJAX re-ordering supported? This is 100% Joomla!-CMS specific. All
	 * other platforms should return false and never ask why.
	 *
	 * @see F0FPlatformInterface::supportsAjaxOrdering()
	 *
	 * @return  boolean
	 */
	public function supportsAjaxOrdering()
	{
		return true;
	}

	/**
	 * Saves something to the cache. This is supposed to be used for system-wide
	 * F0F data, not application data.
	 *
	 * @param   string  $key      The key of the data to save
	 * @param   string  $content  The actual data to save
	 *
	 * @return  boolean  True on success
	 */
	public function setCache($key, $content)
	{
		return false;
	}

	/**
	 * Retrieves data from the cache. This is supposed to be used for system-side
	 * F0F data, not application data.
	 *
	 * @param   string  $key      The key of the data to retrieve
	 * @param   string  $default  The default value to return if the key is not found or the cache is not populated
	 *
	 * @return  string  The cached value
	 */
	public function getCache($key, $default = null)
	{
		return false;
	}

	/**
	 * Is the global F0F cache enabled?
	 *
	 * @return  boolean
	 */
	public function isGlobalFOFCacheEnabled()
	{
		return true;
	}

	/**
	 * Clears the cache of system-wide F0F data. You are supposed to call this in
	 * your components' installation script post-installation and post-upgrade
	 * methods or whenever you are modifying the structure of database tables
	 * accessed by F0F. Please note that F0F's cache never expires and is not
	 * purged by Joomla!. You MUST use this method to manually purge the cache.
	 *
	 * @return  boolean  True on success
	 */
	public function clearCache()
	{
		return false;
	}

	/**
	 * logs in a user
	 *
	 * @param   array  $authInfo  authentification information
	 *
	 * @return  boolean  True on success
	 */
	public function loginUser($authInfo)
	{
		return true;
	}

	/**
	 * logs out a user
	 *
	 * @return  boolean  True on success
	 */
	public function logoutUser()
	{
		return true;
	}

	/**
	 * Logs a deprecated practice. In Joomla! this results in the $message being output in the
	 * deprecated log file, found in your site's log directory.
	 *
	 * @param   string  $message  The deprecated practice log message
	 *
	 * @return  void
	 */
	public function logDeprecated($message)
	{
		// The default implementation does nothing. Override this in your platform classes.
	}

	public function logUserAction($title, $logText, $extension)
	{
		// The default implementation does nothing. Override this in your platform classes.
	}

	/**
	 * Returns the version number string of the platform, e.g. "4.5.6". If
	 * implementation integrates with a CMS or a versioned foundation (e.g.
	 * a framework) it is advisable to return that version.
	 *
	 * @return  string
	 *
	 * @since  2.1.2
	 */
	public function getPlatformVersion()
	{
		return '';
	}

	/**
	 * Handle an exception in a way that results to an error page.
	 *
	 * @param   Exception  $exception  The exception to handle
	 *
	 * @throws  Exception  Possibly rethrown exception
	 */
	public function showErrorPage(Exception $exception)
	{
		throw $exception;
	}
}
Joomla/Filesystem.php000064400000014226152346020460010631 0ustar00<?php
/**
 * @package     FOF
 * @copyright   Copyright (c)2010-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license     GNU GPL version 2 or later
 */

namespace FOF30\Platform\Joomla;

use FOF30\Container\Container;
use FOF30\Platform\Base\Filesystem as BaseFilesystem;

defined('_JEXEC') or die;

/**
 * Abstraction for Joomla! filesystem API
 */
class Filesystem extends BaseFilesystem
{
	/**
	 * Public constructor
	 *
	 * @param \FOF30\Container\Container $c
	 */
	public function __construct(Container $c)
	{
		if (class_exists('\\JLoader'))
		{
			\JLoader::import('joomla.filesystem.path');
			\JLoader::import('joomla.filesystem.folder');
			\JLoader::import('joomla.filesystem.file');
		}

		parent::__construct($c);
	}

	/**
	 * Does the file exists?
	 *
	 * @param   $path  string   Path to the file to test
	 *
	 * @return  bool
	 */
	public function fileExists($path)
	{
		return \JFile::exists($path);
	}

	/**
	 * Delete a file or array of files
	 *
	 * @param   mixed  $file  The file name or an array of file names
	 *
	 * @return  boolean  True on success
	 *
	 */
	public function fileDelete($file)
	{
		return \JFile::delete($file);
	}

	/**
	 * Copies a file
	 *
	 * @param   string   $src          The path to the source file
	 * @param   string   $dest         The path to the destination file
	 * @param   string   $path         An optional base path to prefix to the file names
	 * @param   boolean  $use_streams  True to use streams
	 *
	 * @return  boolean  True on success
	 */
	public function fileCopy($src, $dest, $path = null, $use_streams = false)
	{
		return \JFile::copy($src, $dest, $path, $use_streams);
	}

	/**
	 * Write contents to a file
	 *
	 * @param   string   $file         The full file path
	 * @param   string   &$buffer      The buffer to write
	 * @param   boolean  $use_streams  Use streams
	 *
	 * @return  boolean  True on success
	 */
	public function fileWrite($file, &$buffer, $use_streams = false)
	{
		return \JFile::write($file, $buffer, $use_streams);
	}

	/**
	 * Checks for snooping outside of the file system root.
	 *
	 * @param   string  $path  A file system path to check.
	 *
	 * @return  string  A cleaned version of the path or exit on error.
	 *
	 * @throws  \Exception
	 */
	public function pathCheck($path)
	{
		return \JPath::check($path);
	}

	/**
	 * Function to strip additional / or \ in a path name.
	 *
	 * @param   string  $path  The path to clean.
	 * @param   string  $ds    Directory separator (optional).
	 *
	 * @return  string  The cleaned path.
	 *
	 * @throws  \UnexpectedValueException
	 */
	public function pathClean($path, $ds = DIRECTORY_SEPARATOR)
	{
		return \JPath::clean($path, $ds);
	}

	/**
	 * Searches the directory paths for a given file.
	 *
	 * @param   mixed   $paths  An path string or array of path strings to search in
	 * @param   string  $file   The file name to look for.
	 *
	 * @return  mixed   The full path and file name for the target file, or boolean false if the file is not found in any of the paths.
	 */
	public function pathFind($paths, $file)
	{
		return \JPath::find($paths, $file);
	}

	/**
	 * Wrapper for the standard file_exists function
	 *
	 * @param   string  $path  Folder name relative to installation dir
	 *
	 * @return  boolean  True if path is a folder
	 */
	public function folderExists($path)
	{
		try
		{
			return \JFolder::exists($path);
		}
		catch (\Exception $e)
		{
			return false;
		}
	}

	/**
	 * Utility function to read the files in a folder.
	 *
	 * @param   string   $path           The path of the folder to read.
	 * @param   string   $filter         A filter for file names.
	 * @param   mixed    $recurse        True to recursively search into sub-folders, or an integer to specify the maximum depth.
	 * @param   boolean  $full           True to return the full path to the file.
	 * @param   array    $exclude        Array with names of files which should not be shown in the result.
	 * @param   array    $excludefilter  Array of filter to exclude
	 * @param   boolean  $naturalSort    False for asort, true for natsort
	 *
	 * @return  array  Files in the given folder.
	 */
	public function folderFiles($path, $filter = '.', $recurse = false, $full = false, $exclude = array('.svn', 'CVS', '.DS_Store', '__MACOSX'),
								$excludefilter = array('^\..*', '.*~'), $naturalSort = false)
	{
		// JFolder throws nonsense errors if the path is not a folder
		try
		{
			$path = \JPath::clean($path);
		}
		catch (\Exception $e)
		{
			return array();
		}

		if (!@is_dir($path))
		{
			return array();
		}

		// Now call JFolder
		return \JFolder::files($path, $filter, $recurse, $full, $exclude, $excludefilter, $naturalSort);
	}

	/**
	 * Utility function to read the folders in a folder.
	 *
	 * @param   string   $path           The path of the folder to read.
	 * @param   string   $filter         A filter for folder names.
	 * @param   mixed    $recurse        True to recursively search into sub-folders, or an integer to specify the maximum depth.
	 * @param   boolean  $full           True to return the full path to the folders.
	 * @param   array    $exclude        Array with names of folders which should not be shown in the result.
	 * @param   array    $excludefilter  Array with regular expressions matching folders which should not be shown in the result.
	 *
	 * @return  array  Folders in the given folder.
	 */
	public function folderFolders($path, $filter = '.', $recurse = false, $full = false, $exclude = array('.svn', 'CVS', '.DS_Store', '__MACOSX'),
								  $excludefilter = array('^\..*'))
	{
		// JFolder throws idiotic errors if the path is not a folder
		try
		{
			$path = \JPath::clean($path);
		}
		catch (\Exception $e)
		{
			return array();
		}

		if (!@is_dir($path))
		{
			return array();
		}

		// Now call JFolder
		return \JFolder::folders($path, $filter, $recurse, $full, $exclude, $excludefilter);
	}

	/**
	 * Create a folder -- and all necessary parent folders.
	 *
	 * @param   string   $path  A path to create from the base path.
	 * @param   integer  $mode  Directory permissions to set for folders created. 0755 by default.
	 *
	 * @return  boolean  True if successful.
	 */
	public function folderCreate($path = '', $mode = 0755)
	{
		return \JFolder::create($path, $mode);
	}
}
Joomla/Platform.php000064400000074320152346020460010272 0ustar00<?php
/**
 * @package     FOF
 * @copyright   Copyright (c)2010-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license     GNU GPL version 2 or later
 */

namespace FOF30\Platform\Joomla;

use Exception;
use FOF30\Container\Container;
use FOF30\Date\Date;
use FOF30\Date\DateDecorator;
use FOF30\Input\Input;
use FOF30\Platform\Base\Platform as BasePlatform;
use JApplicationCli;
use JApplicationCms;
use JApplicationWeb;
use JCache;
use JFactory;
use Joomla\Registry\Registry;
use JUri;

defined('_JEXEC') or die;

/**
 * Part of the FOF Platform Abstraction Layer.
 *
 * This implements the platform class for Joomla! 3
 *
 * @since    2.1
 */
class Platform extends BasePlatform
{
	/**
	 * Is this a CLI application?
	 *
	 * @var   bool
	 */
	protected static $isCLI = null;

	/**
	 * Is this an administrator application?
	 *
	 * @var   bool
	 */
	protected static $isAdmin = null;

	/**
	 * A fake session storage for CLI apps. Since CLI applications cannot have a session we are using a Registry object
	 * we manage internally.
	 *
	 * @var   Registry
	 */
	protected static $fakeSession = null;

	/**
	 * The table and table field cache object, used to speed up database access
	 *
	 * @var  \JRegistry|Registry|null
	 */
	private $_cache = null;

	/**
	 * Public constructor.
	 *
	 * Overridden to cater for CLI applications not having access to a session object.
	 *
	 * @param   \FOF30\Container\Container  $c  The component container
	 */
	public function __construct(Container $c)
	{
		parent::__construct($c);

		if ($this->isCli())
		{
			self::$fakeSession = new Registry();
		}
	}

	/**
	 * Checks if the current script is run inside a valid CMS execution
	 *
	 * @see     PlatformInterface::checkExecution()
	 *
	 * @return  bool
	 */
	public function checkExecution()
	{
		return defined('_JEXEC');
	}

	/**
	 * Raises an error, using the logic requested by the CMS (PHP Exception or dedicated class)
	 *
	 * @param   integer  $code
	 * @param   string   $message
	 *
	 * @return  void
	 *
	 * @throws  \Exception
	 */
	public function raiseError($code, $message)
	{
		$this->showErrorPage(new \Exception($message, $code));
	}

	/**
	 * Main function to detect if we're running in a CLI environment and we're admin
	 *
	 * @return  array  isCLI and isAdmin. It's not an associative array, so we can use list().
	 */
	protected function isCliAdmin()
	{
		if (is_null(static::$isCLI) && is_null(static::$isAdmin))
		{
			static::$isCLI   = false;
			static::$isAdmin = false;

			try
			{
				if (is_null(JFactory::$application))
				{
					static::$isCLI = true;
					static::$isAdmin = false;

					return [static::$isCLI, static::$isAdmin];
				}
				else
				{
					$app           = JFactory::getApplication();
					static::$isCLI = $app instanceof \Exception || $app instanceof JApplicationCli;
				}
			}
			catch (\Exception $e)
			{
				static::$isCLI = true;
			}

			if (static::$isCLI)
			{
				return [static::$isCLI, static::$isAdmin];
			}

			try
			{
				$app = JFactory::getApplication();
			}
			catch (Exception $e)
			{
				return [static::$isCLI, static::$isAdmin];
			}

			if (method_exists($app, 'isAdmin'))
			{
				static::$isAdmin = $app->isAdmin();
			}
			elseif (method_exists($app, 'isClient'))
			{
				static::$isAdmin = $app->isClient('administrator');
			}
		}

		return array(static::$isCLI, static::$isAdmin);
	}

	/**
	 * Returns absolute path to directories used by the CMS.
	 *
	 * @see PlatformInterface::getPlatformBaseDirs()
	 *
	 * @return  array  A hash array with keys root, public, admin, tmp and log.
	 */
	public function getPlatformBaseDirs()
	{
		return array(
			'root'   => JPATH_ROOT,
			'public' => JPATH_SITE,
			'media'  => JPATH_SITE . '/media',
			'admin'  => JPATH_ADMINISTRATOR,
			'tmp'    => JFactory::getConfig()->get('tmp_path'),
			'log'    => JFactory::getConfig()->get('log_path')
		);
	}

	/**
	 * Returns the base (root) directories for a given component.
	 *
	 * @param   string $component   The name of the component. For Joomla! this
	 *                              is something like "com_example"
	 *
	 * @see PlatformInterface::getComponentBaseDirs()
	 *
	 * @return  array  A hash array with keys main, alt, site and admin.
	 */
	public function getComponentBaseDirs($component)
	{
		if (!$this->isBackend())
		{
			$mainPath = JPATH_SITE . '/components/' . $component;
			$altPath = JPATH_ADMINISTRATOR . '/components/' . $component;
		}
		else
		{
			$mainPath = JPATH_ADMINISTRATOR . '/components/' . $component;
			$altPath = JPATH_SITE . '/components/' . $component;
		}

		return array(
			'main'  => $mainPath,
			'alt'   => $altPath,
			'site'  => JPATH_SITE . '/components/' . $component,
			'admin' => JPATH_ADMINISTRATOR . '/components/' . $component,
		);
	}

	/**
	 * Returns the application's template name
	 *
	 * @param   boolean|array  $params  An optional associative array of configuration settings
	 *
	 * @return  string  The template name. System is the fallback.
	 */
	public function getTemplate($params = false)
	{
		return JFactory::getApplication()->getTemplate($params);
	}

	/**
	 * Get application-specific suffixes to use with template paths. This allows
	 * you to look for view template overrides based on the application version.
	 *
	 * @return  array  A plain array of suffixes to try in template names
	 */
	public function getTemplateSuffixes()
	{
		$jversion = new \JVersion;
		$versionParts = explode('.', $jversion->getShortVersion());
		$majorVersion = array_shift($versionParts);
		$suffixes = array(
			'.j' . str_replace('.', '', $jversion->getHelpVersion()),
			'.j' . $majorVersion,
		);

		return $suffixes;
	}

	/**
	 * Return the absolute path to the application's template overrides
	 * directory for a specific component. We will use it to look for template
	 * files instead of the regular component directories. If the application
	 * does not have such a thing as template overrides return an empty string.
	 *
	 * @param   string  $component The name of the component for which to fetch the overrides
	 * @param   boolean $absolute  Should I return an absolute or relative path?
	 *
	 * @return  string  The path to the template overrides directory
	 */
	public function getTemplateOverridePath($component, $absolute = true)
	{
		list($isCli, $isAdmin) = $this->isCliAdmin();

		if (!$isCli)
		{
			if ($absolute)
			{
				$path = JPATH_THEMES . '/';
			}
			else
			{
				$path = $isAdmin ? 'administrator/templates/' : 'templates/';
			}

			if (substr($component, 0, 7) == 'media:/')
			{
				$directory = 'media/' . substr($component, 7);
			}
			else
			{
				$directory = 'html/' . $component;
			}

			$path .= $this->getTemplate() .
				'/' . $directory;
		}
		else
		{
			$path = '';
		}

		return $path;
	}

	/**
	 * Load the translation files for a given component.
	 *
	 * @param   string $component   The name of the component. For Joomla! this
	 *                              is something like "com_example"
	 *
	 * @see PlatformInterface::loadTranslations()
	 *
	 * @return  void
	 */
	public function loadTranslations($component)
	{
		if ($this->isBackend())
		{
			$paths = array(JPATH_ROOT, JPATH_ADMINISTRATOR);
		}
		else
		{
			$paths = array(JPATH_ADMINISTRATOR, JPATH_ROOT);
		}

		$jlang = $this->getLanguage();
		$jlang->load($component, $paths[0], 'en-GB', true);
		$jlang->load($component, $paths[0], null, true);
		$jlang->load($component, $paths[1], 'en-GB', true);
		$jlang->load($component, $paths[1], null, true);
	}

	/**
	 * Authorise access to the component in the back-end.
	 *
	 * @param   string $component The name of the component.
	 *
	 * @see PlatformInterface::authorizeAdmin()
	 *
	 * @return  boolean  True to allow loading the component, false to halt loading
	 */
	public function authorizeAdmin($component)
	{
		if ($this->isBackend())
		{
			// Master access check for the back-end, Joomla! 1.6 style.
			$user = $this->getUser();

			if (!$user->authorise('core.manage', $component)
				&& !$user->authorise('core.admin', $component)
			)
			{
				return false;
			}
		}

		return true;
	}

	/**
	 * Return a user object.
	 *
	 * @param   integer $id   The user ID to load. Skip or use null to retrieve
	 *                        the object for the currently logged in user.
	 *
	 * @see PlatformInterface::getUser()
	 *
	 * @return  \JUser  The JUser object for the specified user
	 */
	public function getUser($id = null)
	{
		/**
		 * If I'm in CLI I need load the User directly, otherwise JFactory will check the session (which doesn't exist
		 * in CLI)
		 */
		if ($this->isCli())
		{
			if ($id)
			{
				return \JUser::getInstance($id);
			}

			return new \JUser();
		}

		return JFactory::getUser($id);
	}

	/**
	 * Returns the JDocument object which handles this component's response.
	 *
	 * @see PlatformInterface::getDocument()
	 *
	 * @return  \JDocument
	 */
	public function getDocument()
	{
		$document = null;

		if (!$this->isCli())
		{
			try
			{
				$document = JFactory::getDocument();
			}
			catch (\Exception $exc)
			{
				$document = null;
			}
		}

		return $document;
	}

	/**
	 * Returns an object to handle dates
	 *
	 * @param   mixed $time     The initial time
	 * @param   null  $tzOffest The timezone offset
	 * @param   bool  $locale   Should I try to load a specific class for current language?
	 *
	 * @return  Date object
	 */
	public function getDate($time = 'now', $tzOffest = null, $locale = true)
	{
		if ($locale)
		{
			// Work around a bug in Joomla! 3.7.0.
			if ($time == 'now')
			{
				$time = time();
			}

			$coreObject = JFactory::getDate($time, $tzOffest);

			return new DateDecorator($coreObject);
		}
		else
		{
			return new Date($time, $tzOffest);
		}
	}

	/**
	 * Return the \JLanguage instance of the CMS/application
	 *
	 * @return \JLanguage
	 */
	public function getLanguage()
	{
		return JFactory::getLanguage();
	}

	/**
	 * Returns the database driver object of the CMS/application
	 *
	 * @return \JDatabaseDriver
	 */
	public function getDbo()
	{
		return JFactory::getDbo();
	}

	/**
	 * This method will try retrieving a variable from the request (input) data.
	 *
	 * @param   string   $key          The user state key for the variable
	 * @param   string   $request      The request variable name for the variable
	 * @param   Input    $input        The Input object with the request (input) data
	 * @param   mixed    $default      The default value. Default: null
	 * @param   string   $type         The filter type for the variable data. Default: none (no filtering)
	 * @param   boolean  $setUserState Should I set the user state with the fetched value?
	 *
	 * @see PlatformInterface::getUserStateFromRequest()
	 *
	 * @return  mixed  The value of the variable
	 */
	public function getUserStateFromRequest($key, $request, $input, $default = null, $type = 'none', $setUserState = true)
	{
		list($isCLI, $isAdmin) = $this->isCliAdmin();

		unset($isAdmin); // Just to make phpStorm happy

		if ($isCLI)
		{
			$ret = $input->get($request, $default, $type);

			if ($ret === $default)
			{
				$input->set($request, $ret);
			}

			return $ret;
		}

		$app = JFactory::getApplication();

		if (method_exists($app, 'getUserState'))
		{
			$old_state = $app->getUserState($key, $default);
		}
		else
		{
			$old_state = null;
		}

		$cur_state = (!is_null($old_state)) ? $old_state : $default;
		$new_state = $input->get($request, null, $type);

		// Save the new value only if it was set in this request
		if ($setUserState)
		{
			if ($new_state !== null)
			{
				$app->setUserState($key, $new_state);
			}
			else
			{
				$new_state = $cur_state;
			}
		}
		elseif (is_null($new_state))
		{
			$new_state = $cur_state;
		}

		return $new_state;
	}

	/**
	 * Load plugins of a specific type. Obviously this seems to only be required
	 * in the Joomla! CMS.
	 *
	 * @param   string $type The type of the plugins to be loaded
	 *
	 * @see PlatformInterface::importPlugin()
	 *
	 * @return void
	 *
	 * @codeCoverageIgnore
	 */
	public function importPlugin($type)
	{
		if (!$this->isCli())
		{
			\JLoader::import('joomla.plugin.helper');
			\JPluginHelper::importPlugin($type);
		}
	}

	/**
	 * Execute plugins (system-level triggers) and fetch back an array with
	 * their return values.
	 *
	 * @param   string $event The event (trigger) name, e.g. onBeforeScratchMyEar
	 * @param   array  $data  A hash array of data sent to the plugins as part of the trigger
	 *
	 * @see PlatformInterface::runPlugins()
	 *
	 * @return  array  A simple array containing the results of the plugins triggered
	 *
	 * @codeCoverageIgnore
	 */
	public function runPlugins($event, $data)
	{
		if (!$this->isCli())
		{
			if (class_exists('JEventDispatcher'))
			{
				return \JEventDispatcher::getInstance()->trigger($event, $data);
			}

			return JFactory::getApplication()->triggerEvent($event, $data);
		}
		else
		{
			return array();
		}
	}

	/**
	 * Perform an ACL check.
	 *
	 * @param   string $action    The ACL privilege to check, e.g. core.edit
	 * @param   string $assetname The asset name to check, typically the component's name
	 *
	 * @see PlatformInterface::authorise()
	 *
	 * @return  boolean  True if the user is allowed this action
	 */
	public function authorise($action, $assetname)
	{
		if ($this->isCli())
		{
			return true;
		}

		$ret = JFactory::getUser()->authorise($action, $assetname);

		// Work around Joomla returning null instead of false in some cases.
		return $ret ? true : false;
	}

	/**
	 * Is this the administrative section of the component?
	 *
	 * @see PlatformInterface::isBackend()
	 *
	 * @return  boolean
	 */
	public function isBackend()
	{
		list ($isCli, $isAdmin) = $this->isCliAdmin();

		return $isAdmin && !$isCli;
	}

	/**
	 * Is this the public section of the component?
	 *
	 * @see PlatformInterface::isFrontend()
	 *
	 * @return  boolean
	 */
	public function isFrontend()
	{
		list ($isCli, $isAdmin) = $this->isCliAdmin();

		return !$isAdmin && !$isCli;
	}

	/**
	 * Is this a component running in a CLI application?
	 *
	 * @see PlatformInterface::isCli()
	 *
	 * @return  boolean
	 */
	public function isCli()
	{
		list ($isCli, $isAdmin) = $this->isCliAdmin();

		return !$isAdmin && $isCli;
	}

	/**
	 * Is AJAX re-ordering supported? This is 100% Joomla!-CMS specific. All
	 * other platforms should return false and never ask why.
	 *
	 * @see PlatformInterface::supportsAjaxOrdering()
	 *
	 * @return  boolean
	 *
	 * @codeCoverageIgnore
	 */
	public function supportsAjaxOrdering()
	{
		return true;
	}

	/**
	 * Is the global F0F cache enabled?
	 *
	 * @return  boolean
	 *
	 * @codeCoverageIgnore
	 */
	public function isGlobalF0FCacheEnabled()
	{
		return !(defined('JDEBUG') && JDEBUG);
	}

	/**
	 * Saves something to the cache. This is supposed to be used for system-wide
	 * F0F data, not application data.
	 *
	 * @param   string $key     The key of the data to save
	 * @param   string $content The actual data to save
	 *
	 * @return  boolean  True on success
	 */
	public function setCache($key, $content)
	{
		$registry = $this->getCacheObject();

		$registry->set($key, $content);

		return $this->saveCache();
	}

	/**
	 * Retrieves data from the cache. This is supposed to be used for system-side
	 * F0F data, not application data.
	 *
	 * @param   string $key     The key of the data to retrieve
	 * @param   string $default The default value to return if the key is not found or the cache is not populated
	 *
	 * @return  string  The cached value
	 */
	public function getCache($key, $default = null)
	{
		$registry = $this->getCacheObject();

		return $registry->get($key, $default);
	}

	/**
	 * Gets a reference to the cache object, loading it from the disk if
	 * needed.
	 *
	 * @param   boolean $force Should I forcibly reload the registry?
	 *
	 * @return  \JRegistry|Registry
	 */
	private function &getCacheObject($force = false)
	{
		// Check if we have to load the cache file or we are forced to do that
		if (is_null($this->_cache) || $force)
		{
			// Try to get data from Joomla!'s cache
			$cache = JFactory::getCache('fof', '');
			$this->_cache = $cache->get('cache', 'fof');

			\JLoader::import('joomla.registry.registry');

			$isRegistry = is_object($this->_cache);

			if ($isRegistry)
			{
				$isRegistry = class_exists('JRegistry') ? ($this->_cache instanceof \JRegistry) : ($this->_cache instanceof Registry);
			}

			if (!$isRegistry)
			{
				// Create a new Registry object
				$this->_cache = class_exists('JRegistry') ? new \JRegistry() : new Registry();
			}
		}

		return $this->_cache;
	}

	/**
	 * Save the cache object back to disk
	 *
	 * @return  boolean  True on success
	 */
	private function saveCache()
	{
		// Get the Registry object of our cached data
		$registry = $this->getCacheObject();

		$cache = JFactory::getCache('fof', '');

		return $cache->store($registry, 'cache', 'fof');
	}

	/**
	 * Clears the cache of system-wide F0F data. You are supposed to call this in
	 * your components' installation script post-installation and post-upgrade
	 * methods or whenever you are modifying the structure of database tables
	 * accessed by F0F. Please note that F0F's cache never expires and is not
	 * purged by Joomla!. You MUST use this method to manually purge the cache.
	 *
	 * @return  boolean  True on success
	 */
	public function clearCache()
	{
		$false = false;
		$cache = JFactory::getCache('fof', '');
		$cache->store($false, 'cache', 'fof');
	}

	/**
	 * Returns an object that holds the configuration of the current site.
	 *
	 * @return  \JRegistry|Registry
	 *
	 * @codeCoverageIgnore
	 */
	public function getConfig()
	{
		return JFactory::getConfig();
	}

	/**
	 * logs in a user
	 *
	 * @param   array $authInfo authentification information
	 *
	 * @return  boolean  True on success
	 */
	public function loginUser($authInfo)
	{
		\JLoader::import('joomla.user.authentication');
		$options = array('remember' => false);
		$authenticate = \JAuthentication::getInstance();
		$response = $authenticate->authenticate($authInfo, $options);

		// User failed to authenticate: maybe he enabled two factor authentication?
		// Let's try again "manually", skipping the check vs two factor auth
		// Due the big mess with encryption algorithms and libraries, we are doing this extra check only
		// if we're in Joomla 2.5.18+ or 3.2.1+
		if ($response->status != \JAuthentication::STATUS_SUCCESS && method_exists('JUserHelper', 'verifyPassword'))
		{
			$db = JFactory::getDbo();
			$query = $db->getQuery(true)
				->select('id, password')
				->from('#__users')
				->where('username=' . $db->quote($authInfo['username']));
			$result = $db->setQuery($query)->loadObject();

			if ($result)
			{
				$match = \JUserHelper::verifyPassword($authInfo['password'], $result->password, $result->id);

				if ($match === true)
				{
					// Bring this in line with the rest of the system
					$user = \JUser::getInstance($result->id);
					$response->email = $user->email;
					$response->fullname = $user->name;

					list($isCli, $isAdmin) = $this->isCliAdmin();

					if ($isAdmin)
					{
						$response->language = $user->getParam('admin_language');
					}
					else
					{
						$response->language = $user->getParam('language');
					}

					$response->status = \JAuthentication::STATUS_SUCCESS;
					$response->error_message = '';
				}
			}
		}

		if ($response->status == \JAuthentication::STATUS_SUCCESS)
		{
			$this->importPlugin('user');
			$results = $this->runPlugins('onLoginUser', array((array)$response, $options));

			unset($results); // Just to make phpStorm happy

			\JLoader::import('joomla.user.helper');
			$userid = \JUserHelper::getUserId($response->username);
			$user = $this->getUser($userid);

			$session = $this->container->session;
			$session->set('user', $user);

			return true;
		}

		return false;
	}

	/**
	 * logs out a user
	 *
	 * @return  boolean  True on success
	 */
	public function logoutUser()
	{
		\JLoader::import('joomla.user.authentication');
		$app = JFactory::getApplication();
		$user = $this->getUser();
		$options = array('remember' => false);
		$parameters = array(
			'username' => $user->username,
			'id' => $user->id
		);

		// Set clientid in the options array if it hasn't been set already and shared sessions are not enabled.
		if (!$app->get('shared_session', '0'))
		{
			$options['clientid'] = $app->getClientId();
		}

		$ret = $app->triggerEvent('onUserLogout', array($parameters, $options));

		return !in_array(false, $ret, true);
	}

	/**
	 * Add a log file for FOF
	 *
	 * @param   string  $file
	 *
	 * @return  void
	 *
	 * @codeCoverageIgnore
	 */
	public function logAddLogger($file)
	{
		\JLog::addLogger(array('text_file' => $file), \JLog::ALL, array('fof'));
	}

	/**
	 * Logs a deprecated practice. In Joomla! this results in the $message being output in the
	 * deprecated log file, found in your site's log directory.
	 *
	 * @param   string $message The deprecated practice log message
	 *
	 * @return  void
	 *
	 * @codeCoverageIgnore
	 */
	public function logDeprecated($message)
	{
		\JLog::add($message, \JLog::WARNING, 'deprecated');
	}

	/**
	 * Adds a message to the application's debug log
	 *
	 * @param   string  $message
	 *
	 * @return  void
	 *
	 * @codeCoverageIgnore
	 */
	public function logDebug($message)
	{
		\JLog::add($message, \JLog::DEBUG, 'fof');
	}

	public function logUserAction($title, $logText, $extension)
	{
		static $joomlaModelAdded = false;

		// User Actions Log is available only under Joomla 3.9+
		if (version_compare(JVERSION, '3.9', 'lt'))
		{
			return;
		}

		// Do not perform logging if we're under CLI. Even if we _could_ have a logged user in CLI, ActionlogsModelActionlog
		// model always uses JFactory to fetch the current user, fetching data from the session. This means that under the CLI
		// (where there is no session) such session is started, causing warnings because usually output was already started before
		if ($this->isCli())
		{
			return;
		}

		// Include required Joomla Model
		if (!$joomlaModelAdded)
		{
			\JModelLegacy::addIncludePath(JPATH_ROOT . '/administrator/components/com_actionlogs/models', 'ActionlogsModel');
			$joomlaModelAdded = true;
		}

		$user = $this->getUser();

		// No log for guest users
		if ($user->guest)
		{
			return;
		}

		$message = array(
			'title'    	  => $title,
			'username' 	  => $user->username,
			'accountlink' => 'index.php?option=com_users&task=user.edit&id=' . $user->id
		);

		/** @var \ActionlogsModelActionlog $model **/
		try
		{
			$model = \JModelLegacy::getInstance('Actionlog', 'ActionlogsModel');
			$model->addLog(array($message), $logText, $extension, $user->id);
		}
		catch (\Exception $e)
		{
			// Ignore any error
		}
	}

	/**
	 * Returns the root URI for the request.
	 *
	 * @param   boolean $pathonly If false, prepend the scheme, host and port information. Default is false.
	 * @param   string  $path     The path
	 *
	 * @return  string  The root URI string.
	 *
	 * @codeCoverageIgnore
	 */
	public function URIroot($pathonly = false, $path = null)
	{
		\JLoader::import('joomla.environment.uri');

		return \JUri::root($pathonly, $path);
	}

	/**
	 * Returns the base URI for the request.
	 *
	 * @param   boolean $pathonly If false, prepend the scheme, host and port information. Default is false.
	 *
	 * @return  string  The base URI string
	 *
	 * @codeCoverageIgnore
	 */
	public function URIbase($pathonly = false)
	{
		\JLoader::import('joomla.environment.uri');

		return \JUri::base($pathonly);
	}

	/**
	 * Method to set a response header.  If the replace flag is set then all headers
	 * with the given name will be replaced by the new one (only if the current platform supports header caching)
	 *
	 * @param   string  $name    The name of the header to set.
	 * @param   string  $value   The value of the header to set.
	 * @param   boolean $replace True to replace any headers with the same name.
	 *
	 * @return  void
	 *
	 * @codeCoverageIgnore
	 */
	public function setHeader($name, $value, $replace = false)
	{
		JFactory::getApplication()->setHeader($name, $value, $replace);
	}

	/**
	 * In platforms that perform header caching, send all headers.
	 *
	 * @return  void
	 *
	 * @codeCoverageIgnore
	 */
	public function sendHeaders()
	{
		JFactory::getApplication()->sendHeaders();
	}

	/**
	 * Immediately terminate the containing application's execution
	 *
	 * @param   int  $code  The result code which should be returned by the application
	 *
	 * @return  void
	 */
	public function closeApplication($code = 0)
	{
		// Necessary workaround for broken System - Page Cache plugin in Joomla! 3.7.0
		$this->bugfixJoomlaCachePlugin();

		JFactory::getApplication()->close($code);
	}

	/**
	 * Perform a redirection to a different page, optionally enqueuing a message for the user.
	 *
	 * @param   string  $url     The URL to redirect to
	 * @param   int     $status  (optional) The HTTP redirection status code, default 303 (See Other)
	 * @param   string  $msg     (optional) A message to enqueue
	 * @param   string  $type    (optional) The message type, e.g. 'message' (default), 'warning' or 'error'.
	 *
	 * @return  void
	 *
	 * @throws  \Exception
	 */
	public function redirect($url, $status = 303, $msg = '', $type = 'message')
	{
		// Necessary workaround for broken System - Page Cache plugin in Joomla! 3.7.0
		$this->bugfixJoomlaCachePlugin();

		$app = JFactory::getApplication();

		if (class_exists('JApplicationCms') && class_exists('JApplicationWeb')
			&& ($app instanceof JApplicationCms)
			&& ($app instanceof JApplicationWeb))
		{
			// In modern Joomla! versions we have versatility on setting the message and the redirection HTTP code
			if (!empty($msg))
			{
				if (empty($type))
				{
					$type = 'message';
				}

				$app->enqueueMessage($msg, $type);
			}

			$app->redirect($url, $status);
		}

		/**
		 * If you're here, you have an ancient Joomla version and we have to use the legacy four parameter method...
		 * Note that we can't set a custom HTTP code, we can only tell it if it's a permanent redirection or not.
		 */
		$app->redirect($url, $msg, $type, $status == 301);
	}

	/**
	 * Handle an exception in a way that results to an error page. We use this under Joomla! to work around a bug in
	 * Joomla! 3.7 which results in error pages leading to white pages because Joomla's System - Page Cache plugin is
	 * broken.
	 *
	 * @param   Exception  $exception  The exception to handle
	 *
	 * @throws  Exception  We rethrow the exception
	 */
	public function showErrorPage(Exception $exception)
	{
		// Necessary workaround for broken System - Page Cache plugin in Joomla! 3.7.0
		$this->bugfixJoomlaCachePlugin();

		throw $exception;
	}

	/**
	 * Set a variable in the user session
	 *
	 * @param   string  $name       The name of the variable to set
	 * @param   string  $value      (optional) The value to set it to, default is null
	 * @param   string  $namespace  (optional) The variable's namespace e.g. the component name. Default: 'default'
	 *
	 * @return  void
	 */
	public function setSessionVar($name, $value = null, $namespace = 'default')
	{
		if ($this->isCli())
		{
			self::$fakeSession->set("$namespace.$name", $value);

			return;
		}

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

	/**
	 * Get a variable from the user session
	 *
	 * @param   string  $name       The name of the variable to set
	 * @param   string  $default    (optional) The default value to return if the variable does not exit, default: null
	 * @param   string  $namespace  (optional) The variable's namespace e.g. the component name. Default: 'default'
	 *
	 * @return  mixed
	 */
	public function getSessionVar($name, $default = null, $namespace = 'default')
	{
		if ($this->isCli())
		{
			return self::$fakeSession->get("$namespace.$name", $default);
		}

		return $this->container->session->get($name, $default, $namespace);
	}

	/**
	 * Unset a variable from the user session
	 *
	 * @param   string  $name       The name of the variable to unset
	 * @param   string  $namespace  (optional) The variable's namespace e.g. the component name. Default: 'default'
	 *
	 * @return  void
	 */
	public function unsetSessionVar($name, $namespace = 'default')
	{
		$this->setSessionVar($name, null, $namespace);
	}

	/**
	 * Return the session token. Two types of tokens can be returned:
	 *
	 * Session token ($formToken == false): Used for anti-spam protection of forms. This is specific to a session
	 *   object.
	 *
	 * Form token ($formToken == true): A secure hash of the user ID with the session token. Both the session and the
	 *   user are fetched from the application container. They are interpolated with the site's secret and passed
	 *   through MD5, making this harder to spoof than the plain old session token.
	 *
	 * @param   bool  $formToken  Should I return a form token?
	 * @param   bool  $forceNew   Should I force the creation of a new token?
	 *
	 * @return  mixed
	 */
	public function getToken($formToken = false, $forceNew = false)
	{
		// For CLI apps we implement our own fake token system
		if ($this->isCli())
		{
			$token = $this->getSessionVar('session.token');

			// Create a token
			if (is_null($token) || $forceNew)
			{
				$token = \JUserHelper::genRandomPassword(32);
				$this->setSessionVar('session.token', $token);
			}

			if (!$formToken)
			{
				return $token;
			}

			$user = $this->getUser();

			return \JApplicationHelper::getHash($user->id . $token);
		}

		// Web application, go through the regular Joomla! API.
		if ($formToken)
		{
			return \JSession::getFormToken($forceNew);
		}

		return $this->container->session->getToken($forceNew);
	}

	/**
	 * Joomla! 3.7 has a broken System - Page Cache plugin. When this plugin is enabled it FORCES the caching of all
	 * pages as soon as Joomla! starts loading, before the plugin has a chance to request to not be cached. Event worse,
	 * in case of a redirection, it doesn't try to remove the cache lock. This means that the next request will be
	 * treated as though the result of the page should be cached. Since there is NO cache content for the page Joomla!
	 * returns an empty response with a 200 OK header. This will, of course, get in the way of every single attempt to
	 * perform a redirection in the frontend of the site.
	 */
	private function bugfixJoomlaCachePlugin()
	{
		// Only Joomla! 3.7 and later is broken.
		if (version_compare(JVERSION, '3.6.999', 'le'))
		{
			return;
		}

		// Only do something when the System - Cache plugin is activated
		if (!class_exists('PlgSystemCache'))
		{
			return;
		}

		// Forcibly uncache the current request
		$options = array(
			'defaultgroup' => 'page',
			'browsercache' => false,
			'caching'      => false,
		);

		$cache_key = JUri::getInstance()->toString();
		JCache::getInstance('page', $options)->cache->remove($cache_key, 'page');
	}
}
FilesystemInterface.php000064400000011424152346020460011226 0ustar00<?php
/**
 * @package     FOF
 * @copyright   Copyright (c)2010-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license     GNU GPL version 2 or later
 */

namespace FOF30\Platform;

use FOF30\Container\Container;

defined('_JEXEC') or die;

interface FilesystemInterface
{
	/**
	 * Public constructor.
	 *
	 * @param   \FOF30\Container\Container  $c  The component container
	 */
	public function __construct(Container $c);

	/**
	 * Does the file exists?
	 *
	 * @param   $path  string   Path to the file to test
	 *
	 * @return  bool
	 */
	public function fileExists($path);

	/**
	 * Delete a file or array of files
	 *
	 * @param   mixed  $file  The file name or an array of file names
	 *
	 * @return  boolean  True on success
	 *
	 */
	public function fileDelete($file);

	/**
	 * Copies a file
	 *
	 * @param   string   $src          The path to the source file
	 * @param   string   $dest         The path to the destination file
	 *
	 * @return  boolean  True on success
	 */
	public function fileCopy($src, $dest);

	/**
	 * Write contents to a file
	 *
	 * @param   string   $file         The full file path
	 * @param   string   &$buffer      The buffer to write
	 *
	 * @return  boolean  True on success
	 */
	public function fileWrite($file, &$buffer);

	/**
	 * Checks for snooping outside of the file system root.
	 *
	 * @param   string  $path  A file system path to check.
	 *
	 * @return  string  A cleaned version of the path or exit on error.
	 *
	 * @throws  \Exception
	 */
	public function pathCheck($path);

	/**
	 * Function to strip additional / or \ in a path name.
	 *
	 * @param   string  $path  The path to clean.
	 * @param   string  $ds    Directory separator (optional).
	 *
	 * @return  string  The cleaned path.
	 *
	 * @throws  \UnexpectedValueException
	 */
	public function pathClean($path, $ds = DIRECTORY_SEPARATOR);

	/**
	 * Searches the directory paths for a given file.
	 *
	 * @param   mixed   $paths  An path string or array of path strings to search in
	 * @param   string  $file   The file name to look for.
	 *
	 * @return  mixed   The full path and file name for the target file, or boolean false if the file is not found in any of the paths.
	 */
	public function pathFind($paths, $file);

	/**
	 * Wrapper for the standard file_exists function
	 *
	 * @param   string  $path  Folder name relative to installation dir
	 *
	 * @return  boolean  True if path is a folder
	 */
	public function folderExists($path);

	/**
	 * Utility function to read the files in a folder.
	 *
	 * @param   string   $path           The path of the folder to read.
	 * @param   string   $filter         A filter for file names.
	 * @param   mixed    $recurse        True to recursively search into sub-folders, or an integer to specify the maximum depth.
	 * @param   boolean  $full           True to return the full path to the file.
	 * @param   array    $exclude        Array with names of files which should not be shown in the result.
	 * @param   array    $excludefilter  Array of filter to exclude
	 *
	 * @return  array  Files in the given folder.
	 */
	public function folderFiles($path, $filter = '.', $recurse = false, $full = false, $exclude = array('.svn', 'CVS', '.DS_Store', '__MACOSX'),
								$excludefilter = array('^\..*', '.*~'));

	/**
	 * Utility function to read the folders in a folder.
	 *
	 * @param   string   $path           The path of the folder to read.
	 * @param   string   $filter         A filter for folder names.
	 * @param   mixed    $recurse        True to recursively search into sub-folders, or an integer to specify the maximum depth.
	 * @param   boolean  $full           True to return the full path to the folders.
	 * @param   array    $exclude        Array with names of folders which should not be shown in the result.
	 * @param   array    $excludefilter  Array with regular expressions matching folders which should not be shown in the result.
	 *
	 * @return  array  Folders in the given folder.
	 */
	public function folderFolders($path, $filter = '.', $recurse = false, $full = false, $exclude = array('.svn', 'CVS', '.DS_Store', '__MACOSX'),
								  $excludefilter = array('^\..*'));

	/**
	 * Create a folder -- and all necessary parent folders.
	 *
	 * @param   string   $path  A path to create from the base path.
	 * @param   integer  $mode  Directory permissions to set for folders created. 0755 by default.
	 *
	 * @return  boolean  True if successful.
	 */
	public function folderCreate($path = '', $mode = 0755);

	/**
	 * Gets the extension of a file name
	 *
	 * @param   string  $file  The file name
	 *
	 * @return  string  The file extension
	 */
	public function getExt($file);

	/**
	 * Strips the last extension off of a file name
	 *
	 * @param   string  $file  The file name
	 *
	 * @return  string  The file name without the extension
	 */
	public function stripExt($file);
}
PlatformInterface.php000064400000037001152346020460010665 0ustar00<?php
/**
 * @package     FOF
 * @copyright   Copyright (c)2010-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license     GNU GPL version 2 or later
 */

namespace FOF30\Platform;

use Exception;
use FOF30\Container\Container;
use FOF30\Date\Date;
use FOF30\Input\Input;
use Joomla\Registry\Registry;

defined('_JEXEC') or die;

/**
 * Part of the F0F Platform Abstraction Layer. It implements everything that
 * depends on the platform F0F is running under, e.g. the Joomla! CMS front-end,
 * the Joomla! CMS back-end, a CLI Joomla! Platform app, a bespoke Joomla!
 * Platform / Framework web application and so on.
 */
interface PlatformInterface
{
	/**
	 * Public constructor.
	 *
	 * @param   \FOF30\Container\Container  $c  The component container
	 */
	public function __construct(Container $c);

	/**
	 * Checks if the current script is run inside a valid CMS execution
	 *
	 * @return bool
	 */
	public function checkExecution();

	/**
	 * Raises an error, using the logic requested by the CMS (PHP Exception or dedicated class)
	 *
	 * @param   integer  $code
	 * @param   string   $message
	 *
	 * @return mixed
	 */
	public function raiseError($code, $message);

	/**
	 * Returns the version number string of the CMS/application we're running in
	 *
	 * @return  string
	 *
	 * @since  2.1.2
	 */
	public function getPlatformVersion();

	/**
	 * Returns absolute path to directories used by the containing CMS/application.
	 *
	 * The return is a table with the following key:
	 * * root    Path to the site root
	 * * public  Path to the public area of the site
	 * * admin   Path to the administrative area of the site
	 * * tmp     Path to the temp directory
	 * * log     Path to the log directory
	 *
	 * @return  array  A hash array with keys root, public, admin, tmp and log.
	 */
	public function getPlatformBaseDirs();

	/**
	 * Returns the base (root) directories for a given component, i.e the application
	 * which is running inside our main application (CMS, web app).
	 *
	 * The return is a table with the following keys:
	 * * main	The normal location of component files. For a back-end Joomla!
	 *          component this is the administrator/components/com_example
	 *          directory.
	 * * alt	The alternate location of component files. For a back-end
	 *          Joomla! component this is the front-end directory, e.g.
	 *          components/com_example
	 * * site	The location of the component files serving the public part of
	 *          the application.
	 * * admin	The location of the component files serving the administrative
	 *          part of the application.
	 *
	 * All paths MUST be absolute. All four paths MAY be the same if the
	 * platform doesn't make a distinction between public and private parts,
	 * or when the component does not provide both a public and private part.
	 * All of the directories MUST be defined and non-empty.
	 *
	 * @param   string  $component  The name of the component. For Joomla! this
	 *                              is something like "com_example"
	 *
	 * @return  array  A hash array with keys main, alt, site and admin.
	 */
	public function getComponentBaseDirs($component);

	/**
	 * Returns the application's template name
	 *
	 * @param   boolean|array  $params  An optional associative array of configuration settings
	 *
	 * @return  string  The template name. System is the fallback.
	 */
	public function getTemplate($params = false);

	/**
	 * Get application-specific suffixes to use with template paths. This allows
	 * you to look for view template overrides based on the application version.
	 *
	 * @return  array  A plain array of suffixes to try in template names
	 */
	public function getTemplateSuffixes();

	/**
	 * Return the absolute path to the application's template overrides
	 * directory for a specific component. We will use it to look for template
	 * files instead of the regular component directories. If the application
	 * does not have such a thing as template overrides return an empty string.
	 *
	 * @param   string   $component  The name of the component for which to fetch the overrides
	 * @param   boolean  $absolute   Should I return an absolute or relative path?
	 *
	 * @return  string  The path to the template overrides directory
	 */
	public function getTemplateOverridePath($component, $absolute = true);

	/**
	 * Load the translation files for a given component.
	 *
	 * @param   string  $component  The name of the component. For Joomla! this
	 *                              is something like "com_example"
	 *
	 * @return  void
	 */
	public function loadTranslations($component);

	/**
	 * By default FOF will only use the Controller's onBefore* methods to
	 * perform user authorisation. In some cases, like the Joomla! back-end,
	 * you also need to perform component-wide user authorisation in the
	 * Dispatcher. This method MUST implement this authorisation check. If you
	 * do not need this in your platform, please always return true.
	 *
	 * @param   string  $component  The name of the component.
	 *
	 * @return  boolean  True to allow loading the component, false to halt loading
	 */
	public function authorizeAdmin($component);

	/**
	 * This method will try retrieving a variable from the request (input) data.
	 * If it doesn't exist it will be loaded from the user state, typically
	 * stored in the session. If it doesn't exist there either, the $default
	 * value will be used. If $setUserState is set to true, the retrieved
	 * variable will be stored in the user session.
	 *
	 * @param   string    $key           The user state key for the variable
	 * @param   string    $request       The request variable name for the variable
	 * @param   Input     $input         The Input object with the request (input) data
	 * @param   mixed     $default       The default value. Default: null
	 * @param   string    $type          The filter type for the variable data. Default: none (no filtering)
	 * @param   boolean   $setUserState  Should I set the user state with the fetched value?
	 *
	 * @return  mixed  The value of the variable
	 */
	public function getUserStateFromRequest($key, $request, $input, $default = null, $type = 'none', $setUserState = true);

	/**
	 * Load plugins of a specific type. Obviously this seems to only be required
	 * in the Joomla! CMS itself.
	 *
	 * @param   string  $type  The type of the plugins to be loaded
	 *
	 * @return void
	 */
	public function importPlugin($type);

	/**
	 * Execute plugins (system-level triggers) and fetch back an array with
	 * their return values.
	 *
	 * @param   string  $event  The event (trigger) name, e.g. onBeforeScratchMyEar
	 * @param   array   $data   A hash array of data sent to the plugins as part of the trigger
	 *
	 * @return  array  A simple array containing the results of the plugins triggered
	 */
	public function runPlugins($event, $data);

	/**
	 * Perform an ACL check. Please note that FOF uses by default the Joomla!
	 * CMS convention for ACL privileges, e.g core.edit for the edit privilege.
	 * If your platform uses different conventions you'll have to override the
	 * F0F defaults using fof.xml or by specialising the controller.
	 *
	 * @param   string  $action     The ACL privilege to check, e.g. core.edit
	 * @param   string  $assetname  The asset name to check, typically the component's name
	 *
	 * @return  boolean  True if the user is allowed this action
	 */
	public function authorise($action, $assetname);

	/**
	 * Returns a user object.
	 *
	 * @param   integer  $id  The user ID to load. Skip or use null to retrieve
	 *                        the object for the currently logged in user.
	 *
	 * @return  \JUser  The \JUser object for the specified user
	 */
	public function getUser($id = null);

	/**
	 * Returns the \JDocument object which handles this component's response. You
	 * may also return null and FOF will a. try to figure out the output type by
	 * examining the "format" input parameter (or fall back to "html") and b.
	 * FOF will not attempt to load CSS and Javascript files (as it doesn't make
	 * sense if there's no \JDocument to handle them).
	 *
	 * @return  \JDocument
	 */
	public function getDocument();

	/**
	 * Returns an object to handle dates
	 *
	 * @param   mixed   $time       The initial time
	 * @param   null    $tzOffest   The timezone offset
	 * @param   bool    $locale     Should I try to load a specific class for current language?
	 *
	 * @return  Date object
	 */
	public function getDate($time = 'now', $tzOffest = null, $locale = true);

	/**
	 * Return the \JLanguage instance of the CMS/application
	 *
	 * @return \JLanguage
	 */
	public function getLanguage();

	/**
	 * Returns the database driver object of the CMS/application
	 *
	 * @return \JDatabaseDriver
	 */
	public function getDbo();

	/**
	 * Is this the administrative section of the component?
	 *
	 * @return  boolean
	 */
	public function isBackend();

	/**
	 * Is this the public section of the component?
	 *
	 * @return  boolean
	 */
	public function isFrontend();

	/**
	 * Is this a component running in a CLI application?
	 *
	 * @return  boolean
	 */
	public function isCli();

	/**
	 * Is AJAX re-ordering supported? This is 100% Joomla! CMS (version 3+) specific.
	 *
	 * @return  boolean
	 */
	public function supportsAjaxOrdering();

	/**
	 * Saves something to the cache. This is supposed to be used for system-wide
	 * FOF data, not application data.
	 *
	 * @param   string  $key      The key of the data to save
	 * @param   string  $content  The actual data to save
	 *
	 * @return  boolean  True on success
	 */
	public function setCache($key, $content);

	/**
	 * Retrieves data from the cache. This is supposed to be used for system-side
	 * FOF data, not application data.
	 *
	 * @param   string  $key      The key of the data to retrieve
	 * @param   string  $default  The default value to return if the key is not found or the cache is not populated
	 *
	 * @return  string  The cached value
	 */
	public function getCache($key, $default = null);

	/**
	 * Clears the cache of system-wide FOF data. You are supposed to call this in
	 * your components' installation script post-installation and post-upgrade
	 * methods or whenever you are modifying the structure of database tables
	 * accessed by F0F. Please note that FOF's cache never expires and is not
	 * purged by Joomla!. You MUST use this method to manually purge the cache.
	 *
	 * @return  boolean  True on success
	 */
	public function clearCache();

	/**
	 * Returns an object that holds the configuration of the current site.
	 *
	 * @return  Registry
	 */
	public function getConfig();

	/**
	 * Is the global FOF cache enabled?
	 *
	 * @return  boolean
	 */
	public function isGlobalFOFCacheEnabled();

	/**
	 * logs in a user
	 *
	 * @param   array  $authInfo  authentification information
	 *
	 * @return  boolean  True on success
	 */
	public function loginUser($authInfo);

	/**
	 * logs out a user
	 *
	 * @return  boolean  True on success
	 */
	public function logoutUser();

	/**
	 * Add a log file for FOF
	 *
	 * @param   string  $file
	 *
	 * @return  void
	 */
	public function logAddLogger($file);

	/**
	 * Logs a deprecated practice. In Joomla! this results in the $message being output in the
	 * deprecated log file, found in your site's log directory.
	 *
	 * @param   string  $message  The deprecated practice log message
	 *
	 * @return  void
	 */
	public function logDeprecated($message);

	/**
	 * Adds a message to the application's debug log
	 *
	 * @param   string  $message
	 *
	 * @return  void
	 */
	public function logDebug($message);

	/**
	 * Adds a message
	 *
	 * @param	string	$title
	 * @param	string	$logText
	 * @param	string	$extension
	 *
	 * @return void
	 */
	public function logUserAction($title, $logText, $extension);

	/**
	 * Returns the root URI for the request.
	 *
	 * @param   boolean  $pathonly  If false, prepend the scheme, host and port information. Default is false.
	 * @param   string   $path      The path
	 *
	 * @return  string  The root URI string.
	 */
	public function URIroot($pathonly = false, $path = null);

	/**
	 * Returns the base URI for the request.
	 *
	 * @param   boolean  $pathonly  If false, prepend the scheme, host and port information. Default is false.
	 * |
	 * @return  string  The base URI string
	 */
	public function URIbase($pathonly = false);

	/**
	 * Method to set a response header.  If the replace flag is set then all headers
	 * with the given name will be replaced by the new one (only if the current platform supports header caching)
	 *
	 * @param   string   $name     The name of the header to set.
	 * @param   string   $value    The value of the header to set.
	 * @param   boolean  $replace  True to replace any headers with the same name.
	 *
	 * @return  void
	 */
	public function setHeader($name, $value, $replace = false);

	/**
	 * In platforms that perform header caching, send all headers.
	 *
	 * @return  void
	 */
	public function sendHeaders();

	/**
	 * Immediately terminate the containing application's execution
	 *
	 * @param   int  $code  The result code which should be returned by the application
	 *
	 * @return  void
	 */
	public function closeApplication($code = 0);

	/**
	 * Perform a redirection to a different page, optionally enqueuing a message for the user.
	 *
	 * @param   string  $url     The URL to redirect to
	 * @param   int     $status  (optional) The HTTP redirection status code, default 301
	 * @param   string  $msg     (optional) A message to enqueue
	 * @param   string  $type    (optional) The message type, e.g. 'message' (default), 'warning' or 'error'.
	 *
	 * @return  void
	 *
	 * @throws  \Exception
	 */
	public function redirect($url, $status = 301, $msg = null, $type = 'message');

	/**
	 * Handle an exception in a way that results to an error page.
	 *
	 * @param   Exception  $exception  The exception to handle
	 *
	 * @throws  Exception  Possibly rethrown exception
	 */
	public function showErrorPage(Exception $exception);

	/**
	 * Set a variable in the user session
	 *
	 * @param   string  $name       The name of the variable to set
	 * @param   string  $value      (optional) The value to set it to, default is null
	 * @param   string  $namespace  (optional) The variable's namespace e.g. the component name. Default: 'default'
	 *
	 * @return  void
	 */
	public function setSessionVar($name, $value = null, $namespace = 'default');

	/**
	 * Get a variable from the user session
	 *
	 * @param   string  $name       The name of the variable to set
	 * @param   string  $default    (optional) The default value to return if the variable does not exit, default: null
	 * @param   string  $namespace  (optional) The variable's namespace e.g. the component name. Default: 'default'
	 *
	 * @return  mixed
	 */
	public function getSessionVar($name, $default = null, $namespace = 'default');

	/**
	 * Unset a variable from the user session
	 *
	 * @param   string  $name       The name of the variable to unset
	 * @param   string  $namespace  (optional) The variable's namespace e.g. the component name. Default: 'default'
	 *
	 * @return  void
	 */
	public function unsetSessionVar($name, $namespace = 'default');

	/**
	 * Return the session token. Two types of tokens can be returned:
	 *
	 * Session token ($formToken == false): Used for anti-spam protection of forms. This is specific to a session
	 *   object.
	 *
	 * Form token ($formToken == true): A secure hash of the user ID with the session token. Both the session and the
	 *   user are fetched from the application container.
	 *
	 * @param   bool  $formToken  Should I return a form token?
	 * @param   bool  $forceNew   Should I force the creation of a new token?
	 *
	 * @return  mixed
	 */
	public function getToken($formToken = false, $forceNew = false);
}
AbstractSmartSlider3Platform.php000064400000001137152356644720013002 0ustar00<?php


namespace Nextend\SmartSlider3\Platform;


use Nextend\Framework\Pattern\GetAssetsPathTrait;
use Nextend\Framework\Pattern\SingletonTrait;

abstract class AbstractSmartSlider3Platform {

    use SingletonTrait, GetAssetsPathTrait;

    public abstract function start();

    /**
     * @return string
     */
    public abstract function getAdminUrl();

    /**
     * @return string
     */
    public abstract function getAdminAjaxUrl();

    /**
     * @return string
     */
    public function getNetworkAdminUrl() {

        return $this->getAdminUrl();
    }
}SmartSlider3Platform.php000064400000001356152356644720011321 0ustar00<?php

namespace Nextend\SmartSlider3\Platform;

use Nextend\Framework\Pattern\SingletonTrait;

class SmartSlider3Platform {

    use SingletonTrait;

    /**
     * @var AbstractSmartSlider3Platform
     */
    private static $platform;

    public function __construct() {
        self::$platform = Joomla\SmartSlider3PlatformJoomla::getInstance();
    

        self::$platform->start();
    }

    public static function getAdminUrl() {

        return self::$platform->getAdminUrl();
    }

    public static function getAdminAjaxUrl() {

        return self::$platform->getAdminAjaxUrl();
    }

    public static function getNetworkAdminUrl() {

        return self::$platform->getNetworkAdminUrl();
    }
}Joomla/AdministratorComponent.php000064400000005433152356644720013224 0ustar00<?php


namespace Nextend\SmartSlider3\Platform\Joomla;


use Joomla\CMS\Access\Exception\NotAllowed;
use Joomla\CMS\Factory;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Uri\Uri;
use Nextend\Framework\PageFlow;
use Nextend\Framework\Request\Request;
use Nextend\SmartSlider3\Application\ApplicationSmartSlider3;
use Nextend\SmartSlider3\Install\Install;
use Nextend\SmartSlider3\Install\Tables;
use Nextend\SmartSlider3\Platform\SmartSlider3Platform;
use Nextend\SmartSlider3\Settings;
use Nextend\SmartSlider3\SmartSlider3Info;
use plgSystemSmartSlider3;

class AdministratorComponent {

    public function __construct() {

        $this->checkAcl();

        if (!Request::$GET->getInt('keepalive')) {

            /**
             * Required for the license activation to work.
             */
            Factory::getApplication()
                   ->setHeader('cross-origin-opener-policy', 'unsafe-none', true);

            $this->loadSystemPlugins();

            if (Settings::get('n2_ss3_version') != SmartSlider3Info::$completeVersion) {

                Install::install();
            } else if (Request::$REQUEST->getInt('repairss3')) {
                Install::install();

                Tables::repair();
                header('LOCATION: ' . SmartSlider3Platform::getAdminUrl());
                exit;
            }

            $applicationType = ApplicationSmartSlider3::getInstance()
                                                      ->getApplicationTypeAdmin();

            $isAjax = Request::$GET->getInt('nextendajax');

            $applicationType->processRequest('sliders', 'gettingstarted', $isAjax);

            ?>
            <script>
                _N2.r('$', function () {
                    var $ = _N2.$;
                    var __keepAlive = function () {
                        $.get('<?php echo esc_url(Uri::current() . '?option=com_smartslider3&keepalive=1');?>', function () {
                            setTimeout(__keepAlive, 300000);
                        });
                    };
                    setTimeout(__keepAlive, 300000);
                });
            </script>
            <?php
            PageFlow::markApplicationEnd();
        }
    }

    protected function checkAcl() {

        if (!Factory::getUser()
                     ->authorise('core.manage', 'com_smartslider3')) {
            throw new NotAllowed(Text::_('JERROR_ALERTNOAUTHOR'), 403);
        }
    }

    protected function loadSystemPlugins() {

        if (!class_exists('plgSystemSmartSlider3')) {

            $plugin = PluginHelper::getPlugin('system', 'smartslider3');
            new plgSystemSmartSlider3(JoomlaShim::getDispatcher(), (array)($plugin));
        }
    }
}Joomla/compat.php000064400000000704152356644720010000 0ustar00<?php

use Nextend\SmartSlider3\Application\ApplicationSmartSlider3;

function nextend_smartslider3($sliderId, $usage = 'Used in PHP') {

    $applicationTypeFrontend = ApplicationSmartSlider3::getInstance()
                                                      ->getApplicationTypeFrontend();

    $applicationTypeFrontend->process('slider', 'display', false, array(
        'sliderID' => $sliderId,
        'usage'    => $usage
    ));
}Joomla/ImageFallback.php000064400000007121152356644720011157 0ustar00<?php

namespace Nextend\SmartSlider3\Platform\Joomla;

use Joomla\CMS\Uri\Uri;
use Nextend\Framework\Filesystem\Filesystem;
use Nextend\Framework\Request\Request;

class ImageFallback {

    static public function fallback($imageVars, $textVars = array(), $root = '') {
        $root   = self::fixRoot($root);
        $return = '';

        foreach ($imageVars as $image) {
            if (!empty($image)) {
                if (strpos($image, '#') !== false) {
                    $imageHelper = explode('#', $image);
                    $realImage   = $imageHelper[0];
                } else {
                    $realImage = $image;
                }
                $return = self::getImage($realImage, $root);
                if (!empty($return)) {
                    break;
                }
            }
        }

        if ($return == '' && !empty($textVars)) {
            foreach ($textVars as $text) {
                $imageInText = self::findImage($text);

                if (!empty($imageInText)) {
                    $return = self::getImage($imageInText, $root);

                    if ($return != '$/') {
                        break;
                    } else {
                        $return = '';
                    }
                }
            }
        }

        return $return;
    }

    static public function fixRoot($root) {
        if (substr($root, 0, 5) != 'http:' && substr($root, 0, 6) != 'https:') {
            $root = self::siteURL();
        }

        return self::removeSlashes($root);
    }

    static public function getImage($image, $root) {
        $imageUrl = self::httpLink($image, $root);
        if (self::isExternal($imageUrl) || self::imageUrlExists($imageUrl)) {
            return $imageUrl;
        } else {
            return '';
        }
    }

    static public function findImage($s) {
        preg_match_all('/(<img.*?src=[\'"](.*?)[\'"][^>]*>)|(background(-image)??\s*?:.*?url\((["|\']?)?(.+?)(["|\']?)?\))/i', $s, $r);
        if (isset($r[2]) && !empty($r[2][0])) {
            $s = $r[2][0];
        } else if (isset($r[6]) && !empty($r[6][0])) {
            $s = trim($r[6][0], "'\" \t\n\r\0\x0B");
        } else {
            $s = '';
        }

        return $s;
    }

    static public function removeSlashes($text, $right = true) {
        if ($right) {
            return rtrim($text, '/\\');
        } else {
            return ltrim($text, '/\\');
        }
    }

    static public function siteURL() {
        return Uri::root(false);
    }

    static public function isExternal($url) {
        $url = str_replace(array(
            'http:',
            'https:',
            '//',
            '\\\\'
        ), '', $url);

        $domain = Request::$SERVER->getVar('HTTP_HOST');

        return !(substr($url, 0, strlen($domain)) === $domain);
    }

    static public function httpLink($image, $root) {
        if (substr($image, 0, 5) != 'http:' && substr($image, 0, 6) != 'https:' && substr($image, 0, 2) != '//' && substr($image, 0, 2) != '\\\\') {
            return $root . '/' . self::removeSlashes($image, false);
        } else {
            return $image;
        }
    }

    static public function imageUrlExists($imageUrl) {
        if (substr($imageUrl, 0, 2) == '//' || substr($imageUrl, 0, 2) == '\\\\') {
            $imageUrl = (strtolower(Request::$SERVER->getCmd('HTTPS', 'off')) != 'off' ? "https:" : "http:") . $imageUrl;
        }

        return Filesystem::existsFile(Filesystem::absoluteURLToPath(urldecode($imageUrl)));
    }
}Joomla/Joomla3Assets.php000064400000025030152356644720011203 0ustar00<?php


namespace Nextend\SmartSlider3\Platform\Joomla;


use Joomla\CMS\Document\HtmlDocument;
use Joomla\CMS\Factory;

class Joomla3Assets {

    /**
     * @var HtmlDocument
     */
    private $document;

    private $original = array();
    private $updates = array();

    public function __construct() {

        $this->document = Factory::getDocument();

        $this->original['_styleSheets'] = $this->document->_styleSheets;
        $this->original['_style']       = $this->document->_style;

        $this->original['_scripts'] = $this->document->_scripts;
        $this->original['_script']  = $this->document->_script;

        $this->document->_style  = array();
        $this->document->_script = array();
    }

    public function process() {

        $this->updates['_styleSheets'] = array_diff_key($this->document->_styleSheets, $this->original['_styleSheets']);
        $this->updates['_style']       = $this->document->_style;

        $this->updates['_scripts'] = array_diff_key($this->document->_scripts, $this->original['_scripts']);
        $this->updates['_script']  = $this->document->_script;


        $this->document->_style  = $this->original['_style'];
        $this->document->_script = $this->original['_script'];
    }

    /**
     * Based on Joomla\CMS\Document\DocumentRendererHead
     *
     * @return string
     */
    public function renderHead() {

        if (get_class($this->document) === 'Joomla\CMS\Document\HtmlDocument') {
            $lnEnd        = $this->document->_getLineEnd();
            $tab          = $this->document->_getTab();
            $tagEnd       = ' >';
            $buffer       = '';
            $mediaVersion = $this->document->getMediaVersion();

            $defaultCssMimes = array('text/css');

            // Generate stylesheet links
            foreach ($this->updates['_styleSheets'] as $src => $attribs) {
                // Check if stylesheet uses IE conditional statements.
                $conditional = isset($attribs['options']) && isset($attribs['options']['conditional']) ? $attribs['options']['conditional'] : null;

                // Check if script uses media version.
                if (isset($attribs['options']['version']) && $attribs['options']['version'] && strpos($src, '?') === false && ($mediaVersion || $attribs['options']['version'] !== 'auto')) {
                    $src .= '?' . ($attribs['options']['version'] === 'auto' ? $mediaVersion : $attribs['options']['version']);
                }

                $buffer .= $tab;

                // This is for IE conditional statements support.
                if (!is_null($conditional)) {
                    $buffer .= '<!--[if ' . $conditional . ']>';
                }

                $buffer .= '<link href="' . $src . '" rel="stylesheet"';

                // Add script tag attributes.
                foreach ($attribs as $attrib => $value) {
                    // Don't add the 'options' attribute. This attribute is for internal use (version, conditional, etc).
                    if ($attrib === 'options') {
                        continue;
                    }

                    // Don't add type attribute if document is HTML5 and it's a default mime type. 'mime' is for B/C.
                    if (in_array($attrib, array(
                            'type',
                            'mime'
                        )) && $this->document->isHtml5() && in_array($value, $defaultCssMimes)) {
                        continue;
                    }

                    // Don't add type attribute if document is HTML5 and it's a default mime type. 'mime' is for B/C.
                    if ($attrib === 'mime') {
                        $attrib = 'type';
                    }

                    // Add attribute to script tag output.
                    $buffer .= ' ' . htmlspecialchars($attrib, ENT_COMPAT, 'UTF-8');

                    // Json encode value if it's an array.
                    $value = !is_scalar($value) ? json_encode($value) : $value;

                    $buffer .= '="' . htmlspecialchars($value, ENT_COMPAT, 'UTF-8') . '"';
                }

                $buffer .= $tagEnd;

                // This is for IE conditional statements support.
                if (!is_null($conditional)) {
                    $buffer .= '<![endif]-->';
                }

                $buffer .= $lnEnd;
            }

            // Generate stylesheet declarations
            foreach ($this->updates['_style'] as $type => $content) {
                $buffer .= $tab . '<style';

                if (!is_null($type) && (!$this->document->isHtml5() || !in_array($type, $defaultCssMimes))) {
                    $buffer .= ' type="' . $type . '"';
                }

                $buffer .= '>' . $lnEnd;

                // This is for full XHTML support.
                if ($this->document->_mime != 'text/html') {
                    $buffer .= $tab . $tab . '/*<![CDATA[*/' . $lnEnd;
                }

                $buffer .= $content . $lnEnd;

                // See above note
                if ($this->document->_mime != 'text/html') {
                    $buffer .= $tab . $tab . '/*]]>*/' . $lnEnd;
                }

                $buffer .= $tab . '</style>' . $lnEnd;
            }

            // Generate scripts options
            $scriptOptions = $this->document->getScriptOptions();

            if (!empty($scriptOptions)) {
                $buffer .= $tab . '<script type="application/json" class="joomla-script-options new">';

                $prettyPrint = (JDEBUG && defined('JSON_PRETTY_PRINT') ? JSON_PRETTY_PRINT : false);
                $jsonOptions = json_encode($scriptOptions, $prettyPrint);
                $jsonOptions = $jsonOptions ? $jsonOptions : '{}';

                $buffer .= $jsonOptions;
                $buffer .= '</script>' . $lnEnd;
            }

            $defaultJsMimes         = array(
                'text/javascript',
                'application/javascript',
                'text/x-javascript',
                'application/x-javascript'
            );
            $html5NoValueAttributes = array(
                'defer',
                'async'
            );

            foreach ($this->updates['_scripts'] as $src => $attribs) {
                // Check if script uses IE conditional statements.
                $conditional = isset($attribs['options']) && isset($attribs['options']['conditional']) ? $attribs['options']['conditional'] : null;

                // Check if script uses media version.
                if (isset($attribs['options']['version']) && $attribs['options']['version'] && strpos($src, '?') === false && ($mediaVersion || $attribs['options']['version'] !== 'auto')) {
                    $src .= '?' . ($attribs['options']['version'] === 'auto' ? $mediaVersion : $attribs['options']['version']);
                }

                $buffer .= $tab;

                // This is for IE conditional statements support.
                if (!is_null($conditional)) {
                    $buffer .= '<!--[if ' . $conditional . ']>';
                }

                $buffer .= '<script src="' . $src . '"';

                // Add script tag attributes.
                foreach ($attribs as $attrib => $value) {
                    // Don't add the 'options' attribute. This attribute is for internal use (version, conditional, etc).
                    if ($attrib === 'options') {
                        continue;
                    }

                    // Don't add type attribute if document is HTML5 and it's a default mime type. 'mime' is for B/C.
                    if (in_array($attrib, array(
                            'type',
                            'mime'
                        )) && $this->document->isHtml5() && in_array($value, $defaultJsMimes)) {
                        continue;
                    }

                    // B/C: If defer and async is false or empty don't render the attribute.
                    if (in_array($attrib, array(
                            'defer',
                            'async'
                        )) && !$value) {
                        continue;
                    }

                    // Don't add type attribute if document is HTML5 and it's a default mime type. 'mime' is for B/C.
                    if ($attrib === 'mime') {
                        $attrib = 'type';
                    } // B/C defer and async can be set to yes when using the old method.
                    else if (in_array($attrib, array(
                            'defer',
                            'async'
                        )) && $value === true) {
                        $value = $attrib;
                    }

                    // Add attribute to script tag output.
                    $buffer .= ' ' . htmlspecialchars($attrib, ENT_COMPAT, 'UTF-8');

                    if (!($this->document->isHtml5() && in_array($attrib, $html5NoValueAttributes))) {
                        // Json encode value if it's an array.
                        $value = !is_scalar($value) ? json_encode($value) : $value;

                        $buffer .= '="' . htmlspecialchars($value, ENT_COMPAT, 'UTF-8') . '"';
                    }
                }

                $buffer .= '></script>';

                // This is for IE conditional statements support.
                if (!is_null($conditional)) {
                    $buffer .= '<![endif]-->';
                }

                $buffer .= $lnEnd;
            }

            foreach ($this->updates['_script'] as $type => $content) {
                $buffer .= $tab . '<script';

                if (!is_null($type) && (!$this->document->isHtml5() || !in_array($type, $defaultJsMimes))) {
                    $buffer .= ' type="' . $type . '"';
                }

                $buffer .= '>' . $lnEnd;

                // This is for full XHTML support.
                if ($this->document->_mime != 'text/html') {
                    $buffer .= $tab . $tab . '//<![CDATA[' . $lnEnd;
                }

                $buffer .= $content . $lnEnd;

                // See above note
                if ($this->document->_mime != 'text/html') {
                    $buffer .= $tab . $tab . '//]]>' . $lnEnd;
                }

                $buffer .= $tab . '</script>' . $lnEnd;
            }

            return $buffer;
        } else {
            return null;
        }
    }
}Joomla/JoomlaModule.php000064400000000775152356644720011114 0ustar00<?php


namespace Nextend\SmartSlider3\Platform\Joomla;


use Joomla\Registry\Registry;

class JoomlaModule {

    /**
     * JoomlaModule constructor.
     *
     * @param Registry $params
     */
    public function __construct($params) {

        $sliderId = intval($params->get('slider'));

        if (defined('LITESPEED_ESI_SUPPORT')) {
            nextend_smartslider3($sliderId);
        } else {
            echo 'smartslider3[' . esc_html($sliderId) . ']';
        }
    }
}Joomla/JoomlaShim.php000064400000020572152356644720010564 0ustar00<?php

namespace Nextend\SmartSlider3\Platform\Joomla;

use Exception;
use JEventDispatcher;
use Joomla\CMS\Factory;
use Joomla\Event\Event;
use Joomla\CMS\Plugin\PluginHelper;
use Nextend\Framework\Pattern\SingletonTrait;
use Nextend\Security\Joomla\JoomlaSecurity;
use Nextend\SmartSlider3\Settings;
use ReflectionFunction;

class JoomlaShim {

    use SingletonTrait;

    public static $isJoomla4 = 0;

    protected function init() {
        self::$isJoomla4 = version_compare(JVERSION, '4', '>=') ? 1 : 0;

        JoomlaSecurity::getInstance();
    }

    public static function getDispatcher() {
        if (!self::$isJoomla4) {
            return JEventDispatcher::getInstance();
        }

        return Factory::getApplication()
                      ->getDispatcher();
    }

    private static function getExcludedContentPlugins() {
        static $excludedPlugins;
        if ($excludedPlugins === null) {

            $excludedPlugins   = explode('||', Settings::get('joomla-plugins-content-excluded', ''));
            $excludedPlugins[] = 'plgcontentemailcloak';
            $excludedPlugins[] = 'plgcontentdropeditor';
            $excludedPlugins[] = 'plgcontentshortcode_ultimate';
            $excludedPlugins[] = 'plgcontentarkcontent';
            $excludedPlugins[] = 'plgcontentosyoutube';
            $excludedPlugins[] = 'plgsystemt4';
            $excludedPlugins[] = 'plgcontentfields';
        }

        return $excludedPlugins;
    }

    public static function triggerOnContentPrepare($data) {
        static $contentPluginsEnabled, $pluginsToRun = array();

        PluginHelper::importPlugin('content');

        if (!self::$isJoomla4) {
            if ($contentPluginsEnabled === null) {
                $contentPluginsEnabled = intval(Settings::get('joomla-plugins-content-enabled', 1));

                if ($contentPluginsEnabled) {
                    $classNames = array();
                    foreach (PluginHelper::getPlugin('content') as $plugin) {
                        $classNames[] = strtolower('Plg' . $plugin->type . $plugin->name);
                    }

                    $classNames = array_diff($classNames, self::getExcludedContentPlugins());

                    $dispatcher = JEventDispatcher::getInstance();

                    $observers = $dispatcher->get('_observers');

                    foreach ($observers as $observer) {
                        if (is_object($observer)) {
                            $className = strtolower(get_class($observer));
                            if (in_array($className, $classNames)) {
                                $pluginsToRun[] = $observer;
                            } else if (method_exists($observer, 'onContentPrepare') && !in_array($className, self::getExcludedContentPlugins())) {
                                $pluginsToRun[] = $observer;
                            }
                        }
                    }
                }
            }

            if ($contentPluginsEnabled && !empty($pluginsToRun)) {
                foreach ($pluginsToRun as $observer) {
                    // Joomla removes it in every update
                    $data['event'] = 'oncontentprepare';
                    $observer->update($data);
                }
            }

            return true;
        }


        if ($contentPluginsEnabled === null) {
            $contentPluginsEnabled = intval(Settings::get('joomla-plugins-content-enabled', 1));
            if ($contentPluginsEnabled) {

                $classNames = array();
                foreach (PluginHelper::getPlugin('content') as $plugin) {
                    $classNames[] = strtolower('Plg' . $plugin->type . $plugin->name);
                }

                $classNames = array_diff($classNames, self::getExcludedContentPlugins());

                $dispatcher = Factory::getApplication()
                                     ->getDispatcher();

                $listeners = $dispatcher->getListeners('onContentPrepare');

                foreach ($listeners as $listener) {
                    if (is_array($listener)) {
                        if (is_callable($listener) && is_object($listener[0])) {

                            $className = strtolower(get_class($listener[0]));
                            if (in_array($className, $classNames)) {
                                $pluginsToRun[] = $listener;
                            }
                        }
                    } else {

                        $fn        = new ReflectionFunction($listener);
                        $fnClosure = $fn->getClosureThis();

                        if (is_object($fnClosure)) {
                            $className = strtolower(get_class($fnClosure));
                            if (in_array($className, $classNames)) {
                                $pluginsToRun[] = $listener;
                            }
                        }
                    }
                }
            }
        }

        if ($contentPluginsEnabled && !empty($pluginsToRun)) {
            $event = new Event('onContentPrepare', $data);
            foreach ($pluginsToRun as $callable) {

                try {
                    call_user_func($callable, $event);
                } catch (Exception $e) {
                }
            }
        }

        return true;
    }

    public static function getOnContentPreparePluginsList() {
        if (!self::$isJoomla4) {

            PluginHelper::importPlugin('content');

            $dispatcher = JEventDispatcher::getInstance();

            $classNames = array();
            foreach ($dispatcher->get('_observers') as $observer) {
                if ((is_object($observer) || (is_string($observer) && class_exists($observer))) && method_exists($observer, 'onContentPrepare')) {
                    $className              = strtolower(get_class($observer));
                    $classNames[$className] = $className;
                }
            }

            foreach (PluginHelper::getPlugin('content') as $plugin) {
                $className              = strtolower('Plg' . $plugin->type . $plugin->name);
                $classNames[$className] = ucfirst($plugin->name);
            }

            return $classNames;
        }

        PluginHelper::importPlugin('content');

        $dispatcher = Factory::getApplication()
                             ->getDispatcher();

        $classNames = array();
        foreach ($dispatcher->getListeners('onContentPrepare') as $listener) {

            if (is_array($listener)) {
                if (is_callable($listener) && is_object($listener[0])) {

                    $className              = strtolower(get_class($listener[0]));
                    $classNames[$className] = $className;
                }
            } else {
                $fn        = new ReflectionFunction($listener);
                $fnClosure = $fn->getClosureThis();

                if (is_object($fnClosure)) {
                    $className              = strtolower(get_class($fnClosure));
                    $classNames[$className] = $className;
                }
            }
        }

        foreach (PluginHelper::getPlugin('content') as $plugin) {
            $className              = strtolower('Plg' . $plugin->type . $plugin->name);
            $classNames[$className] = ucfirst($plugin->name);
        }

        return $classNames;
    }

    public static function triggerEvent($eventName, $args = array()) {
        if (!self::$isJoomla4) {
            $dispatcher = JEventDispatcher::getInstance();

            return $dispatcher->trigger('onInitN2Library', $args);
        }

        return Factory::getApplication()
                       ->triggerEvent($eventName, $args);
    }

    public static function loadComContentRoute() {
        if (!self::$isJoomla4) {
            require_once JPATH_ROOT . '/components/com_content/helpers/route.php';
        }
    }

    public static function mediaLibraryUrl() {
        if (!self::$isJoomla4) {
            return 'index.php?option=com_media&view=images&tmpl=component&asset=com_content&author=&fieldid=notused&folder=';
        }

        return 'index.php?option=com_media&tmpl=component&asset=86&author=584&fieldid={field-media-id}&path=local-0:/';
    }
}

JoomlaShim::getInstance();Joomla/SmartSlider3PlatformJoomla.php000064400000001372152356644720013702 0ustar00<?php


namespace Nextend\SmartSlider3\Platform\Joomla;


use Joomla\CMS\Uri\Uri;
use Nextend\Framework\Sanitize;
use Nextend\SmartSlider3\Platform\AbstractSmartSlider3Platform;

class SmartSlider3PlatformJoomla extends AbstractSmartSlider3Platform {

    public function start() {

        require_once(dirname(__FILE__) . '/compat.php');

        $this->initSanitize();
    }


    public function getAdminUrl() {

        return Uri::root() . 'administrator/index.php?option=com_smartslider3';
    }

    public function getAdminAjaxUrl() {

        return Uri::root() . 'administrator/index.php?option=com_smartslider3&nextendajax=1';
    }

    private function initSanitize() {
        Sanitize::set_allowed_tags();
    }
}Joomla/Module/Field/FieldEditSlider.php000064400000001337152356644720013764 0ustar00<?php


namespace Nextend\SmartSlider3\Platform\Joomla\Module\Field;


use Joomla\CMS\Form\FormField;
use Joomla\CMS\Uri\Uri;

jimport('joomla.form.formfield');

class FieldEditSlider extends FormField {

    protected $type = 'EditSlider';

    public function getInput() {
        $style = '<style>#jform_params_slider_chzn{width:100% !important;max-width:500px;}</style>';

        return $style . '<a href="#" onclick="window.open(\'' . Uri::root() . 'administrator/index.php?option=com_smartslider3&nextendcontroller=slider&nextendaction=edit&sliderid=\' + jQuery(\'#jform_params_slider\').val(), \'_blank\'); return false;" class="btn btn-small btn-success" target="_blank"> Edit selected slider</a>';
    }
}Joomla/Plugin/PluginInstallerSmartSlider3.php000064400000002352152356644720015325 0ustar00<?php

namespace Nextend\SmartSlider3\Platform\Joomla\Plugin;

use Joomla\CMS\Factory;
use Joomla\CMS\Plugin\CMSPlugin;
use Nextend\SmartSlider3\Application\Model\ModelLicense;
use Nextend\SmartSlider3\SmartSlider3Info;

class PluginInstallerSmartSlider3 extends CMSPlugin {

    public function onInstallerBeforePackageDownload(&$url, &$headers) {

        if (in_array(parse_url($url, PHP_URL_HOST), array(
                'secure.nextendweb.com',
                'api.nextendweb.com'
            )) && strpos($url, 'smartslider3')) {

            $license  = ModelLicense::getInstance();
            $isActive = $license->isActive() == 'OK';

            if (!$isActive) {
                Factory::getApplication()
                        ->enqueueMessage('Update error: Smart Slider 3 Pro is not activated on your site!', 'error');

                $url = SmartSlider3Info::api(array(
                    'action' => 'joomla_fail'
                ), true);

                return false;
            }

            $url = SmartSlider3Info::api(array(
                'action'  => 'joomla_update',
                'channel' => SmartSlider3Info::$channel
            ), true);
        }

        return true;
    }
}Joomla/Plugin/PluginSmartSlider3.php000064400000013130152356644720013443 0ustar00<?php


namespace Nextend\SmartSlider3\Platform\Joomla\Plugin;

use Artx;
use ArtxPage;
use EshopHelper;
use Joomla\CMS\Factory;
use Joomla\CMS\Application\SiteApplication;
use Joomla\CMS\Plugin\CMSPlugin;
use Nextend\Framework\Asset\AssetManager;
use Nextend\SmartSlider3\Platform\Joomla\Joomla3Assets;
use Nextend\SmartSlider3\Platform\Joomla\JoomlaShim;

jimport('joomla.plugin.plugin');

/**
 * Class PluginSmartSlider3
 *
 * Used in Joomla -> Plugin -> System -> Nextend2
 */
class PluginSmartSlider3 extends CMSPlugin {

    private $hadError = false;

    /*
    Artisteer jQuery fix
    */
    public function onAfterDispatch() {
        if (class_exists('Artx', true)) {
            Artx::load("Artx_Page");
            if (isset(ArtxPage::$inlineScripts)) {
                ArtxPage::$inlineScripts[] = '<script>if(typeof jQuery != "undefined") window.artxJQuery = jQuery;</script>';
            }
        }
    }

    private function isRenderAllowed() {
        static $isAllowed;

        if ($isAllowed === null) {
            /**
             * @var SiteApplication $application
             */
            $application = Factory::getApplication();
            if ($application->isClient('site')) {
                $request   = $application->input->request;
                $isAllowed = true;

                if (!Factory::getUser()->guest) {

                    if ($request->get('view') == 'form' && $request->get('layout') == 'edit' && $application->input->getInt('a_id') > 0) {
                        //Joomla frontend article editing
                        $isAllowed = false;

                    } else if ($request->get('option') == 'com_quix' && $request->get('layout') == 'edit' || $request->get('builder') == 'frontend') {
                        //Quix Visual Builder
                        $isAllowed = false;

                    } else if ($application->input->get('option') == 'com_sppagebuilder' && $application->input->get('layout') == 'edit') {
                        //SP Page Builder - @see SSDEV-3640
                        $isAllowed = false;
                    }
                }

                if ($request->get('type') == 'rss') {
                    //RSS feed
                    $isAllowed = false;
                }
            } else {
                $isAllowed = false;
            }
        }

        return $isAllowed;
    }

    private function displaySliders($output) {

        if (strpos($output, 'smartslider3[') !== false) {
            if (class_exists('\\EshopHelper', false) && EshopHelper::getConfigValue('rich_snippets') == '1') {
                $output = preg_replace_callback('/(<.*?>)?smartslider3\[([0-9]+)\]/', array(
                    self::class,
                    'cleanEshop'
                ), $output);
            }

            $output = preg_replace_callback('/smartslider3\[([0-9]+)\]/', array(
                self::class,
                'prepare'
            ), $output);
        }

        return $output;
    }

    private function onNextendBeforeCompileHead() {

        if ($this->isRenderAllowed()) {

            /**
             * @var SiteApplication $application
             */
            $application = Factory::getApplication();

            $body = $application->getBody();

            // Simple performance check to determine whether bot should process further
            if (strpos($body, 'smartslider3[') !== false) {


                $bodyParts = explode('</head>', $body);
                /**
                 * Last part is not the head
                 */
                $lastPart             = count($bodyParts) - 1;
                $bodyParts[$lastPart] = $this->displaySliders($bodyParts[$lastPart]);

                $application->setBody(implode('</head>', $bodyParts));
            }
        }
    }

    public function onAfterRender() {

        if (!JoomlaShim::$isJoomla4) {
            $joomla3Assets = new Joomla3Assets();

            $this->onNextendBeforeCompileHead();

            $joomla3Assets->process();
        } else {

            $this->onNextendBeforeCompileHead();
        }


        ob_start();
        if (class_exists('\\Nextend\\Framework\\Asset\\AssetManager', false)) {


            // PHPCS - Content already escaped
            echo AssetManager::getCSS(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped

            // PHPCS - Content already escaped
            echo AssetManager::getJs(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
        }
        $head = ob_get_clean();
        if (!empty($head)) {

            $application = Factory::getApplication();
            $body        = $application->getBody();

            $parts = preg_split('/<\/head>/', $body, 2);

            if (!JoomlaShim::$isJoomla4) {
                $head .= $joomla3Assets->renderHead();
            }

            $body = implode($head . '</head>', $parts);

            $application->setBody($body);
        }
    }

    public function onError() {
        $this->hadError = true;
    }

    public function onBeforeRespond() {
        if ($this->hadError) {
            $this->onAfterRender();
        }
    }

    public static function prepare($matches) {
        ob_start();
        nextend_smartslider3($matches[1]);

        return ob_get_clean();
    }

    public static function cleanEshop($matches) {
        if (strpos($matches[1], 'itemprop') !== false) {
            return $matches[1];
        }

        return $matches[0];
    }
}