Your IP : 216.73.216.61


Current Path : /home/wuectly/www/03cbe/
Upload File :
Current File : /home/wuectly/www/03cbe/includes.tar

index.html000060400000000037152453623630006546 0ustar00<!DOCTYPE html><title></title>
framework.php000060400000005524152453623630007265 0ustar00<?php
/**
 * @package    Joomla.Administrator
 *
 * @copyright  (C) 2005 Open Source Matters, Inc. <https://www.joomla.org>
 * @license    GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\Utilities\IpHelper;

// Joomla system checks.
@ini_set('magic_quotes_runtime', 0);

// System includes
require_once JPATH_LIBRARIES . '/import.legacy.php';

// Bootstrap the CMS libraries.
require_once JPATH_LIBRARIES . '/cms.php';

// Set system error handling
JError::setErrorHandling(E_NOTICE, 'message');
JError::setErrorHandling(E_WARNING, 'message');
JError::setErrorHandling(E_ERROR, 'message', array('JError', 'customErrorPage'));

$version = new JVersion;

// Installation check, and check on removal of the install directory.
if (!file_exists(JPATH_CONFIGURATION . '/configuration.php')
	|| (filesize(JPATH_CONFIGURATION . '/configuration.php') < 10)
	|| (file_exists(JPATH_INSTALLATION . '/index.php') && (false === $version->isInDevelopmentState())))
{
	if (file_exists(JPATH_INSTALLATION . '/index.php'))
	{
		header('Location: ../installation/index.php');

		exit();
	}
	else
	{
		echo 'No configuration file found and no installation code available. Exiting...';

		exit;
	}
}

// Pre-Load configuration. Don't remove the Output Buffering due to BOM issues, see JCode 26026
ob_start();
require_once JPATH_CONFIGURATION . '/configuration.php';
ob_end_clean();

// System configuration.
$config = new JConfig;

// Set the error_reporting
switch ($config->error_reporting)
{
	case 'default':
	case '-1':
		break;

	case 'none':
	case '0':
		error_reporting(0);

		break;

	case 'simple':
		error_reporting(E_ERROR | E_WARNING | E_PARSE);
		ini_set('display_errors', 1);

		break;

	case 'maximum':
		error_reporting(E_ALL);
		ini_set('display_errors', 1);

		break;

	case 'development':
		error_reporting(-1);
		ini_set('display_errors', 1);

		break;

	default:
		error_reporting($config->error_reporting);
		ini_set('display_errors', 1);

		break;
}

define('JDEBUG', $config->debug);

// System profiler
if (JDEBUG)
{
	// @deprecated 4.0 - The $_PROFILER global will be removed
	$_PROFILER = JProfiler::getInstance('Application');
}

/**
 * Correctly set the allowing of IP Overrides if behind a trusted proxy/load balancer.
 *
 * We need to do this as high up the stack as we can, as the default in \Joomla\Utilities\IpHelper is to
 * $allowIpOverride = true which is the wrong default for a generic site NOT behind a trusted proxy/load balancer.
 */
if (property_exists($config, 'behind_loadbalancer') && $config->behind_loadbalancer == 1)
{
	// If Joomla is configured to be behind a trusted proxy/load balancer, allow HTTP Headers to override the REMOTE_ADDR
	IpHelper::setAllowIpOverrides(true);
}
else
{
	// We disable the allowing of IP overriding using headers by default.
	IpHelper::setAllowIpOverrides(false);
}

unset($config);
defines.php000060400000002040152453623630006673 0ustar00<?php
/**
 * @package    Joomla.Administrator
 *
 * @copyright  (C) 2005 Open Source Matters, Inc. <https://www.joomla.org>
 * @license    GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

// Global definitions
$parts = explode(DIRECTORY_SEPARATOR, JPATH_BASE);
array_pop($parts);

// Defines
define('JPATH_ROOT',          implode(DIRECTORY_SEPARATOR, $parts));
define('JPATH_SITE',          JPATH_ROOT);
define('JPATH_CONFIGURATION', JPATH_ROOT);
define('JPATH_ADMINISTRATOR', JPATH_ROOT . DIRECTORY_SEPARATOR . 'administrator');
define('JPATH_LIBRARIES',     JPATH_ROOT . DIRECTORY_SEPARATOR . 'libraries');
define('JPATH_PLUGINS',       JPATH_ROOT . DIRECTORY_SEPARATOR . 'plugins');
define('JPATH_INSTALLATION',  JPATH_ROOT . DIRECTORY_SEPARATOR . 'installation');
define('JPATH_THEMES',        JPATH_BASE . DIRECTORY_SEPARATOR . 'templates');
define('JPATH_CACHE',         JPATH_BASE . DIRECTORY_SEPARATOR . 'cache');
define('JPATH_MANIFESTS',     JPATH_ADMINISTRATOR . DIRECTORY_SEPARATOR . 'manifests');
renderer/megamenurender.php000060400000005606152455303030012064 0ustar00<?php
/**
 * @package     Joomla.Platform
 * @subpackage  Document
 *
 * @copyright   Copyright (C) 2005 - 2012 Open Source Matters, Inc. All rights reserved.
 * @license     GNU General Public License version 2 or later; see LICENSE
 */

use Joomla\CMS\Document\DocumentRenderer;

defined('JPATH_PLATFORM') or die;

/**
 * JDocument Megamenu renderer
 */
class JDocumentRendererMegamenuRender extends DocumentRenderer
{
	/**
	 * Render megamenu block, then push the output into megamenu renderer to display
	 *
	 * @param   string  $position  The position of the modules to render
	 * @param   array   $params    Associative array of values
	 * @param   string  $content   Module content
	 *
	 * @return  string  The output of the script
	 *
	 * @since   11.1
	 */
	public function render($info = null, $params = array(), $content = null)
	{
		T3::import('menu/megamenu');

		$t3app = T3::getApp();

		//we will check from params
		$menutype      = empty($params['menutype']) ? (empty($params['name']) ? $t3app->getParam('mm_type', 'mainmenu') : $params['name']) : $params['menutype'];
		$currentconfig = json_decode($t3app->getParam('mm_config', ''), true);

		//force to array
		if (!is_array($currentconfig)) {
			$currentconfig = (array)$currentconfig;
		}

		//get user access levels
		$viewLevels = JFactory::getUser()->getAuthorisedViewLevels();
		$mmkey = $menutype;
		$mmconfig = array();
		if (!empty($currentconfig)) {
			//find best fit configuration based on view level
			$vlevels = array_merge($viewLevels);
			if (is_array($vlevels) && in_array(3, $vlevels)) { //we assume, if a user is special, they should be registered also
				$vlevels[] = 2;
			}
			$vlevels = array_unique($vlevels);
			rsort($vlevels);
			if (!is_array($vlevels)) $vlevels = array();
			$vlevels[] = ''; // extend a blank, default key

			// check if available configuration for language override
			$langcode = JFactory::getDocument()->language;
			$shortlangcode = substr($langcode, 0, 2);
			$types = array($menutype . '-' . $langcode, $menutype . '-' . $shortlangcode, $menutype);

			foreach ($types as $type) {
				foreach ($vlevels as $vlevel) {
					$key  = $type . ($vlevel !== '' ? '-' . $vlevel : '');
					if(isset($currentconfig[$key])) {
						$mmkey    = $key;
						$menutype = $type;
						break 2;
					}
				}
			}
			if (isset($currentconfig[$mmkey])) {
				$mmconfig = $currentconfig[$mmkey];
				if(!is_array($mmconfig)){
					$mmconfig = array();
				}
			}
		}

		JFactory::getApplication()->triggerEvent('onT3Megamenu', array(&$menutype, &$mmconfig, &$viewLevels));

		$mmconfig['access'] = $viewLevels;
		$menu = new T3MenuMegamenu ($menutype, $mmconfig, $t3app->_tpl->params);

		$buffer = $menu->render(true);

		if (isset($params['return_result']) && $params['return_result']) {
			return $buffer;
		} else {
			$t3app->setBuffer($buffer, 'megamenu', empty($params['name']) ? null : $params['name'], null);
			return '';
		}
	}
}
renderer/pageclass.php000060400000004223152455303030011022 0ustar00<?php
/**
 * @package     Joomla.Platform
 * @subpackage  Document
 *
 * @copyright   Copyright (C) 2005 - 2012 Open Source Matters, Inc. All rights reserved.
 * @license     GNU General Public License version 2 or later; see LICENSE
 */

use Joomla\CMS\Document\DocumentRenderer;

defined('JPATH_PLATFORM') or die;

/**
 * JDocument Bodyclass renderer
 *
 * @package     Joomla.Platform
 * @subpackage  Document
 * @since       11.1
 */
class JDocumentRendererPageClass extends DocumentRenderer
{
	/**
	 * Render body class of current page
	 *
	 * @param   string  $position  The position of the modules to render
	 * @param   array   $params    Associative array of values
	 * @param   string  $content   Module content
	 *
	 * @return  string  The output of the script
	 *
	 * @since   11.1
	 */
	public function render($info, $params = array(), $content = null)
	{
		$input = JFactory::getApplication()->input;
		$t3tpl = T3::getApp();
		$pageclass = array();
		if($input->getCmd('option', '')){
			$pageclass[] = $input->getCmd('option', '');
		}
		if($input->getCmd('view', '')){
			$pageclass[] = 'view-' . $input->getCmd('view', '');
		}
		if($input->getCmd('layout', '')){
			$pageclass[] = 'layout-' . $input->getCmd('layout', '');
		}
		if($input->getCmd('task', '')){
			$pageclass[] = 'task-' . $input->getCmd('task', '');
		}
		if($input->getCmd('Itemid', '')){
			$pageclass[] = 'itemid-' . $input->getCmd('Itemid', '');
		}

		$menu = JFactory::getApplication()->getMenu();
		if($menu){
			$active = $menu->getActive();
			$default = $menu->getDefault();

			if ($active) {
				if($default && $active->id == $default->id){
					$pageclass[] = 'home';
				}

				if ($active->getParams() && $active->getParams()->get('pageclass_sfx')) {
					$pageclass[] = $active->getParams()->get('pageclass_sfx');
				}
			}
		}

		$pageclass[] = 'j'.str_replace('.', '', (number_format((float)JVERSION, 1, '.', '')));
		if(version_compare(JVERSION,'4','ge')){
			$pageclass[] = 'j40';
		}

		$pageclass = array_unique(array_merge($pageclass, $t3tpl->getPageclass()));

		JFactory::getApplication()->triggerEvent('onT3BodyClass', array(&$pageclass));

		return implode(' ', $pageclass);
	}

}
renderer/megamenu.php000060400000001637152455303030010664 0ustar00<?php
/**
 * @package     Joomla.Platform
 * @subpackage  Document
 *
 * @copyright   Copyright (C) 2005 - 2012 Open Source Matters, Inc. All rights reserved.
 * @license     GNU General Public License version 2 or later; see LICENSE
 */

defined('JPATH_PLATFORM') or die;

/**
 * JDocument Megamenu renderer - this is a placeholder for menumenurender
 */
T3::import('renderer/megamenurender');

class JDocumentRendererMegamenu extends JDocumentRendererMegamenuRender
{
	/**
	 * Render megamenu block
	 *
	 * @param   string  $position  The position of the modules to render
	 * @param   array   $params    Associative array of values
	 * @param   string  $content   Module content
	 *
	 * @return  string  The output of the script
	 *
	 * @since   11.1
	 */
	public function render($info = null, $params = array(), $content = null)
	{
		$params['return_result'] = true;
		return parent::render($info, $params, $content);
	}
}
renderer/t3ajax.php000060400000006437152455303030010263 0ustar00<?php
/**
 * @package     Joomla.Platform
 * @subpackage  Document
 *
 * @copyright   Copyright (C) 2005 - 2012 Open Source Matters, Inc. All rights reserved.
 * @license     GNU General Public License version 2 or later; see LICENSE
 */

defined('JPATH_PLATFORM') or die;

/**
 * JDocument Modules renderer
 *
 * @package     Joomla.Platform
 * @subpackage  Document
 * @since       11.1
 */
class JDocumentRendererT3Ajax extends JDocumentRenderer
{
	/**
	 * Renders multiple modules script and returns the results as a string
	 *
	 * @param   string  $position  The position of the modules to render
	 * @param   array   $params    Associative array of values
	 * @param   string  $content   Module content
	 *
	 * @return  string  The output of the script
	 *
	 * @since   11.1
	 */
	public function render($info, $params = array(), $content = null)
	{
		$input = JFactory::getApplication()->input;
		$task = $input->getCmd('t3ajax', 'position');
		$format = $input->getCmd('f', 'html');

		if($task == 'position'){
			if($format == 'html'){
				return $this->htmlPosition($info, $params, $content);
			} else if($format == 'json'){
				return $this->jsonPosition($info, $params, $content);
			}
		} else if($task == 'module'){
			if($format == 'html'){
				return $this->htmlModule($info, $params, $content);
			} else if($format == 'json'){
				return $this->jsonModule($info, $params, $content);
			}
		}

		return null;
	}

	protected function htmlPosition($info, $params = array(), $content = null)
	{		
		$renderer = $this->_doc->loadRenderer('module');
		
		$input = JFactory::getApplication()->input;
		$position = $input->getCmd('p');

		$buffer = '';

		foreach (JModuleHelper::getModules($position) as $mod)
		{
			$buffer .= $renderer->render($mod, $params, $content);
		}

		return $buffer;
	}

	protected function jsonPosition($info, $params = array(), $content = null)
	{		
		$result = array();
		
		$result['markup'] = $this->htmlPosition($info, $params = array(), $content = null);
		
		$result['stylesheets'] = $this->_doc->_styleSheets;
		$result['styles'] = $this->_doc->_style;

		$result['scripts'] = $this->_doc->_scripts;
		$result['scriptinlines'] = $this->_doc->_script;

		return json_encode($result);
	}

	protected function htmlModule($info, $params = array(), $content = null)
	{		
		$input = JFactory::getApplication()->input;
		$mid = $input->getInt('m');

		$db = JFactory::getDbo();
		$query = $db->getQuery(true);
		$query->select('m.id, m.title, m.module, m.position, m.content, m.showtitle, m.params');
		$query->from('#__modules AS m');
		$query->where('m.id = '. $mid);
		$query->where('m.published = 1');
		$db->setQuery($query);
		$module = $db->loadObject();
		
		$buffer = '';
		//check in case the module is unpublish or deleted
		if($module && $module->id){
			$buffer = JModuleHelper::renderModule($module, array('style'=> $input->getCmd('style', 'T3Xhtml')));
		}

		return $buffer;
	}

	protected function jsonModule($info, $params = array(), $content = null)
	{		
		$result = array();
		
		$result['markup'] = $this->htmlModule($info, $params = array(), $content = null);
		
		$result['stylesheets'] = $this->_doc->_styleSheets;
		$result['styles'] = $this->_doc->_style;

		$result['scripts'] = $this->_doc->_scripts;
		$result['scriptinlines'] = $this->_doc->_script;

		return json_encode($result);
	}
}
renderer/t3bootstrap.php000060400000002355152455303030011350 0ustar00<?php
/**
 * @package     Joomla.Platform
 * @subpackage  Document
 *
 * @copyright   Copyright (C) 2005 - 2012 Open Source Matters, Inc. All rights reserved.
 * @license     GNU General Public License version 2 or later; see LICENSE
 */

use Joomla\CMS\Document\DocumentRenderer;

defined('JPATH_PLATFORM') or die;

/**
 * JDocument Megamenu renderer
 */
class JDocumentRendererT3Bootstrap extends DocumentRenderer
{
	/**
	 * Render megamenu block
	 *
	 * @param   string  $position  The position of the modules to render
	 * @param   array   $params    Associative array of values
	 * @param   string  $content   Module content
	 *
	 * @return  string  The output of the script
	 *
	 * @since   11.1
	 */
	public function render($info = null, $params = array(), $content = null)
	{
		T3::import('menu/t3bootstrap');

		// import the renderer
		$t3app    = T3::getApp();
		$menutype = empty($params['menutype']) ? $t3app->getParam('mm_type', 'mainmenu') : $params['menutype'];
		if(version_compare(JVERSION, '3','lt')){
			JDispatcher::getInstance()->trigger('onT3BSMenu', array(&$menutype));
		}else{
			JFactory::getApplication()->triggerEvent('onT3BSMenu', array(&$menutype));
		}
		$menu = new T3Bootstrap($menutype);
		
		return $menu->render(true);
	}
}
joomla25/html/bootstrap.php000060400000073041152455303030011667 0ustar00<?php
/**
 * @package     Joomla.Libraries
 * @subpackage  HTML
 *
 * @copyright   Copyright (C) 2005 - 2014 Open Source Matters, Inc. All rights reserved.
 * @license     GNU General Public License version 2 or later; see LICENSE
 */

defined('JPATH_PLATFORM') or die;

/**
 * Utility class for Bootstrap elements.
 *
 * @package     Joomla.Libraries
 * @subpackage  HTML
 * @since       3.0
 */
abstract class JHtmlBootstrap
{
	/**
	 * @var    array  Array containing information for loaded files
	 * @since  3.0
	 */
	protected static $loaded = array();

	/**
	 * Add javascript support for the Bootstrap affix plugin
	 *
	 * @param   string  $selector  Unique selector for the element to be affixed.
	 * @param   array   $params    An array of options.
	 *                             Options for the affix plugin can be:
	 *                             - offset  number|function|object  Pixels to offset from screen when calculating position of scroll.
	 *                                                               If a single number is provided, the offset will be applied in both top
	 *                                                               and left directions. To listen for a single direction, or multiple
	 *                                                               unique offsets, just provide an object offset: { x: 10 }.
	 *                                                               Use a function when you need to dynamically provide an offset
	 *                                                               (useful for some responsive designs).
	 *
	 * @return  void
	 *
	 * @since   3.1
	 */
	public static function affix($selector = 'affix', $params = array())
	{
		$sig = md5(serialize(array($selector, $params)));

		if (!isset(static::$loaded[__METHOD__][$sig]))
		{
			// Include Bootstrap framework
			static::framework();

			// Setup options object
			$opt['offset'] = isset($params['offset']) ? $params['offset'] : 10;

			$options = self::getJSObject($opt);

			// Attach the carousel to document
			JFactory::getDocument()->addScriptDeclaration(
				"(function($){
					$('#$selector').affix($options);
					})(jQuery);"
			);

			// Set static array
			static::$loaded[__METHOD__][$sig] = true;
		}

		return;
	}

	/**
	 * Add javascript support for Bootstrap alerts
	 *
	 * @param   string  $selector  Common class for the alerts
	 *
	 * @return  void
	 *
	 * @since   3.0
	 */
	public static function alert($selector = 'alert')
	{
		// Only load once
		if (isset(static::$loaded[__METHOD__][$selector]))
		{
			return;
		}

		// Include Bootstrap framework
		static::framework();

		// Attach the alerts to the document
		JFactory::getDocument()->addScriptDeclaration(
			"(function($){
				$('.$selector').alert();
				})(jQuery);"
		);

		static::$loaded[__METHOD__][$selector] = true;

		return;
	}

	/**
	 * Add javascript support for Bootstrap buttons
	 *
	 * @param   string  $selector  Common class for the buttons
	 *
	 * @return  void
	 *
	 * @since   3.1
	 */
	public static function button($selector = 'button')
	{
		// Only load once
		if (isset(static::$loaded[__METHOD__][$selector]))
		{
			return;
		}

		// Include Bootstrap framework
		static::framework();

		// Attach the alerts to the document
		JFactory::getDocument()->addScriptDeclaration(
			"(function($){
				$('.$selector').button();
				})(jQuery);"
		);

		static::$loaded[__METHOD__][$selector] = true;

		return;
	}

	/**
	 * Add javascript support for Bootstrap carousels
	 *
	 * @param   string  $selector  Common class for the carousels.
	 * @param   array   $params    An array of options for the modal.
	 *                             Options for the modal can be:
	 *                             - interval  number  The amount of time to delay between automatically cycling an item.
	 *                                                 If false, carousel will not automatically cycle.
	 *                             - pause     string  Pauses the cycling of the carousel on mouseenter and resumes the cycling
	 *                                                 of the carousel on mouseleave.
	 *
	 * @return  void
	 *
	 * @since   3.0
	 */
	public static function carousel($selector = 'carousel', $params = array())
	{
		$sig = md5(serialize(array($selector, $params)));

		if (!isset(static::$loaded[__METHOD__][$sig]))
		{
			// Include Bootstrap framework
			static::framework();

			// Setup options object
			$opt['interval'] = isset($params['interval']) ? (int) $params['interval'] : 5000;
			$opt['pause']    = isset($params['pause']) ? $params['pause'] : 'hover';

			$options = self::getJSObject($opt);

			// Attach the carousel to document
			JFactory::getDocument()->addScriptDeclaration(
				"(function($){
					$('.$selector').carousel($options);
					})(jQuery);"
			);

			// Set static array
			static::$loaded[__METHOD__][$sig] = true;
		}

		return;
	}

	/**
	 * Add javascript support for Bootstrap dropdowns
	 *
	 * @param   string  $selector  Common class for the dropdowns
	 *
	 * @return  void
	 *
	 * @since   3.0
	 */
	public static function dropdown($selector = 'dropdown-toggle')
	{
		// Only load once
		if (isset(static::$loaded[__METHOD__][$selector]))
		{
			return;
		}

		// Include Bootstrap framework
		static::framework();

		// Attach the dropdown to the document
		JFactory::getDocument()->addScriptDeclaration(
			"(function($){
				$('.$selector').dropdown();
				})(jQuery);"
		);

		static::$loaded[__METHOD__][$selector] = true;

		return;
	}

	/**
	 * Method to load the Bootstrap JavaScript framework into the document head
	 *
	 * If debugging mode is on an uncompressed version of Bootstrap is included for easier debugging.
	 *
	 * @param   mixed  $debug  Is debugging mode on? [optional]
	 *
	 * @return  void
	 *
	 * @since   3.0
	 */
	public static function framework($debug = null)
	{
    return; // T3 already load framework
	}

	/**
	 * Add javascript support for Bootstrap modals
	 *
	 * @param   string  $selector  The ID selector for the modal.
	 * @param   array   $params    An array of options for the modal.
	 *                             Options for the modal can be:
	 *                             - backdrop  boolean  Includes a modal-backdrop element.
	 *                             - keyboard  boolean  Closes the modal when escape key is pressed.
	 *                             - show      boolean  Shows the modal when initialized.
	 *                             - remote    string   An optional remote URL to load
	 *
	 * @return  void
	 *
	 * @since   3.0
	 */
	public static function modal($selector = 'modal', $params = array())
	{
		$sig = md5(serialize(array($selector, $params)));

		if (!isset(static::$loaded[__METHOD__][$sig]))
		{
			// Include Bootstrap framework
			static::framework();

			// Setup options object
			$opt['backdrop'] = isset($params['backdrop']) ? (boolean) $params['backdrop'] : true;
			$opt['keyboard'] = isset($params['keyboard']) ? (boolean) $params['keyboard'] : true;
			$opt['show']     = isset($params['show']) ? (boolean) $params['show'] : true;
			$opt['remote']   = isset($params['remote']) ?  $params['remote'] : '';

			$options = self::getJSObject($opt);

			// Attach the modal to document
			JFactory::getDocument()->addScriptDeclaration(
				"(function($){
					$('#$selector').modal($options);
					})(jQuery);"
			);

			// Set static array
			static::$loaded[__METHOD__][$sig] = true;
		}

		return;
	}

	/**
	 * Method to render a Bootstrap modal
	 *
	 * @param   string  $selector  The ID selector for the modal.
	 * @param   array   $params    An array of options for the modal.
	 * @param   string  $footer    Optional markup for the modal footer
	 *
	 * @return  string  HTML markup for a modal
	 *
	 * @since   3.0
	 */
	public static function renderModal($selector = 'modal', $params = array(), $footer = '')
	{
		// Ensure the behavior is loaded
		static::modal($selector, $params);

		$html = "<div class=\"modal hide fade\" id=\"" . $selector . "\">\n";
		$html .= "<div class=\"modal-header\">\n";
		$html .= "<button type=\"button\" class=\"close\" data-dismiss=\"modal\">�</button>\n";
		$html .= "<h3>" . $params['title'] . "</h3>\n";
		$html .= "</div>\n";
		$html .= "<div id=\"" . $selector . "-container\">\n";
		$html .= "</div>\n";
		$html .= "</div>\n";

		$html .= "<script>";
		$html .= "jQuery('#" . $selector . "').on('show', function () {\n";
		$html .= "document.getElementById('" . $selector . "-container').innerHTML = '<div class=\"modal-body\"><iframe class=\"iframe\" src=\""
			. $params['url'] . "\" height=\"" . $params['height'] . "\" width=\"" . $params['width'] . "\"></iframe></div>" . $footer . "';\n";
		$html .= "});\n";
		$html .= "</script>";

		return $html;
	}

	/**
	 * Add javascript support for Bootstrap popovers
	 *
	 * Use element's Title as popover content
	 *
	 * @param   string  $selector  Selector for the popover
	 * @param   array   $params    An array of options for the popover.
	 *                  Options for the popover can be:
	 *                      animation  boolean          apply a css fade transition to the popover
	 *                      html       boolean          Insert HTML into the popover. If false, jQuery's text method will be used to insert
	 *                                                  content into the dom.
	 *                      placement  string|function  how to position the popover - top | bottom | left | right
	 *                      selector   string           If a selector is provided, popover objects will be delegated to the specified targets.
	 *                      trigger    string           how popover is triggered - hover | focus | manual
	 *                      title      string|function  default title value if `title` tag isn't present
	 *                      content    string|function  default content value if `data-content` attribute isn't present
	 *                      delay      number|object    delay showing and hiding the popover (ms) - does not apply to manual trigger type
	 *                                                  If a number is supplied, delay is applied to both hide/show
	 *                                                  Object structure is: delay: { show: 500, hide: 100 }
	 *                      container  string|boolean   Appends the popover to a specific element: { container: 'body' }
	 *
	 * @return  void
	 *
	 * @since   3.0
	 */
	public static function popover($selector = '.hasPopover', $params = array())
	{
		// Only load once
		if (isset(static::$loaded[__METHOD__][$selector]))
		{
			return;
		}

		// Include Bootstrap framework
		static::framework();

		$opt['animation'] = isset($params['animation']) ? $params['animation'] : null;
		$opt['html']      = isset($params['html']) ? $params['html'] : true;
		$opt['placement'] = isset($params['placement']) ? $params['placement'] : null;
		$opt['selector']  = isset($params['selector']) ? $params['selector'] : null;
		$opt['title']     = isset($params['title']) ? $params['title'] : null;
		$opt['trigger']   = isset($params['trigger']) ? $params['trigger'] : 'hover focus';
		$opt['content']   = isset($params['content']) ? $params['content'] : null;
		$opt['delay']     = isset($params['delay']) ? $params['delay'] : null;
		$opt['container'] = isset($params['container']) ? $params['container'] : 'body';

		$options = self::getJSObject($opt);

		// Attach the popover to the document
		JFactory::getDocument()->addScriptDeclaration(
			"jQuery(document).ready(function()
			{
				jQuery('" . $selector . "').popover(" . $options . ");
			});"
		);

		static::$loaded[__METHOD__][$selector] = true;

		return;
	}

	/**
	 * Add javascript support for Bootstrap ScrollSpy
	 *
	 * @param   string  $selector  The ID selector for the ScrollSpy element.
	 * @param   array   $params    An array of options for the ScrollSpy.
	 *                             Options for the modal can be:
	 *                             - offset  number  Pixels to offset from top when calculating position of scroll.
	 *
	 * @return  void
	 *
	 * @since   3.0
	 */
	public static function scrollspy($selector = 'navbar', $params = array())
	{
		$sig = md5(serialize(array($selector, $params)));

		if (!isset(static::$loaded[__METHOD__][$sig]))
		{
			// Include Bootstrap framework
			static::framework();

			// Setup options object
			$opt['offset'] = isset($params['offset']) ? (int) $params['offset'] : 10;

			$options = self::getJSObject($opt);

			// Attach ScrollSpy to document
			JFactory::getDocument()->addScriptDeclaration(
				"(function($){
					$('#$selector').scrollspy($options);
					})(jQuery);"
			);

			// Set static array
			static::$loaded[__METHOD__][$sig] = true;
		}

		return;
	}

	/**
	 * Add javascript support for Bootstrap tooltips
	 *
	 * Add a title attribute to any element in the form
	 * title="title::text"
	 *
	 * @param   string  $selector  The ID selector for the tooltip.
	 * @param   array   $params    An array of options for the tooltip.
	 *                             Options for the tooltip can be:
	 *                             - animation  boolean          Apply a CSS fade transition to the tooltip
	 *                             - html       boolean          Insert HTML into the tooltip. If false, jQuery's text method will be used to insert
	 *                                                           content into the dom.
	 *                             - placement  string|function  How to position the tooltip - top | bottom | left | right
	 *                             - selector   string           If a selector is provided, tooltip objects will be delegated to the specified targets.
	 *                             - title      string|function  Default title value if `title` tag isn't present
	 *                             - trigger    string           How tooltip is triggered - hover | focus | manual
	 *                             - delay      integer          Delay showing and hiding the tooltip (ms) - does not apply to manual trigger type
	 *                                                           If a number is supplied, delay is applied to both hide/show
	 *                                                           Object structure is: delay: { show: 500, hide: 100 }
	 *                             - container  string|boolean   Appends the popover to a specific element: { container: 'body' }
	 *
	 * @return  void
	 *
	 * @since   3.0
	 */
	public static function tooltip($selector = '.hasTooltip', $params = array())
	{
		if (!isset(static::$loaded[__METHOD__][$selector]))
		{
			// Include Bootstrap framework
			static::framework();

			// Setup options object
			$opt['animation'] = isset($params['animation']) ? (boolean) $params['animation'] : null;
			$opt['html']      = isset($params['html']) ? (boolean) $params['html'] : true;
			$opt['placement'] = isset($params['placement']) ? (string) $params['placement'] : null;
			$opt['selector']  = isset($params['selector']) ? (string) $params['selector'] : null;
			$opt['title']     = isset($params['title']) ? (string) $params['title'] : null;
			$opt['trigger']   = isset($params['trigger']) ? (string) $params['trigger'] : null;
			$opt['delay']     = isset($params['delay']) ? (int) $params['delay'] : null;
			$opt['container'] = isset($params['container']) ? $params['container'] : 'body';
			$opt['template']  = isset($params['template']) ? (string) $params['template'] : null;
			$onShow = isset($params['onShow']) ? (string) $params['onShow'] : null;
			$onShown = isset($params['onShown']) ? (string) $params['onShown'] : null;
			$onHide = isset($params['onHide']) ? (string) $params['onHide'] : null;
			$onHidden = isset($params['onHidden']) ? (string) $params['onHidden'] : null;

			$options = self::getJSObject($opt);

			// Build the script.
			$script = array();
			$script[] = "jQuery(document).ready(function(){";
			$script[] = "\tjQuery('" . $selector . "').tooltip(" . $options . ");";

			if ($onShow)
			{
				$script[] = "\tjQuery('" . $selector . "').on('show.bs.tooltip', " . $onShow . ");";
			}

			if ($onShown)
			{
				$script[] = "\tjQuery('" . $selector . "').on('shown.bs.tooltip', " . $onShown . ");";
			}

			if ($onHide)
			{
				$script[] = "\tjQuery('" . $selector . "').on('hide.bs.tooltip', " . $onHide . ");";
			}

			if ($onHidden)
			{
				$script[] = "\tjQuery('" . $selector . "').on('hidden.bs.tooltip', " . $onHidden . ");";
			}

			$script[] = "});";

			// Attach tooltips to document
			JFactory::getDocument()->addScriptDeclaration(implode("\n", $script));

			// Set static array
			static::$loaded[__METHOD__][$selector] = true;
		}

		return;
	}

	/**
	 * Add javascript support for Bootstrap typeahead
	 *
	 * @param   string  $selector  The selector for the typeahead element.
	 * @param   array   $params    An array of options for the typeahead element.
	 *                             Options for the tooltip can be:
	 *                             - source       array, function  The data source to query against. May be an array of strings or a function.
	 *                                                             The function is passed two arguments, the query value in the input field and the
	 *                                                             process callback. The function may be used synchronously by returning the data
	 *                                                             source directly or asynchronously via the process callback's single argument.
	 *                             - items        number           The max number of items to display in the dropdown.
	 *                             - minLength    number           The minimum character length needed before triggering autocomplete suggestions
	 *                             - matcher      function         The method used to determine if a query matches an item. Accepts a single argument,
	 *                                                             the item against which to test the query. Access the current query with this.query.
	 *                                                             Return a boolean true if query is a match.
	 *                             - sorter       function         Method used to sort autocomplete results. Accepts a single argument items and has
	 *                                                             the scope of the typeahead instance. Reference the current query with this.query.
	 *                             - updater      function         The method used to return selected item. Accepts a single argument, the item and
	 *                                                             has the scope of the typeahead instance.
	 *                             - highlighter  function         Method used to highlight autocomplete results. Accepts a single argument item and
	 *                                                             has the scope of the typeahead instance. Should return html.
	 *
	 * @return  void
	 *
	 * @since   3.0
	 */
	public static function typeahead($selector = '.typeahead', $params = array())
	{
		if (!isset(static::$loaded[__METHOD__][$selector]))
		{
			// Include Bootstrap framework
			static::framework();

			// Setup options object
			$opt['source']      = isset($params['source']) ? $params['source'] : '[]';
			$opt['items']       = isset($params['items']) ? (int) $params['items'] : 8;
			$opt['minLength']   = isset($params['minLength']) ? (int) $params['minLength'] : 1;
			$opt['matcher']     = isset($params['matcher']) ? (string) $params['matcher'] : null;
			$opt['sorter']      = isset($params['sorter']) ? (string) $params['sorter'] : null;
			$opt['updater']     = isset($params['updater']) ? (string) $params['updater'] : null;
			$opt['highlighter'] = isset($params['highlighter']) ? (int) $params['highlighter'] : null;

			$options = self::getJSObject($opt);

			// Attach tooltips to document
			JFactory::getDocument()->addScriptDeclaration(
				"jQuery(document).ready(function()
				{
					jQuery('" . $selector . "').typeahead(" . $options . ");
				});"
			);

			// Set static array
			static::$loaded[__METHOD__][$selector] = true;
		}

		return;
	}

	/**
	 * Add javascript support for Bootstrap accordians and insert the accordian
	 *
	 * @param   string  $selector  The ID selector for the tooltip.
	 * @param   array   $params    An array of options for the tooltip.
	 *                             Options for the tooltip can be:
	 *                             - parent  selector  If selector then all collapsible elements under the specified parent will be closed when this
	 *                                                 collapsible item is shown. (similar to traditional accordion behavior)
	 *                             - toggle  boolean   Toggles the collapsible element on invocation
	 *                             - active  string    Sets the active slide during load
	 *
	 * @return  string  HTML for the accordian
	 *
	 * @since   3.0
	 */
	public static function startAccordion($selector = 'myAccordian', $params = array())
	{
		$sig = md5(serialize(array($selector, $params)));

		if (!isset(static::$loaded[__METHOD__][$sig]))
		{
			// Include Bootstrap framework
			static::framework();

			// Setup options object
			$opt['parent'] = isset($params['parent']) ? (boolean) $params['parent'] : false;
			$opt['toggle'] = isset($params['toggle']) ? (boolean) $params['toggle'] : true;
			$opt['active'] = isset($params['active']) ? (string) $params['active'] : '';

			$options = self::getJSObject($opt);

			// Attach accordion to document
			JFactory::getDocument()->addScriptDeclaration(
				"(function($){
					$('#$selector').collapse($options);
				})(jQuery);"
			);

			// Set static array
			static::$loaded[__METHOD__][$sig] = true;
			static::$loaded[__METHOD__]['active'] = $opt['active'];
		}

		return '<div id="' . $selector . '" class="accordion">';
	}

	/**
	 * Close the current accordion
	 *
	 * @return  string  HTML to close the accordian
	 *
	 * @since   3.0
	 */
	public static function endAccordion()
	{
		return '</div>';
	}

	/**
	 * Begins the display of a new accordion slide.
	 *
	 * @param   string  $selector  Identifier of the accordion group.
	 * @param   string  $text      Text to display.
	 * @param   string  $id        Identifier of the slide.
	 * @param   string  $class     Class of the accordion group.
	 *
	 * @return  string  HTML to add the slide
	 *
	 * @since   3.0
	 */
	public static function addSlide($selector, $text, $id, $class = '')
	{
		$in = (static::$loaded['JHtmlBootstrap::startAccordion']['active'] == $id) ? ' in' : '';
		$class = (!empty($class)) ? ' ' . $class : '';

		$html = '<div class="accordion-group' . $class . '">'
			. '<div class="accordion-heading">'
			. '<strong><a href="#' . $id . '" data-parent="#' . $selector . '" data-toggle="collapse" class="accordion-toggle">'
			. $text
			. '</a></strong>'
			. '</div>'
			. '<div class="accordion-body collapse' . $in . '" id="' . $id . '">'
			. '<div class="accordion-inner">';

		return $html;
	}

	/**
	 * Close the current slide
	 *
	 * @return  string  HTML to close the slide
	 *
	 * @since   3.0
	 */
	public static function endSlide()
	{
		return '</div></div></div>';
	}

	/**
	 * Creates a tab pane
	 *
	 * @param   string  $selector  The pane identifier.
	 * @param   array   $params    The parameters for the pane
	 *
	 * @return  string
	 *
	 * @since   3.1
	 */
	public static function startTabSet($selector = 'myTab', $params = array())
	{
		$sig = md5(serialize(array($selector, $params)));

		if (!isset(static::$loaded[__METHOD__][$sig]))
		{
			// Include Bootstrap framework
			static::framework();

			// Setup options object
			$opt['active'] = (isset($params['active']) && ($params['active'])) ? (string) $params['active'] : '';

			// Attach tabs to document
			JFactory::getDocument()
				->addScriptDeclaration(JLayoutHelper::render('libraries.cms.html.bootstrap.starttabsetscript', array('selector' => $selector)));

			// Set static array
			static::$loaded[__METHOD__][$sig] = true;
			static::$loaded[__METHOD__][$selector]['active'] = $opt['active'];
		}

		$html = JLayoutHelper::render('libraries.cms.html.bootstrap.starttabset', array('selector' => $selector));

		return $html;
	}

	/**
	 * Close the current tab pane
	 *
	 * @return  string  HTML to close the pane
	 *
	 * @since   3.1
	 */
	public static function endTabSet()
	{
		$html = JLayoutHelper::render('libraries.cms.html.bootstrap.endtabset');

		return $html;
	}

	/**
	 * Begins the display of a new tab content panel.
	 *
	 * @param   string  $selector  Identifier of the panel.
	 * @param   string  $id        The ID of the div element
	 * @param   string  $title     The title text for the new UL tab
	 *
	 * @return  string  HTML to start a new panel
	 *
	 * @since   3.1
	 */
	public static function addTab($selector, $id, $title)
	{
		static $tabScriptLayout = null;
		static $tabLayout = null;

		$tabScriptLayout = is_null($tabScriptLayout) ? new JLayoutFile('libraries.cms.html.bootstrap.addtabscript') : $tabScriptLayout;
		$tabLayout = is_null($tabLayout) ? new JLayoutFile('libraries.cms.html.bootstrap.addtab') : $tabLayout;

		$active = (static::$loaded['JHtmlBootstrap::startTabSet'][$selector]['active'] == $id) ? ' active' : '';

		// Inject tab into UL
		JFactory::getDocument()
		->addScriptDeclaration($tabScriptLayout->render(array('selector' => $selector,'id' => $id, 'active' => $active, 'title' => $title)));

		$html = $tabLayout->render(array('id' => $id, 'active' => $active));

		return $html;
	}

	/**
	 * Close the current tab content panel
	 *
	 * @return  string  HTML to close the pane
	 *
	 * @since   3.1
	 */
	public static function endTab()
	{
		$html = JLayoutHelper::render('libraries.cms.html.bootstrap.endtab');

		return $html;
	}

	/**
	 * Creates a tab pane
	 *
	 * @param   string  $selector  The pane identifier.
	 * @param   array   $params    The parameters for the pane
	 *
	 * @return  string
	 *
	 * @since   3.0
	 * @deprecated  4.0	Use JHtml::_('bootstrap.startTabSet') instead.
	 */
	public static function startPane($selector = 'myTab', $params = array())
	{
		$sig = md5(serialize(array($selector, $params)));

		if (!isset(static::$loaded['JHtmlBootstrap::startTabSet'][$sig]))
		{
			// Include Bootstrap framework
			static::framework();

			// Setup options object
			$opt['active'] = isset($params['active']) ? (string) $params['active'] : '';

			// Attach tooltips to document
			JFactory::getDocument()->addScriptDeclaration(
				"(function($){
					$('#$selector a').click(function (e) {
						e.preventDefault();
						$(this).tab('show');
					});
				})(jQuery);"
			);

			// Set static array
			static::$loaded['JHtmlBootstrap::startTabSet'][$sig] = true;
			static::$loaded['JHtmlBootstrap::startTabSet'][$selector]['active'] = $opt['active'];
		}

		return '<div class="tab-content" id="' . $selector . 'Content">';
	}

	/**
	 * Close the current tab pane
	 *
	 * @return  string  HTML to close the pane
	 *
	 * @since   3.0
	 * @deprecated  4.0	Use JHtml::_('bootstrap.endTabSet') instead.
	 */
	public static function endPane()
	{
		return '</div>';
	}

	/**
	 * Begins the display of a new tab content panel.
	 *
	 * @param   string  $selector  Identifier of the panel.
	 * @param   string  $id        The ID of the div element
	 *
	 * @return  string  HTML to start a new panel
	 *
	 * @since   3.0
	 * @deprecated  4.0 Use JHtml::_('bootstrap.addTab') instead.
	 */
	public static function addPanel($selector, $id)
	{
		$active = (static::$loaded['JHtmlBootstrap::startTabSet'][$selector]['active'] == $id) ? ' active' : '';

		return '<div id="' . $id . '" class="tab-pane' . $active . '">';
	}

	/**
	 * Close the current tab content panel
	 *
	 * @return  string  HTML to close the pane
	 *
	 * @since   3.0
	 * @deprecated  4.0 Use JHtml::_('bootstrap.endTab') instead.
	 */
	public static function endPanel()
	{
		return '</div>';
	}

	/**
	 * Loads CSS files needed by Bootstrap
	 *
	 * @param   boolean  $includeMainCss  If true, main bootstrap.css files are loaded
	 * @param   string   $direction       rtl or ltr direction. If empty, ltr is assumed
	 * @param   array    $attribs         Optional array of attributes to be passed to JHtml::_('stylesheet')
	 *
	 * @return  void
	 *
	 * @since   3.0
	 */
	public static function loadCss($includeMainCss = true, $direction = 'ltr', $attribs = array())
	{
		// Load Bootstrap main CSS
		if ($includeMainCss)
		{
			JHtml::_('stylesheet', 'jui/bootstrap.min.css', $attribs, true);
			JHtml::_('stylesheet', 'jui/bootstrap-responsive.min.css', $attribs, true);
			JHtml::_('stylesheet', 'jui/bootstrap-extended.css', $attribs, true);
		}

		// Load Bootstrap RTL CSS
		if ($direction === 'rtl')
		{
			JHtml::_('stylesheet', 'jui/bootstrap-rtl.css', $attribs, true);
		}
	}
  
	/**
	 * Internal method to get a JavaScript object notation string from an array
	 *
	 * @param   array  $array  The array to convert to JavaScript object notation
	 *
	 * @return  string  JavaScript object notation representation of the array
	 *
	 * @since   3.0
	 */
	public static function getJSObject(array $array = array())
	{
		$elements = array();

		foreach ($array as $k => $v)
		{
			// Don't encode either of these types
			if (is_null($v) || is_resource($v))
			{
				continue;
			}

			// Safely encode as a Javascript string
			$key = json_encode((string) $k);

			if (is_bool($v))
			{
				$elements[] = $key . ': ' . ($v ? 'true' : 'false');
			}
			elseif (is_numeric($v))
			{
				$elements[] = $key . ': ' . ($v + 0);
			}
			elseif (is_string($v))
			{
				if (strpos($v, '\\') === 0)
				{
					// Items such as functions and JSON objects are prefixed with \, strip the prefix and don't encode them
					$elements[] = $key . ': ' . substr($v, 1);
				}
				else
				{
					// The safest way to insert a string
					$elements[] = $key . ': ' . json_encode((string) $v);
				}
			}
			else
			{
				$elements[] = $key . ': ' . static::getJSObject(is_object($v) ? get_object_vars($v) : $v);
			}
		}

		return '{' . implode(',', $elements) . '}';
	}  
}
joomla25/html/string.php000060400000021735152455303030011163 0ustar00<?php
/**
 * @package     Joomla.Platform
 * @subpackage  HTML
 *
 * @copyright   Copyright (C) 2005 - 2014 Open Source Matters, Inc. All rights reserved.
 * @license     GNU General Public License version 2 or later; see LICENSE
 */

defined('JPATH_PLATFORM') or die;

/**
 * HTML helper class for rendering manipulated strings.
 *
 * @package     Joomla.Platform
 * @subpackage  HTML
 * @since       1.6
 */
abstract class JHtmlString
{
	/**
	 * Truncates text blocks over the specified character limit and closes
	 * all open HTML tags. The method will optionally not truncate an individual
	 * word, it will find the first space that is within the limit and
	 * truncate at that point. This method is UTF-8 safe.
	 *
	 * @param   string   $text       The text to truncate.
	 * @param   integer  $length     The maximum length of the text.
	 * @param   boolean  $noSplit    Don't split a word if that is where the cutoff occurs (default: true).
	 * @param   boolean  $allowHtml  Allow HTML tags in the output, and close any open tags (default: true).
	 *
	 * @return  string   The truncated text.
	 *
	 * @since   1.6
	 */
	public static function truncate($text, $length = 0, $noSplit = true, $allowHtml = true)
	{
		// Assume a lone open tag is invalid HTML.
		if ($length == 1 && substr($text, 0, 1) == '<')
		{
			return '...';
		}

		// Check if HTML tags are allowed.
		if (!$allowHtml)
		{
			// Deal with spacing issues in the input.
			$text = str_replace('>', '> ', $text);
			$text = str_replace(array('&nbsp;', '&#160;'), ' ', $text);
			$text = JString::trim(preg_replace('#\s+#mui', ' ', $text));

			// Strip the tags from the input and decode entities.
			$text = strip_tags($text);
			$text = html_entity_decode($text, ENT_QUOTES, 'UTF-8');

			// Remove remaining extra spaces.
			$text = str_replace('&nbsp;', ' ', $text);
			$text = JString::trim(preg_replace('#\s+#mui', ' ', $text));
		}

		// Whether or not allowing HTML, truncate the item text if it is too long.
		if ($length > 0 && JString::strlen($text) > $length)
		{
			$tmp = trim(JString::substr($text, 0, $length));

			if (substr($tmp, 0, 1) == '<' && strpos($tmp, '>') === false)
			{
				return '...';
			}

			// $noSplit true means that we do not allow splitting of words.
			if ($noSplit)
			{
				// Find the position of the last space within the allowed length.
				$offset = JString::strrpos($tmp, ' ');
				$tmp = JString::substr($tmp, 0, $offset + 1);

				// If there are no spaces and the string is longer than the maximum
				// we need to just use the ellipsis. In that case we are done.
				if ($offset === false && strlen($text) > $length)
				{
					return '...';
				}

				if (JString::strlen($tmp) > $length - 3)
				{
					$tmp = trim(JString::substr($tmp, 0, JString::strrpos($tmp, ' ')));
				}
			}

			if ($allowHtml)
			{
				// Put all opened tags into an array
				preg_match_all("#<([a-z][a-z0-9]*)\b.*?(?!/)>#i", $tmp, $result);
				$openedTags = $result[1];

				// Some tags self close so they do not need a separate close tag.
				$openedTags = array_diff($openedTags, array("img", "hr", "br"));
				$openedTags = array_values($openedTags);

				// Put all closed tags into an array
				preg_match_all("#</([a-z]+)>#iU", $tmp, $result);
				$closedTags = $result[1];

				$numOpened = count($openedTags);

				// All tags are closed so trim the text and finish.
				if (count($closedTags) == $numOpened)
				{
					return trim($tmp) . '...';
				}

				// Closing tags need to be in the reverse order of opening tags.
				$openedTags = array_reverse($openedTags);

				// Close tags
				for ($i = 0; $i < $numOpened; $i++)
				{
					if (!in_array($openedTags[$i], $closedTags))
					{
						$tmp .= "</" . $openedTags[$i] . ">";
					}
					else
					{
						unset($closedTags[array_search($openedTags[$i], $closedTags)]);
					}
				}
			}

			if ($tmp === false || strlen($text) > strlen($tmp))
			{
				$text = trim($tmp) . '...';
			}
		}

		// Clean up any internal spaces created by the processing.
		$text = str_replace(' </', '</', $text);
		$text = str_replace(' ...', '...', $text);

		return $text;
	}

	/**
	 * Method to extend the truncate method to more complex situations
	 *
	 * The goal is to get the proper length plain text string with as much of
	 * the html intact as possible with all tags properly closed.
	 *
	 * @param   string   $html       The content of the introtext to be truncated
	 * @param   integer  $maxLength  The maximum number of characters to render
	 * @param   boolean  $noSplit    Don't split a word if that is where the cutoff occurs (default: true).
	 *
	 * @return  string  The truncated string. If the string is truncated an ellipsis
	 *                  (...) will be appended.
	 *
	 * @note    If a maximum length of 3 or less is selected and the text has more than
	 *          that number of characters an ellipsis will be displayed.
	 *          This method will not create valid HTML from malformed HTML.
	 *
	 * @since   3.1
	 */
	public static function truncateComplex($html, $maxLength = 0, $noSplit = true)
	{
		// Start with some basic rules.
		$baseLength = strlen($html);

		// If the original HTML string is shorter than the $maxLength do nothing and return that.
		if ($baseLength <= $maxLength || $maxLength == 0)
		{
			return $html;
		}

		// Take care of short simple cases.
		if ($maxLength <= 3 && substr($html, 0, 1) != '<' && strpos(substr($html, 0, $maxLength - 1), '<') === false && $baseLength > $maxLength)
		{
			return '...';
		}

		// Deal with maximum length of 1 where the string starts with a tag.
		if ($maxLength == 1 && substr($html, 0, 1) == '<')
		{
			$endTagPos = strlen(strstr($html, '>', true));
			$tag = substr($html, 1, $endTagPos);

			$l = $endTagPos + 1;

			if ($noSplit)
			{
				return substr($html, 0, $l) . '</' . $tag . '...';
			}

			// TODO: $character doesn't seem to be used...
			$character = substr(strip_tags($html), 0, 1);

			return substr($html, 0, $l) . '</' . $tag . '...';
		}

		// First get the truncated plain text string. This is the rendered text we want to end up with.
		$ptString = JHtml::_('string.truncate', $html, $maxLength, $noSplit, $allowHtml = false);

		// It's all HTML, just return it.
		if (strlen($ptString) == 0)
		{
				return $html;
		}

		// If the plain text is shorter than the max length the variable will not end in ...
		// In that case we use the whole string.
		if (substr($ptString, -3) != '...')
		{
				return $html;
		}

		// Regular truncate gives us the ellipsis but we want to go back for text and tags.
		if ($ptString == '...')
		{
			$stripped = substr(strip_tags($html), 0, $maxLength);
			$ptString = JHtml::_('string.truncate', $stripped, $maxLength, $noSplit, $allowHtml = false);
		}

		// We need to trim the ellipsis that truncate adds.
		$ptString = rtrim($ptString, '.');

		// Now deal with more complex truncation.
		while ($maxLength <= $baseLength)
		{
			// Get the truncated string assuming HTML is allowed.
			$htmlString = JHtml::_('string.truncate', $html, $maxLength, $noSplit, $allowHtml = true);

			if ($htmlString == '...' && strlen($ptString) + 3 > $maxLength)
			{
				return $htmlString;
			}

			$htmlString = rtrim($htmlString, '.');

			// Now get the plain text from the HTML string and trim it.
			$htmlStringToPtString = JHtml::_('string.truncate', $htmlString, $maxLength, $noSplit, $allowHtml = false);
			$htmlStringToPtString = rtrim($htmlStringToPtString, '.');

			// If the new plain text string matches the original plain text string we are done.
			if ($ptString == $htmlStringToPtString)
			{
				return $htmlString . '...';
			}

			// Get the number of HTML tag characters in the first $maxLength characters
			$diffLength = strlen($ptString) - strlen($htmlStringToPtString);

			if ($diffLength <= 0)
			{
				return $htmlString . '...';
			}

			// Set new $maxlength that adjusts for the HTML tags
			$maxLength += $diffLength;
		}
	}

	/**
	 * Abridges text strings over the specified character limit. The
	 * behavior will insert an ellipsis into the text replacing a section
	 * of variable size to ensure the string does not exceed the defined
	 * maximum length. This method is UTF-8 safe.
	 *
	 * For example, it transforms "Really long title" to "Really...title".
	 *
	 * Note that this method does not scan for HTML tags so will potentially break them.
	 *
	 * @param   string   $text    The text to abridge.
	 * @param   integer  $length  The maximum length of the text (default is 50).
	 * @param   integer  $intro   The maximum length of the intro text (default is 30).
	 *
	 * @return  string   The abridged text.
	 *
	 * @since   1.6
	 */
	public static function abridge($text, $length = 50, $intro = 30)
	{
		// Abridge the item text if it is too long.
		if (JString::strlen($text) > $length)
		{
			// Determine the remaining text length.
			$remainder = $length - ($intro + 3);

			// Extract the beginning and ending text sections.
			$beg = JString::substr($text, 0, $intro);
			$end = JString::substr($text, JString::strlen($text) - $remainder);

			// Build the resulting string.
			$text = $beg . '...' . $end;
		}

		return $text;
	}
}
joomla25/html/jquery.php000060400000005717152455303030011176 0ustar00<?php
/**
 * @package     Joomla.Libraries
 * @subpackage  HTML
 *
 * @copyright   Copyright (C) 2005 - 2015 Open Source Matters, Inc. All rights reserved.
 * @license     GNU General Public License version 2 or later; see LICENSE
 */

defined('JPATH_PLATFORM') or die;

/**
 * Utility class for jQuery JavaScript behaviors
 *
 * @since  3.0
 */
abstract class JHtmlJquery
{
	/**
	 * @var    array  Array containing information for loaded files
	 * @since  3.0
	 */
	protected static $loaded = array();

	/**
	 * Method to load the jQuery JavaScript framework into the document head
	 *
	 * If debugging mode is on an uncompressed version of jQuery is included for easier debugging.
	 *
	 * @param   boolean  $noConflict  True to load jQuery in noConflict mode [optional]
	 * @param   mixed    $debug       Is debugging mode on? [optional]
	 * @param   boolean  $migrate     True to enable the jQuery Migrate plugin
	 *
	 * @return  void
	 *
	 * @since   3.0
	 */
	public static function framework($noConflict = true, $debug = null, $migrate = true)
	{
		// Only load once
		if (!empty(static::$loaded[__METHOD__]))
		{
			return;
		}

		// If no debugging value is set, use the configuration setting
		if ($debug === null)
		{
			$config = JFactory::getConfig();
			$debug  = (boolean) $config->get('debug');
		}

		JHtml::_('script', 'jui/jquery.min.js', false, true, false, false, $debug);

		// Check if we are loading in noConflict
		if ($noConflict)
		{
			JHtml::_('script', 'jui/jquery-noconflict.js', false, true, false, false, false);
		}

		// Check if we are loading Migrate
		if ($migrate)
		{
			JHtml::_('script', 'jui/jquery-migrate.min.js', false, true, false, false, $debug);
		}

		static::$loaded[__METHOD__] = true;

		return;
	}

	/**
	 * Method to load the jQuery UI JavaScript framework into the document head
	 *
	 * If debugging mode is on an uncompressed version of jQuery UI is included for easier debugging.
	 *
	 * @param   array  $components  The jQuery UI components to load [optional]
	 * @param   mixed  $debug       Is debugging mode on? [optional]
	 *
	 * @return  void
	 *
	 * @since   3.0
	 */
	public static function ui(array $components = array('core'), $debug = null)
	{
		// Set an array containing the supported jQuery UI components handled by this method
		$supported = array('core', 'sortable');

		// Include jQuery
		static::framework();

		// If no debugging value is set, use the configuration setting
		if ($debug === null)
		{
			$config = JFactory::getConfig();
			$debug  = (boolean) $config->get('debug');
		}

		// Load each of the requested components
		foreach ($components as $component)
		{
			// Only attempt to load the component if it's supported in core and hasn't already been loaded
			if (in_array($component, $supported) && empty(static::$loaded[__METHOD__][$component]))
			{
				JHtml::_('script', 'jui/jquery.ui.' . $component . '.min.js', false, true, false, false, $debug);
				static::$loaded[__METHOD__][$component] = true;
			}
		}

		return;
	}
}
joomla25/layout/file.php000060400000033350152455303030011141 0ustar00<?php
/**
 * @package     Joomla.Libraries
 * @subpackage  Layout
 *
 * @copyright   Copyright (C) 2005 - 2016 Open Source Matters, Inc. All rights reserved.
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('JPATH_PLATFORM') or die;

/**
 * Base class for rendering a display layout
 * loaded from from a layout file
 *
 * @see    https://docs.joomla.org/Sharing_layouts_across_views_or_extensions_with_JLayout
 * @since  3.0
 */
class JLayoutFile extends JLayoutBase
{
	/**
	 * Cached layout paths
	 *
	 * @var    array
	 * @since  3.5
	 */
	protected static $cache = array();

	/**
	 * Dot separated path to the layout file, relative to base path
	 *
	 * @var    string
	 * @since  3.0
	 */
	protected $layoutId = '';

	/**
	 * Base path to use when loading layout files
	 *
	 * @var    string
	 * @since  3.0
	 */
	protected $basePath = null;

	/**
	 * Full path to actual layout files, after possible template override check
	 *
	 * @var    string
	 * @since  3.0.3
	 */
	protected $fullPath = null;

	/**
	 * Paths to search for layouts
	 *
	 * @var    array
	 * @since  3.2
	 */
	protected $includePaths = array();

	/**
	 * Method to instantiate the file-based layout.
	 *
	 * @param   string  $layoutId  Dot separated path to the layout file, relative to base path
	 * @param   string  $basePath  Base path to use when loading layout files
	 * @param   mixed   $options   Optional custom options to load. Registry or array format [@since 3.2]
	 *
	 * @since   3.0
	 */
	public function __construct($layoutId, $basePath = null, $options = null)
	{
		// Initialise / Load options
		$this->setOptions($options);

		// Main properties
		$this->setLayoutId($layoutId);
		$this->basePath = $basePath;

		// Init Enviroment
		$this->setComponent($this->options->get('component', 'auto'));
		$this->setClient($this->options->get('client', 'auto'));
	}

	/**
	 * Method to render the layout.
	 *
	 * @param   array  $displayData  Array of properties available for use inside the layout file to build the displayed output
	 *
	 * @return  string  The necessary HTML to display the layout
	 *
	 * @since   3.0
	 */
	public function render($displayData = array())
	{
		$this->clearDebugMessages();

		// Inherit base output from parent class
		$layoutOutput = '';

		// Automatically merge any previously data set if $displayData is an array
		if (is_array($displayData))
		{
			$displayData = array_merge($this->data, $displayData);
		}

		// Check possible overrides, and build the full path to layout file
		$path = $this->getPath();

		if ($this->isDebugEnabled())
		{
			echo "<pre>" . $this->renderDebugMessages() . "</pre>";
		}

		// Nothing to show
		if (empty($path))
		{
			return $layoutOutput;
		}

		ob_start();
		include $path;
		$layoutOutput .= ob_get_contents();
		ob_end_clean();

		return $layoutOutput;
	}

	/**
	 * Method to finds the full real file path, checking possible overrides
	 *
	 * @return  string  The full path to the layout file
	 *
	 * @since   3.0
	 */
	protected function getPath()
	{
		JLoader::import('joomla.filesystem.path');

		$layoutId     = $this->getLayoutId();
		$includePaths = $this->getIncludePaths();
		$suffixes     = $this->getSuffixes();

		$this->addDebugMessage('<strong>Layout:</strong> ' . $this->layoutId);

		if (!$layoutId)
		{
			$this->addDebugMessage('<strong>There is no active layout</strong>');

			return null;
		}

		if (!$includePaths)
		{
			$this->addDebugMessage('<strong>There are no folders to search for layouts:</strong> ' . $layoutId);

			return null;
		}

		$hash = md5(
			json_encode(
				array(
					'paths'    => $includePaths,
					'suffixes' => $suffixes
				)
			)
		);

		if (!empty(static::$cache[$layoutId][$hash]))
		{
			$this->addDebugMessage('<strong>Cached path:</strong> ' . static::$cache[$layoutId][$hash]);

			return static::$cache[$layoutId][$hash];
		}

		$this->addDebugMessage('<strong>Include Paths:</strong> ' . print_r($includePaths, true));

		// Search for suffixed versions. Example: tags.j31.php
		if ($suffixes)
		{
			$this->addDebugMessage('<strong>Suffixes:</strong> ' . print_r($suffixes, true));

			foreach ($suffixes as $suffix)
			{
				$rawPath  = str_replace('.', '/', $this->layoutId) . '.' . $suffix . '.php';
				$this->addDebugMessage('<strong>Searching layout for:</strong> ' . $rawPath);

				if ($foundLayout = JPath::find($this->includePaths, $rawPath))
				{
					$this->addDebugMessage('<strong>Found layout:</strong> ' . $this->fullPath);

					static::$cache[$layoutId][$hash] = $foundLayout;

					return static::$cache[$layoutId][$hash];
				}
			}
		}

		// Standard version
		$rawPath  = str_replace('.', '/', $this->layoutId) . '.php';
		$this->addDebugMessage('<strong>Searching layout for:</strong> ' . $rawPath);

		$foundLayout = JPath::find($this->includePaths, $rawPath);

		if (!$foundLayout)
		{
			$this->addDebugMessage('<strong>Unable to find layout: </strong> ' . $layoutId);

			return null;
		}

		$this->addDebugMessage('<strong>Found layout:</strong> ' . $foundLayout);

		static::$cache[$layoutId][$hash] = $foundLayout;

		return static::$cache[$layoutId][$hash];
	}

	/**
	 * Add one path to include in layout search. Proxy of addIncludePaths()
	 *
	 * @param   string  $path  The path to search for layouts
	 *
	 * @return  self
	 *
	 * @since   3.2
	 */
	public function addIncludePath($path)
	{
		$this->addIncludePaths($path);

		return $this;
	}

	/**
	 * Add one or more paths to include in layout search
	 *
	 * @param   string  $paths  The path or array of paths to search for layouts
	 *
	 * @return  self
	 *
	 * @since   3.2
	 */
	public function addIncludePaths($paths)
	{
		if (empty($paths))
		{
			return $this;
		}

		$includePaths = $this->getIncludePaths();

		if (is_array($paths))
		{
			$includePaths = array_unique(array_merge($paths, $includePaths));
		}
		else
		{
			array_unshift($includePaths, $paths);
		}

		$this->setIncludePaths($includePaths);

		return $this;
	}

	/**
	 * Clear the include paths
	 *
	 * @return  self
	 *
	 * @since   3.5
	 */
	public function clearIncludePaths()
	{
		$this->includePaths = array();

		return $this;
	}

	/**
	 * Get the active include paths
	 *
	 * @return  array
	 *
	 * @since   3.5
	 */
	public function getIncludePaths()
	{
		if (empty($this->includePaths))
		{
			$this->includePaths = $this->getDefaultIncludePaths();
		}

		return $this->includePaths;
	}

	/**
	 * Get the active layout id
	 *
	 * @return  string
	 *
	 * @since   3.5
	 */
	public function getLayoutId()
	{
		return $this->layoutId;
	}

	/**
	 * Get the active suffixes
	 *
	 * @return  array
	 *
	 * @since   3.5
	 */
	public function getSuffixes()
	{
		return $this->getOptions()->get('suffixes', array());
	}

	/**
	 * Load the automatically generated language suffixes.
	 * Example: array('es-ES', 'es', 'ltr')
	 *
	 * @return  self
	 *
	 * @since   3.5
	 */
	public function loadLanguageSuffixes()
	{
		$lang = JFactory::getLanguage();

		$langTag = $lang->getTag();
		$langParts = explode('-', $langTag);

		$suffixes = array($langTag, $langParts[0]);
		$suffixes[] = $lang->isRTL() ? 'rtl' : 'ltr';

		$this->setSuffixes($suffixes);

		return $this;
	}

	/**
	 * Load the automatically generated version suffixes.
	 * Example: array('j311', 'j31', 'j3')
	 *
	 * @return  self
	 *
	 * @since   3.5
	 */
	public function loadVersionSuffixes()
	{
		$cmsVersion = new JVersion;

		// Example j311
		$fullVersion = 'j' . str_replace('.', '', $cmsVersion->getShortVersion());

		// Create suffixes like array('j311', 'j31', 'j3')
		$suffixes = array(
			$fullVersion,
			substr($fullVersion, 0, 3),
			substr($fullVersion, 0, 2),
		);

		$this->setSuffixes(array_unique($suffixes));

		return $this;
	}

	/**
	 * Remove one path from the layout search
	 *
	 * @param   string  $path  The path to remove from the layout search
	 *
	 * @return  self
	 *
	 * @since   3.2
	 */
	public function removeIncludePath($path)
	{
		$this->removeIncludePaths($path);

		return $this;
	}

	/**
	 * Remove one or more paths to exclude in layout search
	 *
	 * @param   string  $paths  The path or array of paths to remove for the layout search
	 *
	 * @return  self
	 *
	 * @since   3.2
	 */
	public function removeIncludePaths($paths)
	{
		if (!empty($paths))
		{
			$paths = (array) $paths;

			$this->includePaths = array_diff($this->includePaths, $paths);
		}

		return $this;
	}

	/**
	 * Validate that the active component is valid
	 *
	 * @param   string  $option  URL Option of the component. Example: com_content
	 *
	 * @return  boolean
	 *
	 * @since   3.2
	 */
	protected function validComponent($option = null)
	{
		// By default we will validate the active component
		$component = ($option !== null) ? $option : $this->options->get('component', null);

		// Valid option format
		if (!empty($component) && substr_count($component, 'com_'))
		{
			// Latest check: component exists and is enabled
			return JComponentHelper::isEnabled($component);
		}

		return false;
	}

	/**
	 * Method to change the component where search for layouts
	 *
	 * @param   string  $option  URL Option of the component. Example: com_content
	 *
	 * @return  mixed  Component option string | null for none
	 *
	 * @since   3.2
	 */
	public function setComponent($option)
	{
		$component = null;

		switch ((string) $option)
		{
			case 'none':
				$component = null;
				break;

			case 'auto':
				$component = JApplicationHelper::getComponentName();
				break;

			default:
				$component = $option;
				break;
		}

		// Extra checks
		if (!$this->validComponent($component))
		{
			$component = null;
		}

		$this->options->set('component', $component);

		// Refresh include paths
		$this->clearIncludePaths();
	}

	/**
	 * Function to initialise the application client
	 *
	 * @param   mixed  $client  Frontend: 'site' or 0 | Backend: 'admin' or 1
	 *
	 * @return  void
	 *
	 * @since   3.2
	 */
	public function setClient($client)
	{
		// Force string conversion to avoid unexpected states
		switch ((string) $client)
		{
			case 'site':
			case '0':
				$client = 0;
				break;

			case 'admin':
			case '1':
				$client = 1;
				break;

			default:
				$client = (int) T3::isAdmin();
				break;
		}

		$this->options->set('client', $client);

		// Refresh include paths
		$this->clearIncludePaths();
	}

	/**
	 * Change the layout
	 *
	 * @param   string  $layoutId  Layout to render
	 *
	 * @return  self
	 *
	 * @since   3.2
	 *
	 * @deprecated  3.5  Use setLayoutId()
	 */
	public function setLayout($layoutId)
	{
		// Log usage of deprecated function
		JLog::add(__METHOD__ . '() is deprecated, use JLayoutFile::setLayoutId() instead.', JLog::WARNING, 'deprecated');

		return $this->setLayoutId($layoutId);
	}

	/**
	 * Set the active layout id
	 *
	 * @param   string  $layoutId  Layout identifier
	 *
	 * @return  self
	 *
	 * @since   3.5
	 */
	public function setLayoutId($layoutId)
	{
		$this->layoutId = $layoutId;
		$this->fullPath = null;

		return $this;
	}

	/**
	 * Refresh the list of include paths
	 *
	 * @return  self
	 *
	 * @since   3.2
	 *
	 * @deprecated  3.5  Use JLayoutFile::clearIncludePaths()
	 */
	protected function refreshIncludePaths()
	{
		// Log usage of deprecated function
		JLog::add(__METHOD__ . '() is deprecated, use JLayoutFile::clearIncludePaths() instead.', JLog::WARNING, 'deprecated');

		$this->clearIncludePaths();

		return $this;
	}

	/**
	 * Get the default array of include paths
	 *
	 * @return  array
	 *
	 * @since   3.5
	 */
	public function getDefaultIncludePaths()
	{
		// Reset includePaths
		$paths = array();

		// (1 - highest priority) Received a custom high priority path
		if (!is_null($this->basePath))
		{
			$paths[] = rtrim($this->basePath, DIRECTORY_SEPARATOR);
		}

		// Component layouts & overrides if exist
		$component = $this->options->get('component', null);

		if (!empty($component))
		{
			// (2) Component template overrides path
			$paths[] = JPATH_THEMES . '/' . JFactory::getApplication()->getTemplate() . '/html/layouts/' . $component;

			// (3) Component path
			if ($this->options->get('client') == 0)
			{
				$paths[] = JPATH_SITE . '/components/' . $component . '/layouts';
			}
			else
			{
				$paths[] = JPATH_ADMINISTRATOR . '/components/' . $component . '/layouts';
			}
		}

		// (4.1) - user custom layout overridden
		if (!defined('T3_LOCAL_DISABLED')) $paths[] = T3_LOCAL_PATH . '/html/layouts';

		// (4) Standard Joomla! layouts overriden
		$paths[] = JPATH_THEMES . '/' . JFactory::getApplication()->getTemplate() . '/html/layouts';

		// (5.1) - T3 base layout overridden
		$paths[] = T3_PATH . '/html/layouts';

		// (5 - lower priority) Frontend base layouts
		$paths[] = JPATH_ROOT . '/layouts';

		return $paths;
	}

	/**
	 * Set the include paths to search for layouts
	 *
	 * @param   array  $paths  Array with paths to search in
	 *
	 * @return  self
	 *
	 * @since   3.5
	 */
	public function setIncludePaths($paths)
	{
		$this->includePaths = (array) $paths;

		return $this;
	}

	/**
	 * Set suffixes to search layouts
	 *
	 * @param   mixed  $suffixes  String with a single suffix or 'auto' | 'none' or array of suffixes
	 *
	 * @return  self
	 *
	 * @since   3.5
	 */
	public function setSuffixes(array $suffixes)
	{
		$this->options->set('suffixes', $suffixes);

		return $this;
	}

	/**
	 * Render a layout with the same include paths & options
	 *
	 * @param   object  $layoutId     Object which properties are used inside the layout file to build displayed output
	 * @param   mixed   $displayData  Data to be rendered
	 *
	 * @return  string  The necessary HTML to display the layout
	 *
	 * @since   3.2
	 */
	public function sublayout($layoutId, $displayData)
	{
		// Sublayouts are searched in a subfolder with the name of the current layout
		if (!empty($this->layoutId))
		{
			$layoutId = $this->layoutId . '.' . $layoutId;
		}

		$sublayout = new static($layoutId, $this->basePath, $this->options);
		$sublayout->includePaths = $this->includePaths;

		return $sublayout->render($displayData);
	}
}
joomla25/layout/base.php000060400000012316152455303030011133 0ustar00<?php
/**
 * @package     Joomla.Libraries
 * @subpackage  Layout
 *
 * @copyright   Copyright (C) 2005 - 2016 Open Source Matters, Inc. All rights reserved.
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('JPATH_PLATFORM') or die;

use Joomla\Registry\Registry;

/**
 * Base class for rendering a display layout
 *
 * @see    https://docs.joomla.org/Sharing_layouts_across_views_or_extensions_with_JLayout
 * @since  3.0
 */
class JLayoutBase implements JLayout
{
	/**
	 * Options object
	 *
	 * @var    Registry
	 * @since  3.2
	 */
	protected $options = null;

	/**
	 * Data for the layout
	 *
	 * @var    array
	 * @since  3.5
	 */
	protected $data = array();

	/**
	 * Debug information messages
	 *
	 * @var    array
	 * @since  3.2
	 */
	protected $debugMessages = array();

	/**
	 * Set the options
	 *
	 * @param   array|Registry  $options  Array / Registry object with the options to load
	 *
	 * @return  JLayoutBase  Instance of $this to allow chaining.
	 *
	 * @since   3.2
	 */
	public function setOptions($options = null)
	{
		// Received Registry
		if ($options instanceof Registry)
		{
			$this->options = $options;
		}
		// Received array
		elseif (is_array($options))
		{
			$this->options = new Registry($options);
		}
		else
		{
			$this->options = new Registry;
		}

		return $this;
	}

	/**
	 * Get the options
	 *
	 * @return  Registry  Object with the options
	 *
	 * @since   3.2
	 */
	public function getOptions()
	{
		// Always return a Registry instance
		if (!($this->options instanceof Registry))
		{
			$this->resetOptions();
		}

		return $this->options;
	}

	/**
	 * Function to empty all the options
	 *
	 * @return  JLayoutBase  Instance of $this to allow chaining.
	 *
	 * @since   3.2
	 */
	public function resetOptions()
	{
		return $this->setOptions(null);
	}

	/**
	 * Method to escape output.
	 *
	 * @param   string  $output  The output to escape.
	 *
	 * @return  string  The escaped output.
	 *
	 * @since   3.0
	 */
	public function escape($output)
	{
		return htmlspecialchars($output, ENT_COMPAT, 'UTF-8');
	}

	/**
	 * Get the debug messages array
	 *
	 * @return  array
	 *
	 * @since   3.2
	 */
	public function getDebugMessages()
	{
		return $this->debugMessages;
	}

	/**
	 * Method to render the layout.
	 *
	 * @param   array  $displayData  Array of properties available for use inside the layout file to build the displayed output
	 *
	 * @return  string  The necessary HTML to display the layout
	 *
	 * @since   3.0
	 */
	public function render($displayData)
	{
		// Automatically merge any previously data set if $displayData is an array
		if (is_array($displayData))
		{
			$displayData = array_merge($this->data, $displayData);
		}

		return '';
	}

	/**
	 * Render the list of debug messages
	 *
	 * @return  string  Output text/HTML code
	 *
	 * @since   3.2
	 */
	public function renderDebugMessages()
	{
		return implode($this->debugMessages, "\n");
	}

	/**
	 * Add a debug message to the debug messages array
	 *
	 * @param   string  $message  Message to save
	 *
	 * @return  self
	 *
	 * @since   3.2
	 */
	public function addDebugMessage($message)
	{
		$this->debugMessages[] = $message;

		return $this;
	}

	/**
	 * Clear the debug messages array
	 *
	 * @return  self
	 *
	 * @since   3.5
	 */
	public function clearDebugMessages()
	{
		$this->debugMessages = array();

		return $this;
	}

	/**
	 * Render a layout with debug info
	 *
	 * @param   mixed  $data  Data passed to the layout
	 *
	 * @return  string
	 *
	 * @since    3.5
	 */
	public function debug($data = array())
	{
		$this->setDebug(true);

		$output = $this->render($data);

		$this->setDebug(false);

		return $output;
	}

	/**
	 * Method to get the value from the data array
	 *
	 * @param   string  $key           Key to search for in the data array
	 * @param   mixed   $defaultValue  Default value to return if the key is not set
	 *
	 * @return  mixed   Value from the data array | defaultValue if doesn't exist
	 *
	 * @since   3.5
	 */
	public function get($key, $defaultValue = null)
	{
		return isset($this->data[$key]) ? $this->data[$key] : $defaultValue;
	}

	/**
	 * Get the data being rendered
	 *
	 * @return  array
	 *
	 * @since   3.5
	 */
	public function getData()
	{
		return $this->data;
	}

	/**
	 * Check if debug mode is enabled
	 *
	 * @return  boolean
	 *
	 * @since   3.5
	 */
	public function isDebugEnabled()
	{
		return $this->getOptions()->get('debug', false) === true;
	}

	/**
	 * Method to set a value in the data array. Example: $layout->set('items', $items);
	 *
	 * @param   string  $key    Key for the data array
	 * @param   mixed   $value  Value to assign to the key
	 *
	 * @return  self
	 *
	 * @since   3.5
	 */
	public function set($key, $value)
	{
		$this->data[(string) $key] = $value;

		return $this;
	}

	/**
	 * Set the the data passed the layout
	 *
	 * @param   array  $data  Array with the data for the layout
	 *
	 * @return  self
	 *
	 * @since   3.5
	 */
	public function setData(array $data)
	{
		$this->data = $data;

		return $this;
	}

	/**
	 * Change the debug mode
	 *
	 * @param   boolean  $debug  Enable / Disable debug
	 *
	 * @return  self
	 *
	 * @since   3.5
	 */
	public function setDebug($debug)
	{
		$this->options->set('debug', (boolean) $debug);

		return $this;
	}
}
joomla25/layout/helper.php000060400000005022152455303030011474 0ustar00<?php
/**
 * @package     Joomla.Libraries
 * @subpackage  Layout
 *
 * @copyright   Copyright (C) 2005 - 2016 Open Source Matters, Inc. All rights reserved.
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('JPATH_PLATFORM') or die;

/**
 * Helper to render a JLayout object, storing a base path
 *
 * @see    https://docs.joomla.org/Sharing_layouts_across_views_or_extensions_with_JLayout
 * @since  3.1
 */
class JLayoutHelper
{
	/**
	 * A default base path that will be used if none is provided when calling the render method.
	 * Note that JLayoutFile itself will defaults to JPATH_ROOT . '/layouts' if no basePath is supplied at all
	 *
	 * @var    string
	 * @since  3.1
	 */
	public static $defaultBasePath = '';

	/**
	 * Method to render a layout with debug info
	 *
	 * @param   string  $layoutFile   Dot separated path to the layout file, relative to base path
	 * @param   object  $displayData  Object which properties are used inside the layout file to build displayed output
	 * @param   string  $basePath     Base path to use when loading layout files
	 * @param   mixed   $options      Optional custom options to load. Registry or array format
	 *
	 * @return  string
	 *
	 * @since   3.5
	 */
	public static function debug($layoutFile, $displayData = null, $basePath = '', $options = null)
	{
		$basePath = empty($basePath) ? self::$defaultBasePath : $basePath;

		// Make sure we send null to JLayoutFile if no path set
		$basePath = empty($basePath) ? null : $basePath;
		$layout = new JLayoutFile($layoutFile, $basePath, $options);
		$renderedLayout = $layout->debug($displayData);

		return $renderedLayout;
	}

	/**
	 * Method to render the layout.
	 *
	 * @param   string  $layoutFile   Dot separated path to the layout file, relative to base path
	 * @param   object  $displayData  Object which properties are used inside the layout file to build displayed output
	 * @param   string  $basePath     Base path to use when loading layout files
	 * @param   mixed   $options      Optional custom options to load. Registry or array format
	 *
	 * @return  string
	 *
	 * @since   3.1
	 */
	public static function render($layoutFile, $displayData = null, $basePath = '', $options = null)
	{
		$basePath = empty($basePath) ? self::$defaultBasePath : $basePath;

		// Make sure we send null to JLayoutFile if no path set
		$basePath = empty($basePath) ? null : $basePath;
		$layout = new JLayoutFile($layoutFile, $basePath, $options);
		$renderedLayout = $layout->render($displayData);

		return $renderedLayout;
	}
}
joomla25/layout/layout.php000060400000001640152455303030011534 0ustar00<?php
/**
 * @package     Joomla.Libraries
 * @subpackage  Layout
 *
 * @copyright   Copyright (C) 2005 - 2016 Open Source Matters, Inc. All rights reserved.
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('JPATH_PLATFORM') or die;

/**
 * Interface to handle display layout
 *
 * @see    https://docs.joomla.org/Sharing_layouts_across_views_or_extensions_with_JLayout
 * @since  3.0
 */
interface JLayout
{
	/**
	 * Method to escape output.
	 *
	 * @param   string  $output  The output to escape.
	 *
	 * @return  string  The escaped output.
	 *
	 * @since   3.0
	 */
	public function escape($output);

	/**
	 * Method to render the layout.
	 *
	 * @param   array  $displayData  Array of properties available for use inside the layout file to build the displayed output
	 *
	 * @return  string  The rendered layout.
	 *
	 * @since   3.0
	 */
	public function render($displayData);
}
joomla25/layout/index.html000060400000000037152455303030011502 0ustar00<!DOCTYPE html><title></title>
joomla25/modulehelper.php000060400000042363152455303030011376 0ustar00<?php
/**
 * @package         Advanced Module Manager
 * @version         3.3.0a
 *
 * @author          Peter van Westen <peter@nonumber.nl>
 * @link            http://www.nonumber.nl
 * @copyright       Copyright � 2011 All Rights Reserved
 *                  Brandon IT Consulting (http://www.metamodpro.com)
 *                  NoNumber (http://www.nonumber.nl)
 *                  JoomlArt (http://www.joomlart.com)
 * @license         http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
 */

/**
 * BASE ON JOOMLA CORE FILE:
 * /libraries/joomla/application/module/helper.php
 */

/**
 * @package     Joomla.Platform
 * @subpackage  Application
 *
 * @copyright   Copyright (C) 2005 - 2012 Open Source Matters, Inc. All rights reserved.
 * @license     GNU General Public License version 2 or later; see LICENSE
 */

defined('JPATH_PLATFORM') or defined('JPATH_BASE') or die;

jimport('joomla.application.component.helper');

/**
 * Module helper class
 *
 * @package     Joomla.Platform
 * @subpackage  Application
 * @since       11.1
 */
abstract class JModuleHelper
{
	/**
	 * Get module by name (real, eg 'Breadcrumbs' or folder, eg 'mod_breadcrumbs')
	 *
	 * @param   string  $name   The name of the module
	 * @param   string  $title  The title of the module, optional
	 *
	 * @return  object  The Module object
	 *
	 * @since   11.1
	 */
	public static function &getModule($name, $title = null)
	{
		$result = null;
		$modules =& JModuleHelper::_load();
		$total = count($modules);

		for ($i = 0; $i < $total; $i++)
		{
			// Match the name of the module
			if ($modules[$i]->name == $name || $modules[$i]->module == $name)
			{
				// Match the title if we're looking for a specific instance of the module
				if (!$title || $modules[$i]->title == $title)
				{
					// Found it
					$result = &$modules[$i];
					break; // Found it
				}
			}
		}

		// If we didn't find it, and the name is mod_something, create a dummy object
		if (is_null($result) && substr($name, 0, 4) == 'mod_')
		{
			$result            = new stdClass;
			$result->id        = 0;
			$result->title     = '';
			$result->module    = $name;
			$result->position  = '';
			$result->content   = '';
			$result->showtitle = 0;
			$result->control   = '';
			$result->params    = '';
			$result->user      = 0;
		}

		return $result;
	}

	/**
	 * Get modules by position
	 *
	 * @param   string  $position  The position of the module
	 *
	 * @return  array  An array of module objects
	 *
	 * @since   11.1
	 */
	public static function &getModules($position)
	{
		$position = strtolower($position);
		$result = array();

		$modules =& JModuleHelper::_load();

		$total = count($modules);
		for ($i = 0; $i < $total; $i++)
		{
			if ($modules[$i]->position == $position)
			{
				$result[] = &$modules[$i];
			}
		}

		if (count($result) == 0)
		{
			if (JRequest::getBool('tp') && JComponentHelper::getParams('com_templates')->get('template_positions_display'))
			{
				$result[0] = JModuleHelper::getModule('mod_' . $position);
				$result[0]->title = $position;
				$result[0]->content = $position;
				$result[0]->position = $position;
			}
		}

		return $result;
	}

	/**
	 * Checks if a module is enabled
	 *
	 * @param   string  $module  The module name
	 *
	 * @return  boolean
	 *
	 * @since   11.1
	 */
	public static function isEnabled($module)
	{
		$result = JModuleHelper::getModule($module);

		return !is_null($result);
	}

	/**
	 * Render the module.
	 *
	 * @param   object  $module   A module object.
	 * @param   array   $attribs  An array of attributes for the module (probably from the XML).
	 *
	 * @return  string  The HTML content of the module output.
	 *
	 * @since   11.1
	 */
	public static function renderModule($module, $attribs = array())
	{
		static $chrome;

		if (constant('JDEBUG'))
		{
			JProfiler::getInstance('Application')->mark('beforeRenderModule ' . $module->module . ' (' . $module->title . ')');
		}

		$app = JFactory::getApplication();

		// Record the scope.
		$scope = $app->scope;

		// Set scope to component name
		$app->scope = $module->module;

		// Get module parameters
		$params = new JRegistry;
		$params->loadString($module->params);

		// Get module path
		$module->module = preg_replace('/[^A-Z0-9_\.-]/i', '', $module->module);
		$path = JPATH_BASE . '/modules/' . $module->module . '/' . $module->module . '.php';

		// Load the module
		// $module->user is a check for 1.0 custom modules and is deprecated refactoring
		if (empty($module->user) && file_exists($path))
		{
			$lang = JFactory::getLanguage();
			// 1.5 or Core then 1.6 3PD
			$lang->load($module->module, JPATH_BASE, null, false, false) ||
				$lang->load($module->module, dirname($path), null, false, false) ||
				$lang->load($module->module, JPATH_BASE, $lang->getDefault(), false, false) ||
				$lang->load($module->module, dirname($path), $lang->getDefault(), false, false);

			$content = '';
			ob_start();
			include $path;
			$module->content = ob_get_contents() . $content;
			ob_end_clean();
		}

		// Load the module chrome functions
		if (!$chrome)
		{
			$chrome = array();
		}

		include_once JPATH_THEMES . '/system/html/modules.php';
		$chromePath = JPATH_THEMES . '/' . $app->getTemplate() . '/html/modules.php';

		if (!isset($chrome[$chromePath]))
		{
			if (file_exists($chromePath))
			{
				include_once $chromePath;
			}

			$chrome[$chromePath] = true;
		}

		// Make sure a style is set
		if (!isset($attribs['style']))
		{
			$attribs['style'] = 'none';
		}

		// Dynamically add outline style
		if (JRequest::getBool('tp') && JComponentHelper::getParams('com_templates')->get('template_positions_display'))
		{
			$attribs['style'] .= ' outline';
		}

		// Do 3rd party stuff to manipulate module content
		// onRenderModule is allowed to alter the $module, $attribs
		// and may return a boolean.
		// true=remove, any other value = keep.
		// $result holds an array of booleans, 1 from each plugin.
		// we ditch the module if any of them = true.
		$result = $app->triggerEvent( 'onRenderModule', array( &$module, &$attribs ) );
		if (!is_array($result)) {
			$result = array($result);
		}
		if ( array_search( true, $result, true ) !== false )
		{
			return '';
		}

		foreach (explode(' ', $attribs['style']) as $style)
		{
			$chromeMethod = 'modChrome_' . $style;

			// Apply chrome and render module
			if (function_exists($chromeMethod))
			{
				$module->style = $attribs['style'];

				ob_start();
				$chromeMethod($module, $params, $attribs);
				$module->content = ob_get_contents();
				ob_end_clean();
			}
		}

		//revert the scope
		$app->scope = $scope;

		if (constant('JDEBUG'))
		{
			JProfiler::getInstance('Application')->mark('afterRenderModule ' . $module->module . ' (' . $module->title . ')');
		}

		return $module->content;
	}

	/**
	 * Get the path to a layout for a module
	 *
	 * @param   string  $module  The name of the module
	 * @param   string  $layout  The name of the module layout. If alternative layout, in the form template:filename.
	 *
	 * @return  string  The path to the module layout
	 *
	 * @since   11.1
	 */
	public static function getLayoutPath($module, $layout = 'default')
	{
		$template = JFactory::getApplication()->getTemplate();
		$defaultLayout = $layout;

		if (strpos($layout, ':') !== false)
		{
			// Get the template and file name from the string
			$temp = explode(':', $layout);
			$template = ($temp[0] == '_') ? $template : $temp[0];
			$layout = $temp[1];
			$defaultLayout = ($temp[1]) ? $temp[1] : 'default';
		}

		// Build the template and base path for the layout
		$tPath = JPATH_THEMES . '/' . $template . '/html/' . $module . '/' . $layout . '.php';
		$bPath = JPATH_BASE . '/modules/' . $module . '/tmpl/' . $defaultLayout . '.php';
		$dPath = JPATH_BASE . '/modules/' . $module . '/tmpl/default.php';

		// Do 3rd party stuff to detect layout path for the module
		// onGetLayoutPath should return the path to the $layout of $module or false
		// $results holds an array of results returned from plugins, 1 from each plugin.
		// if a path to the $layout is found and it is a file, return that path
		$app	= JFactory::getApplication();
		$result = $app->triggerEvent( 'onGetLayoutPath', array( $module, $layout ) );
		if (is_array($result))
		{
			foreach ($result as $path)
			{
				if ($path !== false && is_file ($path))
				{
					return $path;
				}
			}
		}

		// If the template has a layout override use it
		if (file_exists($tPath))
		{
			return $tPath;
		}
		elseif (file_exists($bPath))
		{
			return $bPath;
		}
		else
		{
			return $dPath;
		}
	}

	/**
	 * Load published modules.
	 *
	 * @return  array
	 *
	 * @since   11.1
	 */
	protected static function &_load()
	{
		static $clean;

		if (isset($clean))
		{
			return $clean;
		}

		$Itemid = JRequest::getInt('Itemid');
		$app = JFactory::getApplication();
		$user = JFactory::getUser();
		$groups = implode(',', $user->getAuthorisedViewLevels());
		$lang = JFactory::getLanguage()->getTag();
		$clientId = (int) $app->getClientId();

		/*
		$cache = JFactory::getCache('com_modules', '');
		$cacheid = md5(serialize(array($Itemid, $groups, $clientId, $lang)));

		if (!($clean = $cache->get($cacheid)))
		{
		*/
			$db = JFactory::getDbo();

			$query = new stdClass;
			$query->select = array();
			$query->from = array();
			$query->join = array();
			$query->where = array();
			$query->order = array();

			$query->select[] = 'm.published, m.id, m.title, m.module, m.position, m.content, m.showtitle, m.params, mm.menuid';
			$query->from[] = '#__modules AS m';
			$query->join[] = '#__modules_menu AS mm ON mm.moduleid = m.id';
			$query->where[] = 'm.published = 1';

			$query->join[] = '#__extensions AS e ON e.element = m.module AND e.client_id = m.client_id';
			$query->where[] = 'e.enabled = 1';

			$date = JFactory::getDate();
			$now = $date->toSql();
			$nullDate = $db->getNullDate();
			$query->where[] = '(m.publish_up = ' . $db->q($nullDate) . ' OR m.publish_up <= ' . $db->q($now) . ')';
			$query->where[] = '(m.publish_down = ' . $db->q($nullDate) . ' OR m.publish_down >= ' . $db->q($now) . ')';

			$query->where[] = 'm.access IN ('.$groups.')';
			$query->where[] = 'm.client_id = ' . $clientId;
			$query->where[] = '(mm.menuid = ' . (int) $Itemid . ' OR mm.menuid <= 0)';

			// Filter by language
			if ($app->isClient('site') && $app->getLanguageFilter())
			{
				$query->where[] = 'm.language IN (' . $db->q($lang) . ',' . $db->q('*') . ')';
			}

			$query->order[] = 'm.position, m.ordering';

			// Do 3rd party stuff to change query
			$app->triggerEvent( 'onCreateModuleQuery', array( &$query ) );

			$q = $db->getQuery(true);
			// convert array object to query object
			foreach ( $query as $type => $strings )
			{
				foreach ( $strings as $string )
				{
					if ( $type == 'join' )
					{
						$q->{$type}( 'LEFT', $string );
					}
					else
					{
						$q->{$type}( $string );
					}
				}
			}

			// Set the query
			$db->setQuery($q);
			$modules = $db->loadObjectList();
			$clean = array();

			if ($db->getErrorNum())
			{
				JError::raiseWarning(500, JText::sprintf('JLIB_APPLICATION_ERROR_MODULE_LOAD', $db->getErrorMsg()));
				return $clean;
			}

			// Apply negative selections and eliminate duplicates
			$negId = $Itemid ? -(int) $Itemid : false;
			$dupes = array();
			for ($i = 0, $n = count($modules); $i < $n; $i++)
			{
				$module = &$modules[$i];

				// The module is excluded if there is an explicit prohibition
				$negHit = ($negId === (int) $module->menuid);

				if (isset($dupes[$module->id]))
				{
					// If this item has been excluded, keep the duplicate flag set,
					// but remove any item from the cleaned array.
					if ($negHit)
					{
						unset($clean[$module->id]);
					}
					continue;
				}

				$dupes[$module->id] = true;

				// Only accept modules without explicit exclusions.
				if (!$negHit)
				{
					// Determine if this is a 1.0 style custom module (no mod_ prefix)
					// This should be eliminated when the class is refactored.
					// $module->user is deprecated.
					$file = $module->module;
					$custom = substr($file, 0, 4) == 'mod_' ?  0 : 1;
					$module->user = $custom;
					// 1.0 style custom module name is given by the title field, otherwise strip off "mod_"
					$module->name = $custom ? $module->module : substr($file, 4);
					$module->style = null;
					$module->position = strtolower($module->position);
					$clean[$module->id] = $module;
				}
			}

			unset($dupes);

			// Do 3rd party stuff to manipulate module array.
			// Any plugins using this architecture may make alterations to the referenced $modules array.
			// To remove items you can do unset($modules[n]) or $modules[n]->published = false.

			// "onPrepareModuleList" may alter or add $modules, and does not need to return anything.
			// This should be used for module addition/deletion that the user would expect to happen at an
			// early stage.
			$app->triggerEvent( 'onPrepareModuleList', array( &$clean ) );

			// "onAlterModuleList" may alter or add $modules, and does not need to return anything.
			$app->triggerEvent( 'onAlterModuleList', array( &$clean ) );

			// "onPostProcessModuleList" allows a plugin to perform actions like parameter changes
			// on the completed list of modules and is guaranteed to occur *after*
			// the earlier plugins.
			$app->triggerEvent( 'onPostProcessModuleList', array( &$clean ) );

			// Remove any that were marked as disabled during the preceding steps
			foreach ( $clean as $id => $module )
			{
				if ( !isset( $module->published ) || $module->published == 0 )
				{
					unset( $clean[$id] );
				}
			}


			// Return to simple indexing that matches the query order.
			$clean = array_values($clean);

			/*
			$cache->store($clean, $cacheid);
		}
		*/

		return $clean;
	}

	/**
	 * Module cache helper
	 *
	 * Caching modes:
	 * To be set in XML:
	 * 'static'      One cache file for all pages with the same module parameters
	 * 'oldstatic'   1.5 definition of module caching, one cache file for all pages
	 * with the same module id and user aid,
	 * 'itemid'      Changes on itemid change, to be called from inside the module:
	 * 'safeuri'     Id created from $cacheparams->modeparams array,
	 * 'id'          Module sets own cache id's
	 *
	 * @param   object  $module        Module object
	 * @param   object  $moduleparams  Module parameters
	 * @param   object  $cacheparams   Module cache parameters - id or url parameters, depending on the module cache mode
	 *
	 * @return  string
	 *
	 * @since   11.1
	 *
	 * @link JFilterInput::clean()
	 */
	public static function moduleCache($module, $moduleparams, $cacheparams)
	{
		if (!isset($cacheparams->modeparams))
		{
			$cacheparams->modeparams = null;
		}
		
		// Add module ID to fix problem of cache for modules with the same type
		if ($cacheparams->modeparams && is_string($cacheparams->modeparams)) {
			$cacheparams->modeparams .= ":".$module->id;
		}

		if (!isset($cacheparams->cachegroup))
		{
			$cacheparams->cachegroup = $module->module;
		}

		$user = JFactory::getUser();
		$cache = JFactory::getCache($cacheparams->cachegroup, 'callback');
		$conf = JFactory::getConfig();

		// Turn cache off for internal callers if parameters are set to off and for all logged in users
		if ($moduleparams->get('owncache', null) === '0' || $conf->get('caching') == 0 || $user->get('id'))
		{
			$cache->setCaching(false);
		}

		// module cache is set in seconds, global cache in minutes, setLifeTime works in minutes
		$cache->setLifeTime($moduleparams->get('cache_time', $conf->get('cachetime') * 60) / 60);

		$wrkaroundoptions = array('nopathway' => 1, 'nohead' => 0, 'nomodules' => 1, 'modulemode' => 1, 'mergehead' => 1);

		$wrkarounds = true;
		$view_levels = md5(serialize($user->getAuthorisedViewLevels()));

		switch ($cacheparams->cachemode)
		{
			case 'id':
				$ret = $cache->get(
					array($cacheparams->class, $cacheparams->method),
					$cacheparams->methodparams,
					$cacheparams->modeparams,
					$wrkarounds,
					$wrkaroundoptions
				);
				break;

			case 'safeuri':
				$secureid = null;
				if (is_array($cacheparams->modeparams))
				{
					$uri = JRequest::get();
					$safeuri = new stdClass;
					foreach ($cacheparams->modeparams as $key => $value)
					{
						// Use int filter for id/catid to clean out spamy slugs
						if (isset($uri[$key]))
						{
							$safeuri->$key = JRequest::_cleanVar($uri[$key], 0, $value);
						}
					}
				}
				$secureid = md5(serialize(array($safeuri, $cacheparams->method, $moduleparams)));
				$ret = $cache->get(
					array($cacheparams->class, $cacheparams->method),
					$cacheparams->methodparams,
					$module->id . $view_levels . $secureid,
					$wrkarounds,
					$wrkaroundoptions
				);
				break;

			case 'static':
				$ret = $cache->get(
					array($cacheparams->class,
						$cacheparams->method),
					$cacheparams->methodparams,
					$module->module . md5(serialize($cacheparams->methodparams)),
					$wrkarounds,
					$wrkaroundoptions
				);
				break;

			case 'oldstatic': // provided for backward compatibility, not really usefull
				$ret = $cache->get(
					array($cacheparams->class, $cacheparams->method),
					$cacheparams->methodparams,
					$module->id . $view_levels,
					$wrkarounds,
					$wrkaroundoptions
				);
				break;

			case 'itemid':
			default:
				$ret = $cache->get(
					array($cacheparams->class, $cacheparams->method),
					$cacheparams->methodparams,
					$module->id . $view_levels . JRequest::getVar('Itemid', null, 'default', 'INT'),
					$wrkarounds,
					$wrkaroundoptions
				);
				break;
		}

		return $ret;
	}
}
joomla25/view.php000060400000044321152455303030007657 0ustar00<?php
/**
 * @package     Joomla.Platform
 * @subpackage  Application
 *
 * @copyright   Copyright (C) 2005 - 2012 Open Source Matters, Inc. All rights reserved.
 * @license     GNU General Public License version 2 or later; see LICENSE
 */

defined('JPATH_PLATFORM') or die;

/**
 * Base class for a Joomla View
 *
 * Class holding methods for displaying presentation data.
 *
 * @package     Joomla.Platform
 * @subpackage  Application
 * @since       11.1
 */
class JView extends JObject
{
	/**
	 * The name of the view
	 *
	 * @var    array
	 */
	protected $_name = null;

	/**
	 * Registered models
	 *
	 * @var    array
	 */
	protected $_models = array();

	/**
	 * The base path of the view
	 *
	 * @var    string
	 */
	protected $_basePath = null;

	/**
	 * The default model
	 *
	 * @var	string
	 */
	protected $_defaultModel = null;

	/**
	 * Layout name
	 *
	 * @var    string
	 */
	protected $_layout = 'default';

	/**
	 * Layout extension
	 *
	 * @var    string
	 */
	protected $_layoutExt = 'php';

	/**
	 * Layout template
	 *
	 * @var    string
	 */
	protected $_layoutTemplate = '_';

	/**
	 * The set of search directories for resources (templates)
	 *
	 * @var array
	 */
	protected $_path = array('template' => array(), 'helper' => array());

	/**
	 * The name of the default template source file.
	 *
	 * @var string
	 */
	protected $_template = null;

	/**
	 * The output of the template script.
	 *
	 * @var string
	 */
	protected $_output = null;

	/**
	 * Callback for escaping.
	 *
	 * @var string
	 */
	protected $_escape = 'htmlspecialchars';

	/**
	 * Charset to use in escaping mechanisms; defaults to urf8 (UTF-8)
	 *
	 * @var string
	 */
	protected $_charset = 'UTF-8';

	/**
	 * Constructor
	 *
	 * @param   array  $config  A named configuration array for object construction.<br/>
	 *                          name: the name (optional) of the view (defaults to the view class name suffix).<br/>
	 *                          charset: the character set to use for display<br/>
	 *                          escape: the name (optional) of the function to use for escaping strings<br/>
	 *                          base_path: the parent path (optional) of the views directory (defaults to the component folder)<br/>
	 *                          template_plath: the path (optional) of the layout directory (defaults to base_path + /views/ + view name<br/>
	 *                          helper_path: the path (optional) of the helper files (defaults to base_path + /helpers/)<br/>
	 *                          layout: the layout (optional) to use to display the view<br/>
	 *
	 * @since   11.1
	 */
	public function __construct($config = array())
	{
		// Set the view name
		if (empty($this->_name))
		{
			if (array_key_exists('name', $config))
			{
				$this->_name = $config['name'];
			}
			else
			{
				$this->_name = $this->getName();
			}
		}

		// Set the charset (used by the variable escaping functions)
		if (array_key_exists('charset', $config))
		{
			$this->_charset = $config['charset'];
		}

		// User-defined escaping callback
		if (array_key_exists('escape', $config))
		{
			$this->setEscape($config['escape']);
		}

		// Set a base path for use by the view
		if (array_key_exists('base_path', $config))
		{
			$this->_basePath = $config['base_path'];
		}
		else
		{
			$this->_basePath = JPATH_COMPONENT;
		}

		// Set the default template search path
		if (array_key_exists('template_path', $config))
		{
			// User-defined dirs
			$this->_setPath('template', $config['template_path']);
		}
		else
		{
			$this->_setPath('template', $this->_basePath . '/views/' . $this->getName() . '/tmpl');
		}

		// Set the default helper search path
		if (array_key_exists('helper_path', $config))
		{
			// User-defined dirs
			$this->_setPath('helper', $config['helper_path']);
		}
		else
		{
			$this->_setPath('helper', $this->_basePath . '/helpers');
		}

		// Set the layout
		if (array_key_exists('layout', $config))
		{
			$this->setLayout($config['layout']);
		}
		else
		{
			$this->setLayout('default');
		}

		$this->baseurl = JURI::base(true);
	}

	/**
	 * Execute and display a template script.
	 *
	 * @param   string  $tpl  The name of the template file to parse; automatically searches through the template paths.
	 *
	 * @return  mixed  A string if successful, otherwise a JError object.
	 *
	 * @see     fetch()
	 * @since   11.1
	 */
	public function display($tpl = null)
	{
		$result = $this->loadTemplate($tpl);
		if ($result instanceof Exception)
		{
			return $result;
		}

		echo $result;
	}

	/**
	 * Assigns variables to the view script via differing strategies.
	 *
	 * This method is overloaded; you can assign all the properties of
	 * an object, an associative array, or a single value by name.
	 *
	 * You are not allowed to set variables that begin with an underscore;
	 * these are either private properties for JView or private variables
	 * within the template script itself.
	 *
	 * <code>
	 * $view = new JView;
	 *
	 * // Assign directly
	 * $view->var1 = 'something';
	 * $view->var2 = 'else';
	 *
	 * // Assign by name and value
	 * $view->assign('var1', 'something');
	 * $view->assign('var2', 'else');
	 *
	 * // Assign by assoc-array
	 * $ary = array('var1' => 'something', 'var2' => 'else');
	 * $view->assign($obj);
	 *
	 * // Assign by object
	 * $obj = new stdClass;
	 * $obj->var1 = 'something';
	 * $obj->var2 = 'else';
	 * $view->assign($obj);
	 *
	 * </code>
	 *
	 * @return  boolean  True on success, false on failure.
	 */
	public function assign()
	{
		// Get the arguments; there may be 1 or 2.
		$arg0 = @func_get_arg(0);
		$arg1 = @func_get_arg(1);

		// Assign by object
		if (is_object($arg0))
		{
			// Assign public properties
			foreach (get_object_vars($arg0) as $key => $val)
			{
				if (substr($key, 0, 1) != '_')
				{
					$this->$key = $val;
				}
			}
			return true;
		}

		// Assign by associative array
		if (is_array($arg0))
		{
			foreach ($arg0 as $key => $val)
			{
				if (substr($key, 0, 1) != '_')
				{
					$this->$key = $val;
				}
			}
			return true;
		}

		// Assign by string name and mixed value.

		// We use array_key_exists() instead of isset() because isset()
		// fails if the value is set to null.
		if (is_string($arg0) && substr($arg0, 0, 1) != '_' && func_num_args() > 1)
		{
			$this->$arg0 = $arg1;
			return true;
		}

		// $arg0 was not object, array, or string.
		return false;
	}

	/**
	 * Assign variable for the view (by reference).
	 *
	 * You are not allowed to set variables that begin with an underscore;
	 * these are either private properties for JView or private variables
	 * within the template script itself.
	 *
	 * <code>
	 * $view = new JView;
	 *
	 * // Assign by name and value
	 * $view->assignRef('var1', $ref);
	 *
	 * // Assign directly
	 * $view->ref = &$var1;
	 * </code>
	 *
	 * @param   string  $key   The name for the reference in the view.
	 * @param   mixed   &$val  The referenced variable.
	 *
	 * @return  boolean  True on success, false on failure.
	 *
	 * @since   11.1
	 */
	public function assignRef($key, &$val)
	{
		if (is_string($key) && substr($key, 0, 1) != '_')
		{
			$this->$key = &$val;
			return true;
		}

		return false;
	}

	/**
	 * Escapes a value for output in a view script.
	 *
	 * If escaping mechanism is either htmlspecialchars or htmlentities, uses
	 * {@link $_encoding} setting.
	 *
	 * @param   mixed  $var  The output to escape.
	 *
	 * @return  mixed  The escaped value.
	 *
	 * @since   11.1
	 */
	public function escape($var)
	{
		if (in_array($this->_escape, array('htmlspecialchars', 'htmlentities')))
		{
			return call_user_func($this->_escape, $var, ENT_COMPAT, $this->_charset);
		}

		return call_user_func($this->_escape, $var);
	}

	/**
	 * Method to get data from a registered model or a property of the view
	 *
	 * @param   string  $property  The name of the method to call on the model or the property to get
	 * @param   string  $default   The name of the model to reference or the default value [optional]
	 *
	 * @return  mixed  The return value of the method
	 *
	 * @since   11.1
	 */
	public function get($property, $default = null)
	{

		// If $model is null we use the default model
		if (is_null($default))
		{
			$model = $this->_defaultModel;
		}
		else
		{
			$model = strtolower($default);
		}

		// First check to make sure the model requested exists
		if (isset($this->_models[$model]))
		{
			// Model exists, let's build the method name
			$method = 'get' . ucfirst($property);

			// Does the method exist?
			if (method_exists($this->_models[$model], $method))
			{
				// The method exists, let's call it and return what we get
				$result = $this->_models[$model]->$method();
				return $result;
			}

		}

		// Degrade to JObject::get
		$result = parent::get($property, $default);

		return $result;
	}

	/**
	 * Method to get the model object
	 *
	 * @param   string  $name  The name of the model (optional)
	 *
	 * @return  mixed  JModel object
	 *
	 * @since   11.1
	 */
	public function getModel($name = null)
	{
		if ($name === null)
		{
			$name = $this->_defaultModel;
		}
		return $this->_models[strtolower($name)];
	}

	/**
	 * Get the layout.
	 *
	 * @return  string  The layout name
	 */
	public function getLayout()
	{
		return $this->_layout;
	}

	/**
	 * Get the layout template.
	 *
	 * @return  string  The layout template name
	 */
	public function getLayoutTemplate()
	{
		return $this->_layoutTemplate;
	}

	/**
	 * Method to get the view name
	 *
	 * The model name by default parsed using the classname, or it can be set
	 * by passing a $config['name'] in the class constructor
	 *
	 * @return  string  The name of the model
	 *
	 * @since   11.1
	 */
	public function getName()
	{
		if (empty($this->_name))
		{
			$r = null;
			if (!preg_match('/View((view)*(.*(view)?.*))$/i', get_class($this), $r))
			{
				JError::raiseError(500, JText::_('JLIB_APPLICATION_ERROR_VIEW_GET_NAME'));
			}
			if (strpos($r[3], "view"))
			{
				JError::raiseWarning('SOME_ERROR_CODE', JText::_('JLIB_APPLICATION_ERROR_VIEW_GET_NAME_SUBSTRING'));
			}
			$this->_name = strtolower($r[3]);
		}

		return $this->_name;
	}

	/**
	 * Method to add a model to the view.  We support a multiple model single
	 * view system by which models are referenced by classname.  A caveat to the
	 * classname referencing is that any classname prepended by JModel will be
	 * referenced by the name without JModel, eg. JModelCategory is just
	 * Category.
	 *
	 * @param   JModel   &$model   The model to add to the view.
	 * @param   boolean  $default  Is this the default model?
	 *
	 * @return  object   The added model.
	 *
	 * @since   11.1
	 */
	public function setModel(&$model, $default = false)
	{
		$name = strtolower($model->getName());
		$this->_models[$name] = &$model;

		if ($default)
		{
			$this->_defaultModel = $name;
		}
		return $model;
	}

	/**
	 * Sets the layout name to use
	 *
	 * @param   string  $layout  The layout name or a string in format <template>:<layout file>
	 *
	 * @return  string  Previous value.
	 *
	 * @since   11.1
	 */
	public function setLayout($layout)
	{
		$previous = $this->_layout;
		if (strpos($layout, ':') === false)
		{
			$this->_layout = $layout;
		}
		else
		{
			// Convert parameter to array based on :
			$temp = explode(':', $layout);
			$this->_layout = $temp[1];

			// Set layout template
			$this->_layoutTemplate = $temp[0];
		}

		return $previous;
	}

	/**
	 * Allows a different extension for the layout files to be used
	 *
	 * @param   string  $value  The extension.
	 *
	 * @return  string   Previous value
	 *
	 * @since   11.1
	 */
	public function setLayoutExt($value)
	{
		$previous = $this->_layoutExt;
		if ($value = preg_replace('#[^A-Za-z0-9]#', '', trim($value)))
		{
			$this->_layoutExt = $value;
		}

		return $previous;
	}

	/**
	 * Sets the _escape() callback.
	 *
	 * @param   mixed  $spec  The callback for _escape() to use.
	 *
	 * @return  void
	 *
	 * @since   11.1
	 */
	public function setEscape($spec)
	{
		$this->_escape = $spec;
	}

	/**
	 * Adds to the stack of view script paths in LIFO order.
	 *
	 * @param   mixed  $path  A directory path or an array of paths.
	 *
	 * @return  void
	 *
	 * @since   11.1
	 */
	public function addTemplatePath($path)
	{
		$this->_addPath('template', $path);
	}

	/**
	 * Adds to the stack of helper script paths in LIFO order.
	 *
	 * @param   mixed  $path  A directory path or an array of paths.
	 *
	 * @return  void
	 *
	 * @since   11.1
	 */
	public function addHelperPath($path)
	{
		$this->_addPath('helper', $path);
	}

	/**
	 * Load a template file -- first look in the templates folder for an override
	 *
	 * @param   string  $tpl  The name of the template source file; automatically searches the template paths and compiles as needed.
	 *
	 * @return  string  The output of the the template script.
	 *
	 * @since   11.1
	 */
	public function loadTemplate($tpl = null)
	{
		// Clear prior output
		$this->_output = null;

		$template = JFactory::getApplication()->getTemplate();
		$layout = $this->getLayout();
		$layoutTemplate = $this->getLayoutTemplate();

		// Create the template file name based on the layout
		$file = isset($tpl) ? $layout . '_' . $tpl : $layout;

		// Clean the file name
		$file = preg_replace('/[^A-Z0-9_\.-]/i', '', $file);
		$tpl = isset($tpl) ? preg_replace('/[^A-Z0-9_\.-]/i', '', $tpl) : $tpl;

		// Load the language file for the template
		$lang = JFactory::getLanguage();
		$lang->load('tpl_' . $template, JPATH_BASE, null, false, false)
			|| $lang->load('tpl_' . $template, JPATH_THEMES . "/$template", null, false, false)
			|| $lang->load('tpl_' . $template, JPATH_BASE, $lang->getDefault(), false, false)
			|| $lang->load('tpl_' . $template, JPATH_THEMES . "/$template", $lang->getDefault(), false, false);

		// Change the template folder if alternative layout is in different template
		if (isset($layoutTemplate) && $layoutTemplate != '_' && $layoutTemplate != $template)
		{
			$this->_path['template'] = str_replace($template, $layoutTemplate, $this->_path['template']);
		}

		// Load the template script
		jimport('joomla.filesystem.path');
		$filetofind = $this->_createFileName('template', array('name' => $file));
		$this->_template = JPath::find($this->_path['template'], $filetofind);

		// If alternate layout can't be found, fall back to default layout
		if ($this->_template == false)
		{
			$filetofind = $this->_createFileName('', array('name' => 'default' . (isset($tpl) ? '_' . $tpl : $tpl)));
			$this->_template = JPath::find($this->_path['template'], $filetofind);
		}

		if ($this->_template != false)
		{
			// Unset so as not to introduce into template scope
			unset($tpl);
			unset($file);

			// Never allow a 'this' property
			if (isset($this->this))
			{
				unset($this->this);
			}

			// Start capturing output into a buffer
			ob_start();

			// Include the requested template filename in the local scope
			// (this will execute the view logic).
			include $this->_template;

			// Done with the requested template; get the buffer and
			// clear it.
			$this->_output = ob_get_contents();
			ob_end_clean();

			return $this->_output;
		}
		else
		{
			return JError::raiseError(500, JText::sprintf('JLIB_APPLICATION_ERROR_LAYOUTFILE_NOT_FOUND', $file));
		}
	}

	/**
	 * Load a helper file
	 *
	 * @param   string  $hlp  The name of the helper source file automatically searches the helper paths and compiles as needed.
	 *
	 * @return  void
	 *
	 * @since   11.1
	 */
	public function loadHelper($hlp = null)
	{
		// Clean the file name
		$file = preg_replace('/[^A-Z0-9_\.-]/i', '', $hlp);

		// Load the template script
		jimport('joomla.filesystem.path');
		$helper = JPath::find($this->_path['helper'], $this->_createFileName('helper', array('name' => $file)));

		if ($helper != false)
		{
			// Include the requested template filename in the local scope
			include_once $helper;
		}
	}

	/**
	 * Sets an entire array of search paths for templates or resources.
	 *
	 * @param   string  $type  The type of path to set, typically 'template'.
	 * @param   mixed   $path  The new search path, or an array of search paths.  If null or false, resets to the current directory only.
	 *
	 * @return  void
	 *
	 * @since   11.1
	 */
	protected function _setPath($type, $path)
	{
		$component = JApplicationHelper::getComponentName();
		$app = JFactory::getApplication();

		// Clear out the prior search dirs
		$this->_path[$type] = array();

		// Actually add the user-specified directories
		$this->_addPath($type, $path);

		// Always add the fallback directories as last resort
		switch (strtolower($type))
		{
			case 'template':
				// Set the alternative template search dir
				if (isset($app))
				{
					$component = preg_replace('/[^A-Z0-9_\.-]/i', '', $component);
					
					//if it is T3 template, update search path for template
					$this->_addPath('template', T3_PATH . '/html/' . $component . '/' . $this->getName());

					$fallback = JPATH_THEMES . '/' . $app->getTemplate() . '/html/' . $component . '/' . $this->getName();
					$this->_addPath('template', $fallback);

					//search path for user custom folder
					if (!defined('T3_LOCAL_DISABLED')) $this->_addPath('template', T3_LOCAL_PATH . '/html/' . $component . '/' . $this->getName());

				}
				break;
		}
	}

	/**
	 * Adds to the search path for templates and resources.
	 *
	 * @param   string  $type  The type of path to add.
	 * @param   mixed   $path  The directory or stream, or an array of either, to search.
	 *
	 * @return  void
	 *
	 * @since   11.1
	 */
	protected function _addPath($type, $path)
	{
		// Just force to array
		settype($path, 'array');

		// Loop through the path directories
		foreach ($path as $dir)
		{
			// no surrounding spaces allowed!
			$dir = trim($dir);

			// Add trailing separators as needed
			if (substr($dir, -1) != DIRECTORY_SEPARATOR)
			{
				// Directory
				$dir .= DIRECTORY_SEPARATOR;
			}

			// Add to the top of the search dirs
			array_unshift($this->_path[$type], $dir);
		}
	}

	/**
	 * Create the filename for a resource
	 *
	 * @param   string  $type   The resource type to create the filename for
	 * @param   array   $parts  An associative array of filename information
	 *
	 * @return  string  The filename
	 *
	 * @since   11.1
	 */
	protected function _createFileName($type, $parts = array())
	{
		$filename = '';

		switch ($type)
		{
			case 'template':
				$filename = strtolower($parts['name']) . '.' . $this->_layoutExt;
				break;

			default:
				$filename = strtolower($parts['name']) . '.php';
				break;
		}
		return $filename;
	}
}
joomla25/pagination.php000060400000047375152455303030011052 0ustar00<?php
/**
 * @package     Joomla.Platform
 * @subpackage  HTML
 *
 * @copyright   Copyright (C) 2005 - 2012 Open Source Matters, Inc. All rights reserved.
 * @license     GNU General Public License version 2 or later; see LICENSE
 */

defined('JPATH_PLATFORM') or die;

/**
 * Pagination Class.  Provides a common interface for content pagination for the
 * Joomla! Platform.
 *
 * @package     Joomla.Platform
 * @subpackage  HTML
 * @since       11.1
 */
class JPagination extends JObject
{
	/**
	 * @var    integer  The record number to start displaying from.
	 * @since  11.1
	 */
	public $limitstart = null;

	/**
	 * @var    integer  Number of rows to display per page.
	 * @since  11.1
	 */
	public $limit = null;

	/**
	 * @var    integer  Total number of rows.
	 * @since  11.1
	 */
	public $total = null;

	/**
	 * @var    integer  Prefix used for request variables.
	 * @since  11.1
	 */
	public $prefix = null;

	/**
	 * @var    boolean  View all flag
	 * @since  11.1
	 */
	protected $_viewall = false;

	/**
	 * Additional URL parameters to be added to the pagination URLs generated by the class.  These
	 * may be useful for filters and extra values when dealing with lists and GET requests.
	 *
	 * @var    array
	 * @since  11.1
	 */
	protected $_additionalUrlParams = array();

	/**
	 * Constructor.
	 *
	 * @param   integer  $total       The total number of items.
	 * @param   integer  $limitstart  The offset of the item to start at.
	 * @param   integer  $limit       The number of items to display per page.
	 * @param   string   $prefix      The prefix used for request variables.
	 *
	 * @since   11.1
	 */
	public function __construct($total, $limitstart, $limit, $prefix = '')
	{
		// Value/type checking.
		$this->total = (int) $total;
		$this->limitstart = (int) max($limitstart, 0);
		$this->limit = (int) max($limit, 0);
		$this->prefix = $prefix;

		if ($this->limit > $this->total)
		{
			$this->limitstart = 0;
		}

		if (!$this->limit)
		{
			$this->limit = $total;
			$this->limitstart = 0;
		}

		/*
		 * If limitstart is greater than total (i.e. we are asked to display records that don't exist)
		 * then set limitstart to display the last natural page of results
		 */
		if ($this->limitstart > $this->total - $this->limit)
		{
			$this->limitstart = max(0, (int) (ceil($this->total / $this->limit) - 1) * $this->limit);
		}

		// Set the total pages and current page values.
		if ($this->limit > 0)
		{
			$this->set('pages.total', ceil($this->total / $this->limit));
			$this->set('pages.current', ceil(($this->limitstart + 1) / $this->limit));
		}

		// Set the pagination iteration loop values.
		$displayedPages = 10;
		$this->set('pages.start', $this->get('pages.current') - ($displayedPages / 2));
		if ($this->get('pages.start') < 1)
		{
			$this->set('pages.start', 1);
		}
		if (($this->get('pages.start') + $displayedPages) > $this->get('pages.total'))
		{
			$this->set('pages.stop', $this->get('pages.total'));
			if ($this->get('pages.total') < $displayedPages)
			{
				$this->set('pages.start', 1);
			}
			else
			{
				$this->set('pages.start', $this->get('pages.total') - $displayedPages + 1);
			}
		}
		else
		{
			$this->set('pages.stop', ($this->get('pages.start') + $displayedPages - 1));
		}

		// If we are viewing all records set the view all flag to true.
		if ($limit == 0)
		{
			$this->_viewall = true;
		}
	}

	/**
	 * Method to set an additional URL parameter to be added to all pagination class generated
	 * links.
	 *
	 * @param   string  $key    The name of the URL parameter for which to set a value.
	 * @param   mixed   $value  The value to set for the URL parameter.
	 *
	 * @return  mixed  The old value for the parameter.
	 *
	 * @since   11.1
	 */
	public function setAdditionalUrlParam($key, $value)
	{
		// Get the old value to return and set the new one for the URL parameter.
		$result = isset($this->_additionalUrlParams[$key]) ? $this->_additionalUrlParams[$key] : null;

		// If the passed parameter value is null unset the parameter, otherwise set it to the given value.
		if ($value === null)
		{
			unset($this->_additionalUrlParams[$key]);
		}
		else
		{
			$this->_additionalUrlParams[$key] = $value;
		}

		return $result;
	}

	/**
	 * Method to get an additional URL parameter (if it exists) to be added to
	 * all pagination class generated links.
	 *
	 * @param   string  $key  The name of the URL parameter for which to get the value.
	 *
	 * @return  mixed  The value if it exists or null if it does not.
	 *
	 * @since   11.1
	 */
	public function getAdditionalUrlParam($key)
	{
		$result = isset($this->_additionalUrlParams[$key]) ? $this->_additionalUrlParams[$key] : null;

		return $result;
	}

	/**
	 * Return the rationalised offset for a row with a given index.
	 *
	 * @param   integer  $index  The row index
	 *
	 * @return  integer  Rationalised offset for a row with a given index.
	 *
	 * @since   11.1
	 */
	public function getRowOffset($index)
	{
		return $index + 1 + $this->limitstart;
	}

	/**
	 * Return the pagination data object, only creating it if it doesn't already exist.
	 *
	 * @return  object   Pagination data object.
	 *
	 * @since   11.1
	 */
	public function getData()
	{
		static $data;
		if (!is_object($data))
		{
			$data = $this->_buildDataObject();
		}
		return $data;
	}

	/**
	 * Create and return the pagination pages counter string, ie. Page 2 of 4.
	 *
	 * @return  string   Pagination pages counter string.
	 *
	 * @since   11.1
	 */
	public function getPagesCounter()
	{
		// Initialise variables.
		$html = null;
		if ($this->get('pages.total') > 1)
		{
			$html .= JText::sprintf('JLIB_HTML_PAGE_CURRENT_OF_TOTAL', $this->get('pages.current'), $this->get('pages.total'));
		}
		return $html;
	}

	/**
	 * Create and return the pagination result set counter string, e.g. Results 1-10 of 42
	 *
	 * @return  string   Pagination result set counter string.
	 *
	 * @since   11.1
	 */
	public function getResultsCounter()
	{
		// Initialise variables.
		$html = null;
		$fromResult = $this->limitstart + 1;

		// If the limit is reached before the end of the list.
		if ($this->limitstart + $this->limit < $this->total)
		{
			$toResult = $this->limitstart + $this->limit;
		}
		else
		{
			$toResult = $this->total;
		}

		// If there are results found.
		if ($this->total > 0)
		{
			$msg = JText::sprintf('JLIB_HTML_RESULTS_OF', $fromResult, $toResult, $this->total);
			$html .= "\n" . $msg;
		}
		else
		{
			$html .= "\n" . JText::_('JLIB_HTML_NO_RECORDS_FOUND');
		}

		return $html;
	}

	/**
	 * Create and return the pagination page list string, ie. Previous, Next, 1 2 3 ... x.
	 *
	 * @return  string  Pagination page list string.
	 *
	 * @since   11.1
	 */
	public function getPagesLinks()
	{
		$app = JFactory::getApplication();

		// Build the page navigation list.
		$data = $this->_buildDataObject();

		$list = array();
		$list['prefix'] = $this->prefix;

		$itemOverride = false;
		$listOverride = false;

		// T3: detect if chrome pagination.php in template or in plugin
		$chromePath = T3Path::getPath ('html/pagination.php');		
		// $chromePath = JPATH_THEMES . '/' . $app->getTemplate() . '/html/pagination.php';
		if (file_exists($chromePath))
		{
			include_once $chromePath;
			if (function_exists('pagination_item_active') && function_exists('pagination_item_inactive'))
			{
				$itemOverride = true;
			}
			if (function_exists('pagination_list_render'))
			{
				$listOverride = true;
			}
		}

		// Build the select list
		if ($data->all->base !== null)
		{
			$list['all']['active'] = true;
			$list['all']['data'] = ($itemOverride) ? pagination_item_active($data->all) : $this->_item_active($data->all);
		}
		else
		{
			$list['all']['active'] = false;
			$list['all']['data'] = ($itemOverride) ? pagination_item_inactive($data->all) : $this->_item_inactive($data->all);
		}

		if ($data->start->base !== null)
		{
			$list['start']['active'] = true;
			$list['start']['data'] = ($itemOverride) ? pagination_item_active($data->start) : $this->_item_active($data->start);
		}
		else
		{
			$list['start']['active'] = false;
			$list['start']['data'] = ($itemOverride) ? pagination_item_inactive($data->start) : $this->_item_inactive($data->start);
		}
		if ($data->previous->base !== null)
		{
			$list['previous']['active'] = true;
			$list['previous']['data'] = ($itemOverride) ? pagination_item_active($data->previous) : $this->_item_active($data->previous);
		}
		else
		{
			$list['previous']['active'] = false;
			$list['previous']['data'] = ($itemOverride) ? pagination_item_inactive($data->previous) : $this->_item_inactive($data->previous);
		}

		$list['pages'] = array(); //make sure it exists
		foreach ($data->pages as $i => $page)
		{
			if ($page->base !== null)
			{
				$list['pages'][$i]['active'] = true;
				$list['pages'][$i]['data'] = ($itemOverride) ? pagination_item_active($page) : $this->_item_active($page);
			}
			else
			{
				$list['pages'][$i]['active'] = false;
				$list['pages'][$i]['data'] = ($itemOverride) ? pagination_item_inactive($page) : $this->_item_inactive($page);
			}
		}

		if ($data->next->base !== null)
		{
			$list['next']['active'] = true;
			$list['next']['data'] = ($itemOverride) ? pagination_item_active($data->next) : $this->_item_active($data->next);
		}
		else
		{
			$list['next']['active'] = false;
			$list['next']['data'] = ($itemOverride) ? pagination_item_inactive($data->next) : $this->_item_inactive($data->next);
		}

		if ($data->end->base !== null)
		{
			$list['end']['active'] = true;
			$list['end']['data'] = ($itemOverride) ? pagination_item_active($data->end) : $this->_item_active($data->end);
		}
		else
		{
			$list['end']['active'] = false;
			$list['end']['data'] = ($itemOverride) ? pagination_item_inactive($data->end) : $this->_item_inactive($data->end);
		}

		if ($this->total > $this->limit)
		{
			return ($listOverride) ? pagination_list_render($list) : $this->_list_render($list);
		}
		else
		{
			return '';
		}
	}

	/**
	 * Return the pagination footer.
	 *
	 * @return  string   Pagination footer.
	 *
	 * @since   11.1
	 */
	public function getListFooter()
	{
		$app = JFactory::getApplication();

		$list = array();
		$list['prefix'] = $this->prefix;
		$list['limit'] = $this->limit;
		$list['limitstart'] = $this->limitstart;
		$list['total'] = $this->total;
		$list['limitfield'] = $this->getLimitBox();
		$list['pagescounter'] = $this->getPagesCounter();
		$list['pageslinks'] = $this->getPagesLinks();

		// T3: detect if chrome pagination.php in template or in plugin
		$chromePath = T3Path::getPath ('html/pagination.php');		
		// $chromePath = JPATH_THEMES . '/' . $app->getTemplate() . '/html/pagination.php';
		if (file_exists($chromePath))
		{
			include_once $chromePath;
			if (function_exists('pagination_list_footer'))
			{
				return pagination_list_footer($list);
			}
		}
		return $this->_list_footer($list);
	}

	/**
	 * Creates a dropdown box for selecting how many records to show per page.
	 *
	 * @return  string  The HTML for the limit # input box.
	 *
	 * @since   11.1
	 */
	public function getLimitBox()
	{
		$app = JFactory::getApplication();

		// Initialise variables.
		$limits = array();

		// Make the option list.
		for ($i = 5; $i <= 30; $i += 5)
		{
			$limits[] = JHtml::_('select.option', "$i");
		}
		$limits[] = JHtml::_('select.option', '50', JText::_('J50'));
		$limits[] = JHtml::_('select.option', '100', JText::_('J100'));
		$limits[] = JHtml::_('select.option', '0', JText::_('JALL'));

		$selected = $this->_viewall ? 0 : $this->limit;

		// Build the select list.
		if (T3::isAdmin())
		{
			$html = JHtml::_(
				'select.genericlist',
				$limits,
				$this->prefix . 'limit',
				'class="inputbox" size="1" onchange="Joomla.submitform();"',
				'value',
				'text',
				$selected
			);
		}
		else
		{
			$html = JHtml::_(
				'select.genericlist',
				$limits,
				$this->prefix . 'limit',
				'class="inputbox" size="1" onchange="this.form.submit()"',
				'value',
				'text',
				$selected
			);
		}
		return $html;
	}

	/**
	 * Return the icon to move an item UP.
	 *
	 * @param   integer  $i          The row index.
	 * @param   boolean  $condition  True to show the icon.
	 * @param   string   $task       The task to fire.
	 * @param   string   $alt        The image alternative text string.
	 * @param   boolean  $enabled    An optional setting for access control on the action.
	 * @param   string   $checkbox   An optional prefix for checkboxes.
	 *
	 * @return  string   Either the icon to move an item up or a space.
	 *
	 * @since   11.1
	 */
	public function orderUpIcon($i, $condition = true, $task = 'orderup', $alt = 'JLIB_HTML_MOVE_UP', $enabled = true, $checkbox = 'cb')
	{
		if (($i > 0 || ($i + $this->limitstart > 0)) && $condition)
		{
			return JHtml::_('jgrid.orderUp', $i, $task, '', $alt, $enabled, $checkbox);
		}
		else
		{
			return '&#160;';
		}
	}

	/**
	 * Return the icon to move an item DOWN.
	 *
	 * @param   integer  $i          The row index.
	 * @param   integer  $n          The number of items in the list.
	 * @param   boolean  $condition  True to show the icon.
	 * @param   string   $task       The task to fire.
	 * @param   string   $alt        The image alternative text string.
	 * @param   boolean  $enabled    An optional setting for access control on the action.
	 * @param   string   $checkbox   An optional prefix for checkboxes.
	 *
	 * @return  string   Either the icon to move an item down or a space.
	 *
	 * @since   11.1
	 */
	public function orderDownIcon($i, $n, $condition = true, $task = 'orderdown', $alt = 'JLIB_HTML_MOVE_DOWN', $enabled = true, $checkbox = 'cb')
	{
		if (($i < $n - 1 || $i + $this->limitstart < $this->total - 1) && $condition)
		{
			return JHtml::_('jgrid.orderDown', $i, $task, '', $alt, $enabled, $checkbox);
		}
		else
		{
			return '&#160;';
		}
	}

	/**
	 * Create the HTML for a list footer
	 *
	 * @param   array  $list  Pagination list data structure.
	 *
	 * @return  string  HTML for a list footer
	 *
	 * @since   11.1
	 */
	protected function _list_footer($list)
	{
		$html = "<div class=\"list-footer\">\n";

		$html .= "\n<div class=\"limit\">" . JText::_('JGLOBAL_DISPLAY_NUM') . $list['limitfield'] . "</div>";
		$html .= $list['pageslinks'];
		$html .= "\n<div class=\"counter\">" . $list['pagescounter'] . "</div>";

		$html .= "\n<input type=\"hidden\" name=\"" . $list['prefix'] . "limitstart\" value=\"" . $list['limitstart'] . "\" />";
		$html .= "\n</div>";

		return $html;
	}

	/**
	 * Create the html for a list footer
	 *
	 * @param   array  $list  Pagination list data structure.
	 *
	 * @return  string  HTML for a list start, previous, next,end
	 *
	 * @since   11.1
	 */
	protected function _list_render($list)
	{
		// Reverse output rendering for right-to-left display.
		$html = '<ul>';
		$html .= '<li class="pagination-start">' . $list['start']['data'] . '</li>';
		$html .= '<li class="pagination-prev">' . $list['previous']['data'] . '</li>';
		foreach ($list['pages'] as $page)
		{
			$html .= '<li>' . $page['data'] . '</li>';
		}
		$html .= '<li class="pagination-next">' . $list['next']['data'] . '</li>';
		$html .= '<li class="pagination-end">' . $list['end']['data'] . '</li>';
		$html .= '</ul>';

		return $html;
	}

	/**
	 * Method to create an active pagination link to the item
	 *
	 * @param   JPaginationObject  &$item  The object with which to make an active link.
	 *
	 * @return   string  HTML link
	 *
	 * @since    11.1
	 */
	protected function _item_active(&$item)
	{
		$app = JFactory::getApplication();
		if (T3::isAdmin())
		{
			if ($item->base > 0)
			{
				return "<a title=\"" . $item->text . "\" onclick=\"document.adminForm." . $this->prefix . "limitstart.value=" . $item->base
					. "; Joomla.submitform();return false;\">" . $item->text . "</a>";
			}
			else
			{
				return "<a title=\"" . $item->text . "\" onclick=\"document.adminForm." . $this->prefix
					. "limitstart.value=0; Joomla.submitform();return false;\">" . $item->text . "</a>";
			}
		}
		else
		{
			return "<a title=\"" . $item->text . "\" href=\"" . $item->link . "\" class=\"pagenav\">" . $item->text . "</a>";
		}
	}

	/**
	 * Method to create an inactive pagination string
	 *
	 * @param   object  &$item  The item to be processed
	 *
	 * @return  string
	 *
	 * @since   11.1
	 */
	protected function _item_inactive(&$item)
	{
		$app = JFactory::getApplication();
		if (T3::isAdmin())
		{
			return "<span>" . $item->text . "</span>";
		}
		else
		{
			return "<span class=\"pagenav\">" . $item->text . "</span>";
		}
	}

	/**
	 * Create and return the pagination data object.
	 *
	 * @return  object  Pagination data object.
	 *
	 * @since   11.1
	 */
	protected function _buildDataObject()
	{
		// Initialise variables.
		$data = new stdClass;

		// Build the additional URL parameters string.
		$params = '';
		if (!empty($this->_additionalUrlParams))
		{
			foreach ($this->_additionalUrlParams as $key => $value)
			{
				$params .= '&' . $key . '=' . $value;
			}
		}

		$data->all = new JPaginationObject(JText::_('JLIB_HTML_VIEW_ALL'), $this->prefix);
		if (!$this->_viewall)
		{
			$data->all->base = '0';
			$data->all->link = JRoute::_($params . '&' . $this->prefix . 'limitstart=');
		}

		// Set the start and previous data objects.
		$data->start = new JPaginationObject(JText::_('JLIB_HTML_START'), $this->prefix);
		$data->previous = new JPaginationObject(JText::_('JPREV'), $this->prefix);

		if ($this->get('pages.current') > 1)
		{
			$page = ($this->get('pages.current') - 2) * $this->limit;

			// Set the empty for removal from route
			//$page = $page == 0 ? '' : $page;

			$data->start->base = '0';
			$data->start->link = JRoute::_($params . '&' . $this->prefix . 'limitstart=0' . '&limit=' . $this->limit);
			$data->previous->base = $page;
			$data->previous->link = JRoute::_($params . '&' . $this->prefix . 'limitstart=' . $page . '&limit=' . $this->limit);
		}

		// Set the next and end data objects.
		$data->next = new JPaginationObject(JText::_('JNEXT'), $this->prefix);
		$data->end = new JPaginationObject(JText::_('JLIB_HTML_END'), $this->prefix);

		if ($this->get('pages.current') < $this->get('pages.total'))
		{
			$next = $this->get('pages.current') * $this->limit;
			$end = ($this->get('pages.total') - 1) * $this->limit;

			$data->next->base = $next;
			$data->next->link = JRoute::_($params . '&' . $this->prefix . 'limitstart=' . $next . '&limit=' . $this->limit);
			$data->end->base = $end;
			$data->end->link = JRoute::_($params . '&' . $this->prefix . 'limitstart=' . $end . '&limit=' . $this->limit);
		}

		$data->pages = array();
		$stop = $this->get('pages.stop');
		for ($i = $this->get('pages.start'); $i <= $stop; $i++)
		{
			$offset = ($i - 1) * $this->limit;
			// Set the empty for removal from route
			//$offset = $offset == 0 ? '' : $offset;

			$data->pages[$i] = new JPaginationObject($i, $this->prefix);
			if ($i != $this->get('pages.current') || $this->_viewall)
			{
				$data->pages[$i]->base = $offset;
				$data->pages[$i]->link = JRoute::_($params . '&' . $this->prefix . 'limitstart=' . $offset . '&limit=' . $this->limit);
			}
		}
		return $data;
	}
}

/**
 * Pagination object representing a particular item in the pagination lists.
 *
 * @package     Joomla.Platform
 * @subpackage  HTML
 * @since       11.1
 */
class JPaginationObject extends JObject
{
	/**
	 * @var    string  The link text.
	 * @since  11.1
	 */
	public $text;

	/**
	 * @var    integer  The number of rows as a base offset.
	 * @since  11.1
	 */
	public $base;

	/**
	 * @var    string  The link URL.
	 * @since  11.1
	 */
	public $link;

	/**
	 * @var    integer  The prefix used for request variables.
	 * @since  11.1
	 */
	public $prefix;

	/**
	 * Class constructor.
	 *
	 * @param   string   $text    The link text.
	 * @param   integer  $prefix  The prefix used for request variables.
	 * @param   integer  $base    The number of rows as a base offset.
	 * @param   string   $link    The link URL.
	 *
	 * @since   11.1
	 */
	public function __construct($text, $prefix = '', $base = null, $link = null)
	{
		$this->text = $text;
		$this->prefix = $prefix;
		$this->base = $base;
		$this->link = $link;
	}
}
joomla4/html/bootstrap.php000060400000004443152455303030011604 0ustar00<?php
/**
 * @package     Joomla.Libraries
 * @subpackage  HTML
 *
 * @copyright   Copyright (C) 2005 - 2020 Open Source Matters, Inc. All rights reserved.
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */
use Joomla\CMS\HTML\Helpers\Bootstrap as JBootstrap;
defined('JPATH_PLATFORM') or die;

/**
 * Utility class for JavaScript behaviors
 *
 * @since  1.5
 */
abstract class T3HtmlBootstrap extends JBootstrap
{


	/**
	 * Method to render a Bootstrap modal
	 *
	 * @param   string  $selector  The ID selector for the modal.
	 * @param   array   $params    An array of options for the modal.
	 *                             Options for the modal can be:
	 *                             - title        string   The modal title
	 *                             - backdrop     mixed    A boolean select if a modal-backdrop element should be included (default = true)
	 *                                                     The string 'static' includes a backdrop which doesn't close the modal on click.
	 *                             - keyboard     boolean  Closes the modal when escape key is pressed (default = true)
	 *                             - closeButton  boolean  Display modal close button (default = true)
	 *                             - animation    boolean  Fade in from the top of the page (default = true)
	 *                             - footer       string   Optional markup for the modal footer
	 *                             - url          string   URL of a resource to be inserted as an `<iframe>` inside the modal body
	 *                             - height       string   height of the `<iframe>` containing the remote resource
	 *                             - width        string   width of the `<iframe>` containing the remote resource
	 * @param   string  $body      Markup for the modal body. Appended after the `<iframe>` if the URL option is set
	 *
	 * @return  string  HTML markup for a modal
	 *
	 * @since   3.0
	 */
	public static function renderModal($selector = 'modal', $params = array(), $body = '') :string
	{
		$method = parent::class . '::' . __FUNCTION__;
		// Force to rerender in admin
		if (!empty(static::$loaded[$method][$selector]))
		{
			static::$loaded[$method][$selector] = false;
		}

		return parent::renderModal($selector, $params, $body);
	}
}joomla4/html/behavior.php000060400000014666152455303030011376 0ustar00<?php
/**
 * @package     Joomla.Libraries
 * @subpackage  HTML
 *
 * @copyright   Copyright (C) 2005 - 2020 Open Source Matters, Inc. All rights reserved.
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

use Joomla\CMS\HTML\Helpers\Behavior;

defined('JPATH_PLATFORM') or die;

/**
 * Utility class for JavaScript behaviors
 *
 * @since  1.5
 */
abstract class T3HtmlBehavior extends Behavior
{

	/**
	 * Add unobtrusive JavaScript support for a hover tooltips.
	 *
	 * Add a title attribute to any element in the form
	 * title="title::text"
	 *
	 * Uses the core Tips class in MooTools.
	 *
	 * @param   string  $selector  The class selector for the tooltip.
	 * @param   array   $params    An array of options for the tooltip.
	 *                             Options for the tooltip can be:
	 *                             - maxTitleChars  integer   The maximum number of characters in the tooltip title (defaults to 50).
	 *                             - offsets        object    The distance of your tooltip from the mouse (defaults to {'x': 16, 'y': 16}).
	 *                             - showDelay      integer   The millisecond delay the show event is fired (defaults to 100).
	 *                             - hideDelay      integer   The millisecond delay the hide hide is fired (defaults to 100).
	 *                             - className      string    The className your tooltip container will get.
	 *                             - fixed          boolean   If set to true, the toolTip will not follow the mouse.
	 *                             - onShow         function  The default function for the show event, passes the tip element
	 *                               and the currently hovered element.
	 *                             - onHide         function  The default function for the hide event, passes the currently
	 *                               hovered element.
	 *
	 * @return  void
	 *
	 * @since   1.5
	 */
	public static function tooltip($selector = '.hasTip', $params = array())
	{
		$sig = md5(serialize(array($selector, $params)));

		if (isset(static::$loaded[__METHOD__][$sig]))
		{
			return;
		}

		// Include MooTools framework
		static::framework(true);

		// Setup options object
		$opt['maxTitleChars'] = isset($params['maxTitleChars']) && $params['maxTitleChars'] ? (int) $params['maxTitleChars'] : 50;

		// Offsets needs an array in the format: array('x'=>20, 'y'=>30)
		$opt['offset']    = isset($params['offset']) && is_array($params['offset']) ? $params['offset'] : null;
		$opt['showDelay'] = isset($params['showDelay']) ? (int) $params['showDelay'] : null;
		$opt['hideDelay'] = isset($params['hideDelay']) ? (int) $params['hideDelay'] : null;
		$opt['className'] = isset($params['className']) ? $params['className'] : null;
		$opt['fixed']     = isset($params['fixed']) && $params['fixed'];
		$opt['onShow']    = isset($params['onShow']) ? '\\' . $params['onShow'] : null;
		$opt['onHide']    = isset($params['onHide']) ? '\\' . $params['onHide'] : null;

		$options = json_encode($opt);

		// Include jQuery
		JHtml::_('jquery.framework');

		// Attach tooltips to document
		JFactory::getDocument()->addScriptDeclaration(
			"jQuery(function($) {
			 $('$selector').each(function() {
				var title = $(this).attr('title');
				if (title) {
					var parts = title.split('::', 2);
					var mtelement = document.getElementById(this);
					if(mtelement){
						mtelement.store('tip:title', parts[0]);
						mtelement.store('tip:text', parts[1]);
					}
				}
			});
			// var JTooltips = new Tips($('$selector').get(), $options);
		});"
		);

		// Set static array
		static::$loaded[__METHOD__][$sig] = true;

		return;
	}

	/**
	 * Add unobtrusive JavaScript support for form validation.
	 *
	 * To enable form validation the form tag must have class="form-validate".
	 * Each field that needs to be validated needs to have class="validate".
	 * Additional handlers can be added to the handler for username, password,
	 * numeric and email. To use these add class="validate-email" and so on.
	 *
	 * @return  void
	 *
	 * @since   1.5
	 *
	 * @Deprecated 3.4 Use formvalidator instead
	 */
	public static function formvalidation()
	{
		// Include MooTools framework
		static::framework();

		// Load the new jQuery code
		static::formvalidator();
	}


	/**
	 * Method to load the MooTools framework into the document head
	 *
	 * If debugging mode is on an uncompressed version of MooTools is included for easier debugging.
	 *
	 * @param   boolean  $extras  Flag to determine whether to load MooTools More in addition to Core
	 * @param   mixed    $debug   Is debugging mode on? [optional]
	 *
	 * @return  void
	 *
	 * @since   1.6
	 * @deprecated 4.0 Update scripts to jquery
	 */
	public static function framework($extras = false, $debug = null)
	{
		$type = $extras ? 'more' : 'core';

		// Only load once
		if (!empty(static::$loaded[__METHOD__][$type]))
		{
			return;
		}

		JLog::add('JHtmlBehavior::framework is deprecated. Update to jquery scripts.', JLog::WARNING, 'deprecated');

		// If no debugging value is set, use the configuration setting
		if ($debug === null)
		{
			$debug = JDEBUG;
		}

		if ($type !== 'core' && empty(static::$loaded[__METHOD__]['core']))
		{
			static::framework(false, $debug);
		}

		JHtml::_('script', 'system/mootools-' . $type . '.js', array('version' => 'auto', 'relative' => true, 'detectDebug' => $debug));

		// Keep loading core.js for BC reasons
		static::core();

		static::$loaded[__METHOD__][$type] = true;

		return;
	}


	/**
	 * Add unobtrusive JavaScript support for image captions.
	 *
	 * @param   string  $selector  The selector for which a caption behaviour is to be applied.
	 *
	 * @return  void
	 *
	 * @since   1.5
	 *
	 * @Deprecated 4.0 Use native HTML figure tags.
	 */
	public static function caption($selector = 'img.caption')
	{
		JLog::add('JHtmlBehavior::caption is deprecated. Use native HTML figure tags.', JLog::WARNING, 'deprecated');

		// Only load once
		if (isset(static::$loaded[__METHOD__][$selector]))
		{
			return;
		}

		// Include jQuery
		JHtml::_('jquery.framework');
		
		if (!is_file(JPATH_ROOT . 'media/system/js/caption.js')){
			return;
		}
		
		JHtml::_('script', 'system/js/caption.js', array('version' => 'auto', 'relative' => true));

		// Attach caption to document
		JFactory::getDocument()->addScriptDeclaration(
			"jQuery(window).on('load',  function() {
				new JCaption('" . $selector . "');
			});"
		);

		// Set static array
		static::$loaded[__METHOD__][$selector] = true;
	}

}
joomla4/ModuleHelper.php000060400000021576152455303030011216 0ustar00<?php
/**
 * Joomla! Content Management System
 *
 * @copyright  Copyright (C) 2005 - 2017 Open Source Matters, Inc. All rights reserved.
 * @license    GNU General Public License version 2 or later; see LICENSE.txt
 */

namespace Joomla\CMS\Helper;

defined('JPATH_PLATFORM') or die;

use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Factory;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Layout\LayoutHelper;
use Joomla\CMS\Log\Log;
use Joomla\CMS\Profiler\Profiler;
use Joomla\Registry\Registry;

// Make alias of original FileLayout
\T3::makeAlias(JPATH_LIBRARIES . '/src/Helper/ModuleHelper.php', 'ModuleHelper', '_ModuleHelper');


/**
 * Module helper class
 *
 * @since  1.5
 */
abstract class ModuleHelper extends _ModuleHelper
{
		/**
	 * Render the module.
	 *
	 * @param   object  $module   A module object.
	 * @param   array   $attribs  An array of attributes for the module (probably from the XML).
	 *
	 * @return  string  The HTML content of the module output.
	 *
	 * @since   1.5
	 */
	public static function renderModule($module, $attribs = array())
	{
		$app = Factory::getApplication();

		// Check that $module is a valid module object
		if (!\is_object($module) || !isset($module->module) || !isset($module->params))
		{
			if (JDEBUG)
			{
				Log::addLogger(array('text_file' => 'jmodulehelper.log.php'), Log::ALL, array('modulehelper'));
				$app->getLogger()->debug(
					__METHOD__ . '() - The $module parameter should be a module object.',
					array('category' => 'modulehelper')
				);
			}

			return '';
		}

		// Get module parameters
		$params = new Registry($module->params);

		// Render the module content
		static::renderRawModule($module, $params, $attribs);

		// Return early if only the content is required
		if (!empty($attribs['contentOnly']))
		{
			return $module->content;
		}

		if (JDEBUG)
		{
			Profiler::getInstance('Application')->mark('beforeRenderModule ' . $module->module . ' (' . $module->title . ')');
		}

		// Record the scope.
		$scope = $app->scope;

		// Set scope to component name
		$app->scope = $module->module;

		// Get the template
		$template = $app->getTemplate();

		// Check if the current module has a style param to override template module style
		$paramsChromeStyle = $params->get('style');
		$basePath          = '';

		if ($paramsChromeStyle)
		{
			$paramsChromeStyle   = explode('-', $paramsChromeStyle, 2);
			$ChromeStyleTemplate = strtolower($paramsChromeStyle[0]);
			$attribs['style']    = $paramsChromeStyle[1];

			// Only set $basePath if the specified template isn't the current or system one.
			if ($ChromeStyleTemplate !== $template && $ChromeStyleTemplate !== 'system')
			{
				$basePath = JPATH_THEMES . '/' . $ChromeStyleTemplate . '/html/layouts';
			}
		}
		if(version_compare(JVERSION, '4.0', 'lt')){
			include_once JPATH_THEMES . '/system/html/modules.php';
		}

		$chromePath = JPATH_THEMES . '/' . $template . '/html/modules.php';

		if (!isset($chrome[$chromePath]))
		{
			if (file_exists($chromePath))
			{
				// load module style on template
				include_once $chromePath;
			}else{
				if($app->isClient('site')){
					// load module style function for use on some module of JA
					$chromePath = \T3Path::getPath('html/modules.php');
					include_once $chromePath;
				}
			}

			$chrome[$chromePath] = true;
		}
		// Make sure a style is set
		if (!isset($attribs['style']))
		{
			$attribs['style'] = 'none';
		}

		// Dynamically add outline style
		if ($app->input->getBool('tp') && ComponentHelper::getParams('com_templates')->get('template_positions_display'))
		{
			$attribs['style'] .= ' outline';
		}

		$module->style = $attribs['style'];

		// If the $module is nulled it will return an empty content, otherwise it will render the module normally.
		$app->triggerEvent('onRenderModule', array(&$module, &$attribs));

		if ($module === null || !isset($module->content))
		{
			return '';
		}

		$displayData = array(
			'module'  => $module,
			'params'  => $params,
			'attribs' => $attribs,
		);

		foreach (explode(' ', $attribs['style']) as $style)
		{
			if ($moduleContent = LayoutHelper::render('chromes.' . $style, $displayData, $basePath))
			{
				$module->content = $moduleContent;
			}
		}
		foreach (explode(' ', $attribs['style']) as $style)
		{
			$chromeMethod = 'modChrome_' . $style;
			$chromeStylePath = \T3Path::getPath('html/layouts/chromes/'.$style.'.php');
			// Apply chrome and render module
			if (function_exists($chromeMethod) && !file_exists($chromeStylePath))
			{
				$module->style = $attribs['style'];

				ob_start();
				$chromeMethod($module, $params, $attribs);
				$module->content = ob_get_contents();
				ob_end_clean();
			}
		}
		// Revert the scope
		$app->scope = $scope;

		$app->triggerEvent('onAfterRenderModule', array(&$module, &$attribs));

		if (JDEBUG)
		{
			Profiler::getInstance('Application')->mark('afterRenderModule ' . $module->module . ' (' . $module->title . ')');
		}

		return $module->content;
	}
	
	/**
	 * Render the module content.
	 *
	 * @param   object    $module   A module object
	 * @param   Registry  $params   A module parameters
	 * @param   array     $attribs  An array of attributes for the module (probably from the XML).
	 *
	 * @return  string
	 *
	 * @since   4.0.0
	 */
	public static function renderRawModule($module, Registry $params, $attribs = array())
	{
		if (!empty($module->contentRendered))
		{
			return $module->content;
		}

		if (JDEBUG)
		{
			Profiler::getInstance('Application')->mark('beforeRenderModule ' . $module->module . ' (' . $module->title . ')');
		}

		$app = Factory::getApplication();

		// Record the scope.
		$scope = $app->scope;

		// Set scope to component name
		$app->scope = $module->module;
		
		if(version_compare(JVERSION, '4.0', 'ge')){

			$dispatcher = $app->bootModule($module->module, $app->getName())->getDispatcher($module, $app);

			// Check if we have a dispatcher
			if ($dispatcher)
			{
				ob_start();
				$dispatcher->dispatch();
				$module->content = ob_get_clean();
			}

		}else{
			// Get module path
			$module->module = preg_replace('/[^A-Z0-9_\.-]/i', '', $module->module);
			$path = JPATH_BASE . '/modules/' . $module->module . '/' . $module->module . '.php';

			// Load the module
			if (file_exists($path))
			{
				$lang = Factory::getLanguage();

				$coreLanguageDirectory      = JPATH_BASE;
				$extensionLanguageDirectory = dirname($path);

				$langPaths = $lang->getPaths();

				// Only load the module's language file if it hasn't been already
				if (!$langPaths || (!isset($langPaths[$coreLanguageDirectory]) && !isset($langPaths[$extensionLanguageDirectory])))
				{
					// 1.5 or Core then 1.6 3PD
					$lang->load($module->module, $coreLanguageDirectory, null, false, true) ||
						$lang->load($module->module, $extensionLanguageDirectory, null, false, true);
				}

				$content = '';
				ob_start();
				include $path;
				$module->content = ob_get_contents() . $content;
				ob_end_clean();
			}
		}
		// Add the flag that the module content has been rendered
		$module->contentRendered = true;

		// Revert the scope
		$app->scope = $scope;

		if (JDEBUG)
		{
			Profiler::getInstance('Application')->mark('afterRenderRawModule ' . $module->module . ' (' . $module->title . ')');
		}

		return $module->content;
	}
	/**
	 * Get the path to a layout for a module
	 *
	 * @param   string  $module  The name of the module
	 * @param   string  $layout  The name of the module layout. If alternative layout, in the form template:filename.
	 *
	 * @return  string  The path to the module layout
	 *
	 * @since   1.5
	 */
	public static function getLayoutPath($module, $layout = 'default')
	{
		$template = Factory::getApplication()->getTemplate();
		$defaultLayout = $layout;

		if (strpos($layout, ':') !== false)
		{
			// Get the template and file name from the string
			$temp = explode(':', $layout);
			$template = $temp[0] === '_' ? $template : $temp[0];
			$layout = $temp[1];
			$defaultLayout = $temp[1] ?: 'default';
		}

		// T3
		// Do 3rd party stuff to detect layout path for the module
		// onGetLayoutPath should return the path to the $layout of $module or false
		// $results holds an array of results returned from plugins, 1 from each plugin.
		// if a path to the $layout is found and it is a file, return that path
		$app	= Factory::getApplication();
		$result = $app->triggerEvent( 'onGetLayoutPath', array( $module, $layout ) );
		if (is_array($result))
		{
			foreach ($result as $path)
			{
				if ($path !== false && is_file ($path))
				{
					return $path;
				}
			}
		}
		// /T3

		// Build the template and base path for the layout
		$tPath = JPATH_THEMES . '/' . $template . '/html/' . $module . '/' . $layout . '.php';
		$bPath = JPATH_BASE . '/modules/' . $module . '/tmpl/' . $defaultLayout . '.php';
		$dPath = JPATH_BASE . '/modules/' . $module . '/tmpl/default.php';

		// If the template has a layout override use it
		if (file_exists($tPath))
		{
			return $tPath;
		}

		if (file_exists($bPath))
		{
			return $bPath;
		}

		return $dPath;
	}
}
joomla4/Pagination.php000060400000013615152455303030010715 0ustar00<?php
/**
 * Joomla! Content Management System
 *
 * @copyright  Copyright (C) 2005 - 2017 Open Source Matters, Inc. All rights reserved.
 * @license    GNU General Public License version 2 or later; see LICENSE.txt
 */

namespace Joomla\CMS\Pagination;

defined('JPATH_PLATFORM') or die;


// Make alias of original FileLayout
\T3::makeAlias(JPATH_LIBRARIES . '/src/Pagination/Pagination.php', 'Pagination', '_Pagination');

/**
 * Pagination Class. Provides a common interface for content pagination for the Joomla! CMS.
 *
 * @since  1.5
 */
class Pagination extends _Pagination
{

	/**
	 * Create and return the pagination page list string, ie. Previous, Next, 1 2 3 ... x.
	 *
	 * @return  string  Pagination page list string.
	 *
	 * @since   1.5
	 */
	public function getPagesLinks()
	{
		// Build the page navigation list.
		$data = $this->_buildDataObject();

		$list           = array();
		$list['prefix'] = $this->prefix;

		$itemOverride = false;
		$listOverride = false;

		// $chromePath = JPATH_THEMES . '/' . $this->app->getTemplate() . '/html/pagination.php';
		// T3: detect if chrome pagination.php in template or in plugin
		$chromePath = \T3Path::getPath ('html/pagination.php');

		if (file_exists($chromePath))
		{
			include_once $chromePath;

			/*
			 * @deprecated 4.0 Item rendering should use a layout
			 */
			if (function_exists('pagination_item_active') && function_exists('pagination_item_inactive'))
			{
				\JLog::add(
					'pagination_item_active and pagination_item_inactive are deprecated. Use the layout joomla.pagination.link instead.',
					\JLog::WARNING,
					'deprecated'
				);

				$itemOverride = true;
			}

			/*
			 * @deprecated 4.0 The list rendering is now a layout.
			 * @see Pagination::_list_render()
			 */
			if (function_exists('pagination_list_render'))
			{
				\JLog::add('pagination_list_render is deprecated. Use the layout joomla.pagination.list instead.', \JLog::WARNING, 'deprecated');
				$listOverride = true;
			}
		}

		// Build the select list
		if ($data->all->base !== null)
		{
			$list['all']['active'] = true;
			$list['all']['data']   = $itemOverride ? pagination_item_active($data->all) : $this->_item_active($data->all);
		}
		else
		{
			$list['all']['active'] = false;
			$list['all']['data']   = $itemOverride ? pagination_item_inactive($data->all) : $this->_item_inactive($data->all);
		}

		if ($data->start->base !== null)
		{
			$list['start']['active'] = true;
			$list['start']['data']   = $itemOverride ? pagination_item_active($data->start) : $this->_item_active($data->start);
		}
		else
		{
			$list['start']['active'] = false;
			$list['start']['data']   = $itemOverride ? pagination_item_inactive($data->start) : $this->_item_inactive($data->start);
		}

		if ($data->previous->base !== null)
		{
			$list['previous']['active'] = true;
			$list['previous']['data']   = $itemOverride ? pagination_item_active($data->previous) : $this->_item_active($data->previous);
		}
		else
		{
			$list['previous']['active'] = false;
			$list['previous']['data']   = $itemOverride ? pagination_item_inactive($data->previous) : $this->_item_inactive($data->previous);
		}

		// Make sure it exists
		$list['pages'] = array();

		foreach ($data->pages as $i => $page)
		{
			if ($page->base !== null)
			{
				$list['pages'][$i]['active'] = true;
				$list['pages'][$i]['data']   = $itemOverride ? pagination_item_active($page) : $this->_item_active($page);
			}
			else
			{
				$list['pages'][$i]['active'] = false;
				$list['pages'][$i]['data']   = $itemOverride ? pagination_item_inactive($page) : $this->_item_inactive($page);
			}
		}

		if ($data->next->base !== null)
		{
			$list['next']['active'] = true;
			$list['next']['data']   = $itemOverride ? pagination_item_active($data->next) : $this->_item_active($data->next);
		}
		else
		{
			$list['next']['active'] = false;
			$list['next']['data']   = $itemOverride ? pagination_item_inactive($data->next) : $this->_item_inactive($data->next);
		}

		if ($data->end->base !== null)
		{
			$list['end']['active'] = true;
			$list['end']['data']   = $itemOverride ? pagination_item_active($data->end) : $this->_item_active($data->end);
		}
		else
		{
			$list['end']['active'] = false;
			$list['end']['data']   = $itemOverride ? pagination_item_inactive($data->end) : $this->_item_inactive($data->end);
		}

		if ($this->total > $this->limit)
		{
			return $listOverride ? pagination_list_render($list) : $this->_list_render($list);
		}
		else
		{
			return '';
		}
	}

	/**
	 * Return the pagination footer.
	 *
	 * @return  string  Pagination footer.
	 *
	 * @since   1.5
	 */
	public function getListFooter()
	{
		// Keep B/C for overrides done with chromes
		// $chromePath = JPATH_THEMES . '/' . $this->app->getTemplate() . '/html/pagination.php';
		// T3: detect if chrome pagination.php in template or in plugin
		$chromePath = \T3Path::getPath ('html/pagination.php');

		if (file_exists($chromePath))
		{
			include_once $chromePath;

			if (function_exists('pagination_list_footer'))
			{
				\JLog::add('pagination_list_footer is deprecated. Use the layout joomla.pagination.links instead.', \JLog::WARNING, 'deprecated');

				$list = array(
					'prefix'       => $this->prefix,
					'limit'        => $this->limit,
					'limitstart'   => $this->limitstart,
					'total'        => $this->total,
					'limitfield'   => $this->getLimitBox(),
					'pagescounter' => $this->getPagesCounter(),
					'pageslinks'   => $this->getPagesLinks(),
				);

				return pagination_list_footer($list);
			}
		}

		return $this->getPaginationLinks();
	}



	/**
	 * Compatible with J3
	 */
	public function get($property, $default = null)
	{
		\JLog::add('Pagination::get() is deprecated. Access the properties directly.', \JLog::WARNING, 'deprecated');

		if (strpos($property, '.'))
		{
			$prop     = explode('.', $property);
			$prop[1]  = ucfirst($prop[1]);
			$property = implode($prop);
		}

		if (isset($this->$property))
		{
			return $this->$property;
		}

		return $default;
	}
}
joomla4/FileLayout.php000060400000004722152455303030010700 0ustar00<?php
/**
 * Joomla! Content Management System
 *
 * @copyright  Copyright (C) 2005 - 2017 Open Source Matters, Inc. All rights reserved.
 * @license    GNU General Public License version 2 or later; see LICENSE.txt
 */

namespace Joomla\CMS\Layout;

use Joomla\CMS\Factory;

defined('JPATH_PLATFORM') or die;

// Make alias of original FileLayout
\T3::makeAlias(JPATH_LIBRARIES . '/src/Layout/FileLayout.php', 'FileLayout', '_FileLayout');

/**
 * Base class for rendering a display layout
 * loaded from from a layout file
 *
 * @link   https://docs.joomla.org/Special:MyLanguage/Sharing_layouts_across_views_or_extensions_with_JLayout
 * @since  3.0
 */
class FileLayout extends _FileLayout
{

	/**
	 * Get the default array of include paths
	 *
	 * @return  array
	 *
	 * @since   3.5
	 */
	public function getDefaultIncludePaths()
	{
		// Get the template
		$template = Factory::getApplication()->getTemplate(true);

		// Reset includePaths
		$paths = array();

		// (1 - highest priority) Received a custom high priority path
		if ($this->basePath !== null)
		{
			$paths[] = rtrim($this->basePath, DIRECTORY_SEPARATOR);
		}

		// Component layouts & overrides if exist
		$component = $this->options->get('component', null);

		if (!empty($component))
		{
			// (2) Component template overrides path
			$paths[] = JPATH_THEMES . '/' . $template->template . '/html/layouts/' . $component;

			if (!empty($template->parent))
			{
				// (2.a) Component template overrides path for an inherited template using the parent
				$paths[] = JPATH_THEMES . '/' . $template->parent . '/html/layouts/' . $component;
			}

			// (3) Component path
			if ($this->options->get('client') == 0)
			{
				$paths[] = JPATH_SITE . '/components/' . $component . '/layouts';
			}
			else
			{
				$paths[] = JPATH_ADMINISTRATOR . '/components/' . $component . '/layouts';
			}
		}

		// T3 - (4.1) - user custom layout overridden
		if (!defined('T3_LOCAL_DISABLED')) $paths[] = T3_LOCAL_PATH . '/html/layouts';

		// (4) Standard Joomla! layouts overridden
		$paths[] = JPATH_THEMES . '/' . $template->template . '/html/layouts';

		if (!empty($template->parent))
		{
			// (4.a) Component template overrides path for an inherited template using the parent
			$paths[] = JPATH_THEMES . '/' . $template->parent . '/html/layouts';
		}

		// T3 - (5.1) - T3 base layout overridden
		$paths[] = T3_PATH . '/html/layouts';

		// (5 - lower priority) Frontend base layouts
		$paths[] = JPATH_ROOT . '/layouts';

		return $paths;
	}

}
joomla4/HtmlView.php000060400000004222152455303030010355 0ustar00<?php
/**
 * Joomla! Content Management System
 *
 * @copyright  Copyright (C) 2005 - 2017 Open Source Matters, Inc. All rights reserved.
 * @license    GNU General Public License version 2 or later; see LICENSE.txt
 */

namespace Joomla\CMS\MVC\View;

use Joomla\CMS\Application\ApplicationHelper;
use Joomla\CMS\Factory;
use Joomla\CMS\Filesystem\Path;

defined('JPATH_PLATFORM') or die;


// Make alias of original FileLayout
\T3::makeAlias(JPATH_LIBRARIES . '/src/MVC/View/HtmlView.php', 'HtmlView', '_JHtmlView');


/**
 * Base class for a Joomla View
 *
 * Class holding methods for displaying presentation data.
 *
 * @since  2.5.5
 */
class HtmlView extends _JHtmlView
{

	/**
	 * Sets an entire array of search paths for templates or resources.
	 *
	 * @param   string  $type  The type of path to set, typically 'template'.
	 * @param   mixed   $path  The new search path, or an array of search paths.  If null or false, resets to the current directory only.
	 *
	 * @return  void
	 *
	 * @since   3.0
	 */
	protected function _setPath($type, $path)
	{
		$component = ApplicationHelper::getComponentName();
		$app = Factory::getApplication();

		// Clear out the prior search dirs
		$this->_path[$type] = array();

		// Actually add the user-specified directories
		$this->_addPath($type, $path);

		// Always add the fallback directories as last resort
		switch (strtolower($type))
		{
			case 'template':
				// Set the alternative template search dir
				if (isset($app))
				{
					$component = preg_replace('/[^A-Z0-9_\.-]/i', '', $component);

					//if it is T3 template, update search path for template
					$this->_addPath('template', T3_PATH . '/html/' . $component . '/' . $this->getName());
					if (\T3::isAdmin()) $this->_addPath('template', T3_ADMIN_PATH . '/admin/html/' . $component . '/' . $this->getName());

					$fallback = JPATH_THEMES . '/' . $app->getTemplate() . '/html/' . $component . '/' . $this->getName();
					$this->_addPath('template', $fallback);

					//search path for user custom folder
					if (!defined('T3_LOCAL_DISABLED')) $this->_addPath('template', T3_LOCAL_PATH . '/html/' . $component . '/' . $this->getName());
				}
				break;
		}
	}


}
minify/csscompressor.php000060400000020101152455303030011443 0ustar00<?php
/**
 * Class Minify_CSS_Compressor 
 * @package Minify
 */

/**
 * Compress CSS
 *
 * This is a heavy regex-based removal of whitespace, unnecessary
 * comments and tokens, and some CSS value minimization, where practical.
 * Many steps have been taken to avoid breaking comment-based hacks, 
 * including the ie5/mac filter (and its inversion), but expect tricky
 * hacks involving comment tokens in 'content' value strings to break
 * minimization badly. A test suite is available.
 * 
 * @package Minify
 * @author Stephen Clay <steve@mrclay.org>
 * @author http://code.google.com/u/1stvamp/ (Issue 64 patch)
 */
class Minify_CSS_Compressor {

    /**
     * Minify a CSS string
     * 
     * @param string $css
     * 
     * @param array $options (currently ignored)
     * 
     * @return string
     */
    public static function process($css, $options = array())
    {
        $obj = new Minify_CSS_Compressor($options);
        return $obj->_process($css);
    }
    
    /**
     * @var array
     */
    protected $_options = null;
    
    /**
     * Are we "in" a hack? I.e. are some browsers targetted until the next comment?
     *
     * @var bool
     */
    protected $_inHack = false;
    
    
    /**
     * Constructor
     * 
     * @param array $options (currently ignored)
     */
    private function __construct($options) {
        $this->_options = $options;
    }
    
    /**
     * Minify a CSS string
     * 
     * @param string $css
     * 
     * @return string
     */
    protected function _process($css)
    {
        $css = str_replace("\r\n", "\n", $css);
        
        // preserve empty comment after '>'
        // http://www.webdevout.net/css-hacks#in_css-selectors
        $css = preg_replace('@>/\\*\\s*\\*/@', '>/*keep*/', $css);
        
        // preserve empty comment between property and value
        // http://css-discuss.incutio.com/?page=BoxModelHack
        $css = preg_replace('@/\\*\\s*\\*/\\s*:@', '/*keep*/:', $css);
        $css = preg_replace('@:\\s*/\\*\\s*\\*/@', ':/*keep*/', $css);
        
        // apply callback to all valid comments (and strip out surrounding ws
        $css = preg_replace_callback('@\\s*/\\*([\\s\\S]*?)\\*/\\s*@'
            ,array($this, '_commentCB'), $css);

        // remove ws around { } and last semicolon in declaration block
        $css = preg_replace('/\\s*{\\s*/', '{', $css);
        $css = preg_replace('/;?\\s*}\\s*/', '}', $css);
        
        // remove ws surrounding semicolons
        $css = preg_replace('/\\s*;\\s*/', ';', $css);
        
        // remove ws around urls
        $css = preg_replace('/
                url\\(      # url(
                \\s*
                ([^\\)]+?)  # 1 = the URL (really just a bunch of non right parenthesis)
                \\s*
                \\)         # )
            /x', 'url($1)', $css);
        
        // remove ws between rules and colons
        $css = preg_replace('/
                \\s*
                ([{;])              # 1 = beginning of block or rule separator 
                \\s*
                ([\\*_]?[\\w\\-]+)  # 2 = property (and maybe IE filter)
                \\s*
                :
                \\s*
                (\\b|[#\'"-])        # 3 = first character of a value
            /x', '$1$2:$3', $css);
        
        // remove ws in selectors
        $css = preg_replace_callback('/
                (?:              # non-capture
                    \\s*
                    [^~>+,\\s]+  # selector part
                    \\s*
                    [,>+~]       # combinators
                )+
                \\s*
                [^~>+,\\s]+      # selector part
                {                # open declaration block
            /x'
            ,array($this, '_selectorsCB'), $css);
        
        // minimize hex colors
        $css = preg_replace('/([^=])#([a-f\\d])\\2([a-f\\d])\\3([a-f\\d])\\4([\\s;\\}])/i'
            , '$1#$2$3$4$5', $css);
        
        // remove spaces between font families
        $css = preg_replace_callback('/font-family:([^;}]+)([;}])/'
            ,array($this, '_fontFamilyCB'), $css);
        
        $css = preg_replace('/@import\\s+url/', '@import url', $css);
        
        // replace any ws involving newlines with a single newline
        $css = preg_replace('/[ \\t]*\\n+\\s*/', "\n", $css);
        
        // separate common descendent selectors w/ newlines (to limit line lengths)
        $css = preg_replace('/([\\w#\\.\\*]+)\\s+([\\w#\\.\\*]+){/', "$1\n$2{", $css);
        
        // Use newline after 1st numeric value (to limit line lengths).
        $css = preg_replace('/
            ((?:padding|margin|border|outline):\\d+(?:px|em)?) # 1 = prop : 1st numeric value
            \\s+
            /x'
            ,"$1\n", $css);
        
        // prevent triggering IE6 bug: http://www.crankygeek.com/ie6pebug/
        $css = preg_replace('/:first-l(etter|ine)\\{/', ':first-l$1 {', $css);
            
        return trim($css);
    }
    
    /**
     * Replace what looks like a set of selectors  
     *
     * @param array $m regex matches
     * 
     * @return string
     */
    protected function _selectorsCB($m)
    {
        // remove ws around the combinators
        return preg_replace('/\\s*([,>+~])\\s*/', '$1', $m[0]);
    }
    
    /**
     * Process a comment and return a replacement
     * 
     * @param array $m regex matches
     * 
     * @return string
     */
    protected function _commentCB($m)
    {
        $hasSurroundingWs = (trim($m[0]) !== $m[1]);
        $m = $m[1]; 
        // $m is the comment content w/o the surrounding tokens, 
        // but the return value will replace the entire comment.
        if ($m === 'keep') {
            return '/**/';
        }
        if ($m === '" "') {
            // component of http://tantek.com/CSS/Examples/midpass.html
            return '/*" "*/';
        }
        if (preg_match('@";\\}\\s*\\}/\\*\\s+@', $m)) {
            // component of http://tantek.com/CSS/Examples/midpass.html
            return '/*";}}/* */';
        }
        if ($this->_inHack) {
            // inversion: feeding only to one browser
            if (preg_match('@
                    ^/               # comment started like /*/
                    \\s*
                    (\\S[\\s\\S]+?)  # has at least some non-ws content
                    \\s*
                    /\\*             # ends like /*/ or /**/
                @x', $m, $n)) {
                // end hack mode after this comment, but preserve the hack and comment content
                $this->_inHack = false;
                return "/*/{$n[1]}/**/";
            }
        }
        if (substr($m, -1) === '\\') { // comment ends like \*/
            // begin hack mode and preserve hack
            $this->_inHack = true;
            return '/*\\*/';
        }
        if ($m !== '' && $m[0] === '/') { // comment looks like /*/ foo */
            // begin hack mode and preserve hack
            $this->_inHack = true;
            return '/*/*/';
        }
        if ($this->_inHack) {
            // a regular comment ends hack mode but should be preserved
            $this->_inHack = false;
            return '/**/';
        }
        // Issue 107: if there's any surrounding whitespace, it may be important, so 
        // replace the comment with a single space
        return $hasSurroundingWs // remove all other comments
            ? ' '
            : '';
    }
    
    /**
     * Process a font-family listing and return a replacement
     * 
     * @param array $m regex matches
     * 
     * @return string   
     */
    protected function _fontFamilyCB($m)
    {
        // Issue 210: must not eliminate WS between words in unquoted families
        $pieces = preg_split('/(\'[^\']+\'|"[^"]+")/', $m[1], null, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
        $out = 'font-family:';
        while (null !== ($piece = array_shift($pieces))) {
            if ($piece[0] !== '"' && $piece[0] !== "'") {
                $piece = preg_replace('/\\s+/', ' ', $piece);
                $piece = preg_replace('/\\s?,\\s?/', ',', $piece);
            }
            $out .= $piece;
        }
        return $out . $m[2];
    }
}
minify/closurecompiler.php000060400000011327152455303030011757 0ustar00<?php
/**
 * Class Minify_JS_ClosureCompiler
 * @package Minify
 */

/**
 * Minify Javascript using Google's Closure Compiler API
 *
 * @link http://code.google.com/closure/compiler/
 * @package Minify
 * @author Stephen Clay <steve@mrclay.org>
 *
 * @todo can use a stream wrapper to unit test this?
 */
class Minify_JS_ClosureCompiler {
    const URL = 'http://closure-compiler.appspot.com/compile';

    /**
     * Minify Javascript code via HTTP request to the Closure Compiler API
     *
     * @param string $js input code
     * @param array $options unused at this point
     * @return string
     */
    public static function minify($js, array $options = array())
    {
        $obj = new self($options);
        return $obj->min($js);
    }

    /**
     *
     * @param array $options
     *
     * fallbackFunc : default array($this, 'fallback');
     */
    public function __construct(array $options = array())
    {
        $this->_fallbackFunc = isset($options['fallbackMinifier'])
            ? $options['fallbackMinifier']
            : array($this, '_fallback');
    }

    public function min($js)
    {
        $postBody = $this->_buildPostBody($js);
        $bytes = (function_exists('mb_strlen') && ((int)ini_get('mbstring.func_overload') & 2))
            ? mb_strlen($postBody, '8bit')
            : strlen($postBody);
        if ($bytes > 200000) {
            //T3 Framework
            //instead of throwing error, we use fall back option
            if (is_callable($this->_fallbackFunc)) {
                $response = "/*\n(Using fallback minifier)\n*/\n";
                $response .= call_user_func($this->_fallbackFunc, $js);
            } else {
                throw new Minify_JS_ClosureCompiler_Exception(
                    'POST content larger than 200000 bytes'
                );
            }
        }
        $response = $this->_getResponse($postBody);
        if (preg_match('/^Error\(\d\d?\):/', $response)) {
            if (is_callable($this->_fallbackFunc)) {
                $response = "/* Received errors from Closure Compiler API:\n$response"
                          . "\n(Using fallback minifier)\n*/\n";
                $response .= call_user_func($this->_fallbackFunc, $js);
            } else {
                throw new Minify_JS_ClosureCompiler_Exception($response);
            }
        }
        if ($response === '') {
            $errors = $this->_getResponse($this->_buildPostBody($js, true));
            throw new Minify_JS_ClosureCompiler_Exception($errors);
        }
        return $response;
    }

    protected $_fallbackFunc = null;

    protected function _getResponse($postBody)
    {
        $allowUrlFopen = preg_match('/1|yes|on|true/i', ini_get('allow_url_fopen'));
        if ($allowUrlFopen) {
            $contents = file_get_contents(self::URL, false, stream_context_create(array(
                'http' => array(
                    'method' => 'POST',
                    'header' => "Content-type: application/x-www-form-urlencoded\r\nConnection: close\r\n",
                    'content' => $postBody,
                    'max_redirects' => 0,
                    'timeout' => 15,
                )
            )));
        } elseif (defined('CURLOPT_POST')) {
            $ch = curl_init(self::URL);
            curl_setopt($ch, CURLOPT_POST, true);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-type: application/x-www-form-urlencoded'));
            curl_setopt($ch, CURLOPT_POSTFIELDS, $postBody);
            curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);
            curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 15);
            $contents = curl_exec($ch);
            curl_close($ch);
        } else {
            throw new Minify_JS_ClosureCompiler_Exception(
               "Could not make HTTP request: allow_url_open is false and cURL not available"
            );
        }
        if (false === $contents) {
            throw new Minify_JS_ClosureCompiler_Exception(
               "No HTTP response from server"
            );
        }
        return trim($contents);
    }

    protected function _buildPostBody($js, $returnErrors = false)
    {
        return http_build_query(array(
            'js_code' => $js,
            'output_info' => ($returnErrors ? 'errors' : 'compiled_code'),
            'output_format' => 'text',
            'compilation_level' => 'SIMPLE_OPTIMIZATIONS'
        ), null, '&');
    }

    /**
     * Default fallback function if CC API fails
     * @param string $js
     * @return string
     */
    protected function _fallback($js)
    {
        //T3 Framework
        T3::import('minify/jsmin');
        return JSMin::minify($js);
    }
}

class Minify_JS_ClosureCompiler_Exception extends Exception {}
minify/jsmin.php000060400000036261152455303030007674 0ustar00<?php
/**
 * JSMin.php - modified PHP implementation of Douglas Crockford's JSMin.
 *
 * <code>
 * $minifiedJs = JSMin::minify($js);
 * </code>
 *
 * This is a modified port of jsmin.c. Improvements:
 *
 * Does not choke on some regexp literals containing quote characters. E.g. /'/
 *
 * Spaces are preserved after some add/sub operators, so they are not mistakenly
 * converted to post-inc/dec. E.g. a + ++b -> a+ ++b
 *
 * Preserves multi-line comments that begin with /*!
 *
 * PHP 5 or higher is required.
 *
 * Permission is hereby granted to use this version of the library under the
 * same terms as jsmin.c, which has the following license:
 *
 * --
 * Copyright (c) 2002 Douglas Crockford  (www.crockford.com)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
 * of the Software, and to permit persons to whom the Software is furnished to do
 * so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * The Software shall be used for Good, not Evil.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 * --
 *
 * @package JSMin
 * @author Ryan Grove <ryan@wonko.com> (PHP port)
 * @author Steve Clay <steve@mrclay.org> (modifications + cleanup)
 * @author Andrea Giammarchi <http://www.3site.eu> (spaceBeforeRegExp)
 * @copyright 2002 Douglas Crockford <douglas@crockford.com> (jsmin.c)
 * @copyright 2008 Ryan Grove <ryan@wonko.com> (PHP port)
 * @license http://opensource.org/licenses/mit-license.php MIT License
 * @link http://code.google.com/p/jsmin-php/
 */

class JSMin {
    const ORD_LF            = 10;
    const ORD_SPACE         = 32;
    const ACTION_KEEP_A     = 1;
    const ACTION_DELETE_A   = 2;
    const ACTION_DELETE_A_B = 3;

    protected $a           = "\n";
    protected $b           = '';
    protected $input       = '';
    protected $inputIndex  = 0;
    protected $inputLength = 0;
    protected $lookAhead   = null;
    protected $output      = '';
    protected $lastByteOut  = '';
    protected $keptComment = '';

    /**
     * Minify Javascript.
     *
     * @param string $js Javascript to be minified
     *
     * @return string
     */
    public static function minify($js)
    {
        $jsmin = new JSMin($js);
        return $jsmin->min();
    }

    /**
     * @param string $input
     */
    public function __construct($input)
    {
        $this->input = $input;
    }

    /**
     * Perform minification, return result
     *
     * @return string
     */
    public function min()
    {
        if ($this->output !== '') { // min already run
            return $this->output;
        }

        $mbIntEnc = null;
        if (function_exists('mb_strlen') && ((int)ini_get('mbstring.func_overload') & 2)) {
            $mbIntEnc = mb_internal_encoding();
            mb_internal_encoding('8bit');
        }
        $this->input = str_replace("\r\n", "\n", $this->input);
        $this->inputLength = strlen($this->input);

        $this->action(self::ACTION_DELETE_A_B);

        while ($this->a !== null) {
            // determine next command
            $command = self::ACTION_KEEP_A; // default
            if ($this->a === ' ') {
                if (($this->lastByteOut === '+' || $this->lastByteOut === '-')
                        && ($this->b === $this->lastByteOut)) {
                    // Don't delete this space. If we do, the addition/subtraction
                    // could be parsed as a post-increment
                } elseif (! $this->isAlphaNum($this->b)) {
                    $command = self::ACTION_DELETE_A;
                }
            } elseif ($this->a === "\n") {
                if ($this->b === ' ') {
                    $command = self::ACTION_DELETE_A_B;

                    // in case of mbstring.func_overload & 2, must check for null b,
                    // otherwise mb_strpos will give WARNING
                } elseif ($this->b === null
                          || (false === strpos('{[(+-!~', $this->b)
                              && ! $this->isAlphaNum($this->b))) {
                    $command = self::ACTION_DELETE_A;
                }
            } elseif (! $this->isAlphaNum($this->a)) {
                if ($this->b === ' '
                    || ($this->b === "\n"
                        && (false === strpos('}])+-"\'', $this->a)))) {
                    $command = self::ACTION_DELETE_A_B;
                }
            }
            $this->action($command);
        }
        $this->output = trim($this->output);

        if ($mbIntEnc !== null) {
            mb_internal_encoding($mbIntEnc);
        }
        return $this->output;
    }

    /**
     * ACTION_KEEP_A = Output A. Copy B to A. Get the next B.
     * ACTION_DELETE_A = Copy B to A. Get the next B.
     * ACTION_DELETE_A_B = Get the next B.
     *
     * @param int $command
     * @throws JSMin_UnterminatedRegExpException|JSMin_UnterminatedStringException
     */
    protected function action($command)
    {
        // make sure we don't compress "a + ++b" to "a+++b", etc.
        if ($command === self::ACTION_DELETE_A_B
            && $this->b === ' '
            && ($this->a === '+' || $this->a === '-')) {
            // Note: we're at an addition/substraction operator; the inputIndex
            // will certainly be a valid index
            if ($this->input[$this->inputIndex] === $this->a) {
                // This is "+ +" or "- -". Don't delete the space.
                $command = self::ACTION_KEEP_A;
            }
        }

        switch ($command) {
            case self::ACTION_KEEP_A: // 1
                $this->output .= $this->a;

                if ($this->keptComment) {
                    $this->output = rtrim($this->output, "\n");
                    $this->output .= $this->keptComment;
                    $this->keptComment = '';
                }

                $this->lastByteOut = $this->a;

                // fallthrough intentional
            case self::ACTION_DELETE_A: // 2
                $this->a = $this->b;
                if ($this->a === "'" || $this->a === '"') { // string literal
                    $str = $this->a; // in case needed for exception
                    for(;;) {
                        $this->output .= $this->a;
                        $this->lastByteOut = $this->a;

                        $this->a = $this->get();
                        if ($this->a === $this->b) { // end quote
                            break;
                        }
                        if ($this->isEOF($this->a)) {
                            throw new JSMin_UnterminatedStringException(
                                "JSMin: Unterminated String at byte {$this->inputIndex}: {$str}");
                        }
                        $str .= $this->a;
                        if ($this->a === '\\') {
                            $this->output .= $this->a;
                            $this->lastByteOut = $this->a;

                            $this->a       = $this->get();
                            $str .= $this->a;
                        }
                    }
                }

                // fallthrough intentional
            case self::ACTION_DELETE_A_B: // 3
                $this->b = $this->next();
                if ($this->b === '/' && $this->isRegexpLiteral()) {
                    $this->output .= $this->a . $this->b;
                    $pattern = '/'; // keep entire pattern in case we need to report it in the exception
                    for(;;) {
                        $this->a = $this->get();
                        $pattern .= $this->a;
                        if ($this->a === '[') {
                            for(;;) {
                                $this->output .= $this->a;
                                $this->a = $this->get();
                                $pattern .= $this->a;
                                if ($this->a === ']') {
                                    break;
                                }
                                if ($this->a === '\\') {
                                    $this->output .= $this->a;
                                    $this->a = $this->get();
                                    $pattern .= $this->a;
                                }
                                if ($this->isEOF($this->a)) {
                                    throw new JSMin_UnterminatedRegExpException(
                                        "JSMin: Unterminated set in RegExp at byte "
                                            . $this->inputIndex .": {$pattern}");
                                }
                            }
                        }

                        if ($this->a === '/') { // end pattern
                            break; // while (true)
                        } elseif ($this->a === '\\') {
                            $this->output .= $this->a;
                            $this->a = $this->get();
                            $pattern .= $this->a;
                        } elseif ($this->isEOF($this->a)) {
                            throw new JSMin_UnterminatedRegExpException(
                                "JSMin: Unterminated RegExp at byte {$this->inputIndex}: {$pattern}");
                        }
                        $this->output .= $this->a;
                        $this->lastByteOut = $this->a;
                    }
                    $this->b = $this->next();
                }
            // end case ACTION_DELETE_A_B
        }
    }

    /**
     * @return bool
     */
    protected function isRegexpLiteral()
    {
        if (false !== strpos("(,=:[!&|?+-~*{;", $this->a)) {
            // we obviously aren't dividing
            return true;
        }
        if ($this->a === ' ' || $this->a === "\n") {
            $length = strlen($this->output);
            if ($length < 2) { // weird edge case
                return true;
            }
            // you can't divide a keyword
            if (preg_match('/(?:case|else|in|return|typeof)$/', $this->output, $m)) {
                if ($this->output === $m[0]) { // odd but could happen
                    return true;
                }
                // make sure it's a keyword, not end of an identifier
                $charBeforeKeyword = substr($this->output, $length - strlen($m[0]) - 1, 1);
                if (! $this->isAlphaNum($charBeforeKeyword)) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * Return the next character from stdin. Watch out for lookahead. If the character is a control character,
     * translate it to a space or linefeed.
     *
     * @return string
     */
    protected function get()
    {
        $c = $this->lookAhead;
        $this->lookAhead = null;
        if ($c === null) {
            // getc(stdin)
            if ($this->inputIndex < $this->inputLength) {
                $c = $this->input[$this->inputIndex];
                $this->inputIndex += 1;
            } else {
                $c = null;
            }
        }
        if ($c === null || ord($c) >= self::ORD_SPACE || $c === "\n") {
            return $c;
        }
        if ($c === "\r") {
            return "\n";
        }
        return ' ';
    }

    /**
     * Does $a indicate end of input?
     *
     * @param string $a
     * @return bool
     */
    protected function isEOF($a)
    {
        return ord($a) <= self::ORD_LF;
    }

    /**
     * Get next char (without getting it). If is ctrl character, translate to a space or newline.
     *
     * @return string
     */
    protected function peek()
    {
        $this->lookAhead = $this->get();
        return $this->lookAhead;
    }

    /**
     * Return true if the character is a letter, digit, underscore, dollar sign, or non-ASCII character.
     *
     * @param string $c
     *
     * @return bool
     */
    protected function isAlphaNum($c)
    {
        return (preg_match('/^[a-z0-9A-Z_\\$\\\\]$/', $c) || ord($c) > 126);
    }

    /**
     * Consume a single line comment from input (possibly retaining it)
     */
    protected function consumeSingleLineComment()
    {
        $comment = '';
        while (true) {
            $get = $this->get();
            $comment .= $get;
            if (ord($get) <= self::ORD_LF) { // end of line reached
                // if IE conditional comment
                if (preg_match('/^\\/@(?:cc_on|if|elif|else|end)\\b/', $comment)) {
                    $this->keptComment .= "/{$comment}";
                }
                return;
            }
        }
    }

    /**
     * Consume a multiple line comment from input (possibly retaining it)
     *
     * @throws JSMin_UnterminatedCommentException
     */
    protected function consumeMultipleLineComment()
    {
        $this->get();
        $comment = '';
        for(;;) {
            $get = $this->get();
            if ($get === '*') {
                if ($this->peek() === '/') { // end of comment reached
                    $this->get();
                    if (0 === strpos($comment, '!')) {
                        // preserved by YUI Compressor
                        if (!$this->keptComment) {
                            // don't prepend a newline if two comments right after one another
                            $this->keptComment = "\n";
                        }
                        $this->keptComment .= "/*!" . substr($comment, 1) . "*/\n";
                    } else if (preg_match('/^@(?:cc_on|if|elif|else|end)\\b/', $comment)) {
                        // IE conditional
                        $this->keptComment .= "/*{$comment}*/";
                    }
                    return;
                }
            } elseif ($get === null) {
                throw new JSMin_UnterminatedCommentException(
                    "JSMin: Unterminated comment at byte {$this->inputIndex}: /*{$comment}");
            }
            $comment .= $get;
        }
    }

    /**
     * Get the next character, skipping over comments. Some comments may be preserved.
     *
     * @return string
     */
    protected function next()
    {
        $get = $this->get();
        if ($get === '/') {
            switch ($this->peek()) {
                case '/':
                    $this->consumeSingleLineComment();
                    $get = "\n";
                    break;
                case '*':
                    $this->consumeMultipleLineComment();
                    $get = ' ';
                    break;
            }
        }
        return $get;
    }
}

class JSMin_UnterminatedStringException extends Exception {}
class JSMin_UnterminatedCommentException extends Exception {}
class JSMin_UnterminatedRegExpException extends Exception {}
jacssjanus/csslex.php000060400000007446152455303030010731 0ustar00<?php
class CSSLEX {
	private $csslex = array();
	function __construct () {
		$csslex = array();

		$csslex['keyword'] = '(?:\@(?:import|page|media|charset))';

		# nl                      \n|\r\n|\r|\f ; a newline
		$csslex['newline'] = '\n|\r\n|\r|\f';

		# h                       [0-9a-f]      ; a hexadecimal digit
		$csslex['hex'] = '[0-9a-f]';

		# nonascii                [\200-\377]
		$csslex['non_ascii'] = '[\200-\377]';

		# unicode                 \\{h}{1,6}(\r\n|[ \t\r\n\f])?
		$csslex['unicode'] = '(?:(?:\\' . $csslex['hex'] . '{1,6})(?:\r\n|[ \t\r\n\f])?)';

		# escape                  {unicode}|\\[^\r\n\f0-9a-f]
		$csslex['escape'] = '(?:' . $csslex['unicode'] . '|\\[^\r\n\f0-9a-f])';

		# nmstart                 [_a-z]|{nonascii}|{escape}
		$csslex['nmstart'] = '(?:[_a-z]|' . $csslex['non_ascii'] . '|' . $csslex['escape'] . ')';

		# nmchar                  [_a-z0-9-]|{nonascii}|{escape}
		$csslex['nmchar'] = '(?:[_a-z0-9-]|' . $csslex['non_ascii'] . '|' . $csslex['escape'] . ')';

		# ident                   -?{nmstart}{nmchar}*
		$csslex['ident'] = '-?' . $csslex['nmstart'] . $csslex['nmchar'] . '*';

		# name                    {nmchar}+
		$csslex['name'] = $csslex['nmchar'] . '+';

		# hash
		$csslex['hash'] = '#' . $csslex['name'];

		# string1                 \"([^\n\r\f\\"]|\\{nl}|{escape})*\"  ; "string"
		$csslex['string1'] = '"(?:[^\"\\]|\\.)*"';

		# string2                 \'([^\n\r\f\\']|\\{nl}|{escape})*\'  ; 'string'
		$csslex['string2'] = "'(?:[^\'\\]|\\.)*'";

		# string                  {string1}|{string2}
		$csslex['string'] = '(?:' . $csslex['string1'] . '|' . $csslex['string2'] . ')';

		# num                     [0-9]+|[0-9]*"."[0-9]+
		$csslex['num'] = '(?:[0-9]*\.[0-9]+|[0-9]+)';

		# s                       [ \t\r\n\f]
		$csslex['space'] = '[ \t\r\n\f]';

		# w                       {s}*
		$csslex['whitespace'] = '(?:' . $csslex['space'] . '*)';

		# url special chars
		$csslex['url_special_chars'] = '[!#$%&*-~]';

		# url chars               ({url_special_chars}|{nonascii}|{escape})*
		$csslex['url_chars'] = sprintf('(?:%s|%s|%s)*', $csslex['url_special_chars'], $csslex['non_ascii'], $csslex['escape']);

		# url
		$csslex['url'] = sprintf('url\(%s(%s|%s)%s\)', $csslex['whitespace'], $csslex['string'], $csslex['url_chars'], $csslex['whitespace']);

		# comments
		# see http://www.w3.org/tr/css21/grammar.html
		$csslex['comment'] = '\/\*[^\*]*\*+([^\/\*][^\*]*\*+)*\/';

		# {e}{m}             {return ems;}
		# {e}{x}             {return exs;}
		# {p}{x}             {return length;}
		# {c}{m}             {return length;}
		# {m}{m}             {return length;}
		# {i}{n}             {return length;}
		# {p}{t}             {return length;}
		# {p}{c}             {return length;}
		# {d}{e}{g}          {return angle;}
		# {r}{a}{d}          {return angle;}
		# {g}{r}{a}{d}       {return angle;}
		# {m}{s}             {return time;}
		# {s}                {return time;}
		# {h}{z}             {return freq;}
		# {k}{h}{z}          {return freq;}
		# %                  {return percentage;}
		$csslex['unit'] = '(?:em|ex|px|cm|mm|in|pt|pc|deg|rad|grad|ms|s|hz|khz|%)';

		# {num}{unit|ident}                   {return number;}
		$csslex['quantity'] = sprintf('%s(?:%s%s|%s)?', $csslex['num'], $csslex['whitespace'], $csslex['unit'], $csslex['ident']);

		# "<!--"                  {return cdo;}
		# "-->"                   {return cdc;}
		# "~="                    {return includes;}
		# "|="                    {return dashmatch;}
		# {w}"{"                  {return lbrace;}
		# {w}"+"                  {return plus;}
		# {w}">"                  {return greater;}
		# {w}","                  {return comma;}
		$csslex['punc'] = '<!--|-->|~=|\|=|[\{\+>,:;]';

		$this->csslex = $csslex;
	}

	function __get ($name) {
		return isset($this->csslex[$name]) ? $this->csslex[$name] : null;
	}
}
jacssjanus/test.php000060400000036647152455303030010414 0ustar00<style type="text/css">
.pass {color: green;}
.fail {color: red;}

table.result {
  font-family: verdana,arial,sans-serif;
  font-size:11px;
  color:#333333;
  border-width: 1px;
  border-color: #666666;
  border-collapse: collapse;
}
table.result td {
  border-width: 1px;
  padding: 8px;
  border-style: solid;
  border-color: #666666;
  background-color: #ffffff;
  width: 400px;
}
table.result tr td:first-child {
  border-width: 1px;
  padding: 8px;
  border-style: solid;
  border-color: #666666;
  background-color: #dedede;
  width: 50px;
}

</style>

<?php
require_once 'ja.cssjanus.php';

$test = '';
$testcase = '';
$shouldbe = '';
$swap_ltr_rtl_in_url = False;
$swap_left_right_in_url = False;

function test () {
  global $test, $testcase, $shouldbe, $swap_ltr_rtl_in_url, $swap_left_right_in_url;

  $input = implode ("\n", $testcase);
  $expect = implode ("\n", $shouldbe);
  $output = JACSSJanus::transform ($input, $swap_ltr_rtl_in_url, $swap_left_right_in_url);
  $pass = ($output == $expect);
  $result = $pass ? '<span class="pass">pass</span>' : '<span class="fail">fail</span>';
?>
  <h2 class="<?php echo $pass ? 'pass':'fail' ?>"><?php echo $test ?></h2>
  <table class="result">
    <tr><td>Input</td><td><?php echo str_replace("\n", "<br />\n", $input) ?></td></tr>
    <tr><td>Expect</td><td><?php echo str_replace("\n", "<br />\n", $expect) ?></td></tr>
    <tr><td>Output</td><td><?php echo str_replace("\n", "<br />\n", $output) ?></td></tr>
    <tr><td>Result</td><td><?php echo $result ?></td></tr>
  </table>
  <br /><br />
<?php
}


$test = 'testPreserveComments';
$testcase = array('/* left /* right */left: 10px');
$shouldbe = array('/* left /* right */right: 10px');
test();

$testcase = array('/*left*//*left*/left: 10px');
$shouldbe = array('/*left*//*left*/right: 10px');
test();

$testcase = array('/* Going right is cool */\n#test {left: 10px}');
$shouldbe = array('/* Going right is cool */\n#test {right: 10px}');

$testcase = array('/* padding-right 1 2 3 4 */\n#test {left: 10px}\n/*right*/');
$shouldbe = array('/* padding-right 1 2 3 4 */\n#test {right: 10px}\n/*right*/');
test();

$testcase = array('/** Two line comment\n * left\n \*/\n#test {left: 10px}');
$shouldbe = array('/** Two line comment\n * left\n \*/\n#test {right: 10px}');
test();

$test = 'testPositionAbsoluteOrRelativeValues';
$testcase = array('left: 10px');
$shouldbe = array('right: 10px');
test();


$test = 'testFourNotation';
$testcase = array('padding: .25em 15px 0pt 0ex');
$shouldbe = array('padding: .25em 0ex 0pt 15px');
test();

$testcase = array('margin: 1px -4px 3px 2px');
$shouldbe = array('margin: 1px 2px 3px -4px');
test();

$testcase = array('padding:0 15px .25em 0');
$shouldbe = array('padding:0 0 .25em 15px');
test();

$testcase = array('padding: 1px 4.1grad 3px 2%');
$shouldbe = array('padding: 1px 2% 3px 4.1grad');
test();

$testcase = array('padding: 1px 2px 3px auto');
$shouldbe = array('padding: 1px auto 3px 2px');
test();

$testcase = array('padding: 1px inherit 3px auto');
$shouldbe = array('padding: 1px auto 3px inherit');
test();

# not really four notation
$testcase = array('#settings td p strong');
$shouldbe = $testcase;
test();

$test = 'testThreeNotation';
$testcase = array('margin: 1em 0 .25em');
$shouldbe = array('margin: 1em 0 .25em');
test();

$testcase = array('margin:-1.5em 0 -.75em');
$shouldbe = array('margin:-1.5em 0 -.75em');
test();

$test = 'testTwoNotation';
$testcase = array('padding: 1px 2px');
$shouldbe = array('padding: 1px 2px');
test();

$test = 'testOneNotation';
$testcase = array('padding: 1px');
$shouldbe = array('padding: 1px');
test();

$test = 'testDirection';
# we don't want direction to be changed other than in body
$testcase = array('direction: ltr');
$shouldbe = array('direction: ltr');
test();

# we don't want direction to be changed other than in body
$testcase = array('direction: rtl');
$shouldbe = array('direction: rtl');
test();

# we don't want direction to be changed other than in body
$testcase = array('input { direction: ltr }');
$shouldbe = array('input { direction: ltr }');
test();

$testcase = array('body { direction: ltr }');
$shouldbe = array('body { direction: rtl }');
test();

$testcase = array('body { padding: 10px; direction: ltr; }');
$shouldbe = array('body { padding: 10px; direction: rtl; }');
test();

$testcase = array('body { direction: ltr } .myClass { direction: ltr }');
$shouldbe = array('body { direction: rtl } .myClass { direction: ltr }');
test();

$testcase = array('body{\n direction: ltr\n}');
$shouldbe = array('body{\n direction: rtl\n}');
test();

$test = 'testDoubleDash';
$testcase = array('border-left-color: red');
$shouldbe = array('border-right-color: red');
test();

$testcase = array('border-right-color: red');
$shouldbe = array('border-left-color: red');
test();

# This is for compatibility strength, in reality CSS has no properties
# that are currently like this.
$test = 'testCSSProperty';
$testcase = array('alright: 10px');
$shouldbe = array('alright: 10px');
test();

$testcase = array('alleft: 10px');
$shouldbe = array('alleft: 10px');
test();

$test = 'testFloat';
$testcase = array('float: right');
$shouldbe = array('float: left');
test();

$testcase = array('float: left');
$shouldbe = array('float: right');
test();

$test = 'testUrlWithFlagOff';
$swap_ltr_rtl_in_url = False;
$swap_left_right_in_url = False;

$testcase = array('background: url(/foo/bar-left.png)');
$shouldbe = array('background: url(/foo/bar-left.png)');
test();

$testcase = array('background: url(/foo/left-bar.png)');
$shouldbe = array('background: url(/foo/left-bar.png)');
test();

$testcase = array('url("http://www.blogger.com/img/triangle_ltr.gif")');
$shouldbe = array('url("http://www.blogger.com/img/triangle_ltr.gif")');
test();

$testcase = array("url('http://www.blogger.com/img/triangle_ltr.gif')");
$shouldbe = array("url('http://www.blogger.com/img/triangle_ltr.gif')");
test();

$testcase = array("url('http://www.blogger.com/img/triangle_ltr.gif'  )");
$shouldbe = array("url('http://www.blogger.com/img/triangle_ltr.gif'  )");
test();

$testcase = array('background: url(/foo/bar.left.png)');
$shouldbe = array('background: url(/foo/bar.left.png)');
test();

$testcase = array('background: url(/foo/bar-rtl.png)');
$shouldbe = array('background: url(/foo/bar-rtl.png)');
test();

$testcase = array('background: url(/foo/bar-rtl.png); left: 10px');
$shouldbe = array('background: url(/foo/bar-rtl.png); right: 10px');
test();

$testcase = array('background: url(/foo/bar-right.png); direction: ltr');
$shouldbe = array('background: url(/foo/bar-right.png); direction: ltr');
test();

$testcase = array('background: url(/foo/bar-rtl_right.png);',
          'left:10px; direction: ltr');
$shouldbe = array('background: url(/foo/bar-rtl_right.png);',
          'right:10px; direction: ltr');
test();

$test = 'testUrlWithFlagOn';
$swap_ltr_rtl_in_url = True;
$swap_left_right_in_url = True;

$testcase = array('background: url(/foo/bar-left.png)');
$shouldbe = array('background: url(/foo/bar-right.png)');
test();

$testcase = array('background: url(/foo/left-bar.png)');
$shouldbe = array('background: url(/foo/right-bar.png)');
test();

$testcase = array('url("http://www.blogger.com/img/triangle_ltr.gif")');
$shouldbe = array('url("http://www.blogger.com/img/triangle_rtl.gif")');
test();

$testcase = array("url('http://www.blogger.com/img/triangle_ltr.gif')");
$shouldbe = array("url('http://www.blogger.com/img/triangle_rtl.gif')");
test();

$testcase = array("url('http://www.blogger.com/img/triangle_ltr.gif'  )");
$shouldbe = array("url('http://www.blogger.com/img/triangle_rtl.gif'  )");
test();

$testcase = array('background: url(/foo/bar.left.png)');
$shouldbe = array('background: url(/foo/bar.right.png)');
test();

$testcase = array('background: url(/foo/bright.png)');
$shouldbe = array('background: url(/foo/bright.png)');
test();

$testcase = array('background: url(/foo/bar-rtl.png)');
$shouldbe = array('background: url(/foo/bar-ltr.png)');
test();

$testcase = array('background: url(/foo/bar-rtl.png); left: 10px');
$shouldbe = array('background: url(/foo/bar-ltr.png); right: 10px');
test();

$testcase = array('background: url(/foo/bar-right.png); direction: ltr');
$shouldbe = array('background: url(/foo/bar-left.png); direction: ltr');
test();

$testcase = array('background: url(/foo/bar-rtl_right.png);',
          'left:10px; direction: ltr');
$shouldbe = array('background: url(/foo/bar-ltr_left.png);',
          'right:10px; direction: ltr');
test();

$test = 'testPadding';
$testcase = array('padding-right: bar');
$shouldbe = array('padding-left: bar');
test();

$testcase = array('padding-left: bar');
$shouldbe = array('padding-right: bar');
test();

$test = 'testMargin';
$testcase = array('margin-left: bar');
$shouldbe = array('margin-right: bar');
test();

$testcase = array('margin-right: bar');
$shouldbe = array('margin-left: bar');
test();

$test = 'testBorder';
$testcase = array('border-left: bar');
$shouldbe = array('border-right: bar');
test();

$testcase = array('border-right: bar');
$shouldbe = array('border-left: bar');
test();

$test = 'testCursor';
$testcase = array('cursor: e-resize');
$shouldbe = array('cursor: w-resize');
test();

$testcase = array('cursor: w-resize');
$shouldbe = array('cursor: e-resize');
test();

$testcase = array('cursor: se-resize');
$shouldbe = array('cursor: sw-resize');
test();

$testcase = array('cursor: sw-resize');
$shouldbe = array('cursor: se-resize');
test();

$testcase = array('cursor: ne-resize');
$shouldbe = array('cursor: nw-resize');
test();

$testcase = array('cursor: nw-resize');
$shouldbe = array('cursor: ne-resize');
test();

$test = 'testBGPosition';
$testcase = array('background: url(/foo/bar.png) top left');
$shouldbe = array('background: url(/foo/bar.png) top right');
test();

$testcase = array('background: url(/foo/bar.png) top right');
$shouldbe = array('background: url(/foo/bar.png) top left');
test();

$testcase = array('background-position: top left');
$shouldbe = array('background-position: top right');
test();

$testcase = array('background-position: top right');
$shouldbe = array('background-position: top left');
test();

$test = 'testBGPositionPercentage';
$testcase = array('background-position: 100% 40%');
$shouldbe = array('background-position: 0% 40%');
test();

$testcase = array('background-position: 0% 40%');
$shouldbe = array('background-position: 100% 40%');
test();

$testcase = array('background-position: 23% 0');
$shouldbe = array('background-position: 77% 0');
test();

$testcase = array('background-position: 23% auto');
$shouldbe = array('background-position: 77% auto');
test();

$testcase = array('background-position-x: 23%');
$shouldbe = array('background-position-x: 77%');
test();

$testcase = array('background-position-y: 23%');
$shouldbe = array('background-position-y: 23%');
test();

$testcase = array('background:url(../foo-bar_baz.2008.gif) no-repeat 75% 50%');
$shouldbe = array('background:url(../foo-bar_baz.2008.gif) no-repeat 25% 50%');
test();

$testcase = array('.test { background: 10% 20% } .test2 { background: 40% 30% }');
$shouldbe = array('.test { background: 90% 20% } .test2 { background: 60% 30% }');
test();

$testcase = array('.test { background: 0% 20% } .test2 { background: 40% 30% }');
$shouldbe = array('.test { background: 100% 20% } .test2 { background: 60% 30% }');
test();

$test = 'testDirectionalClassnames';
/*
"""Makes sure we don't unnecessarily destroy classnames with tokens in them.

Despite the fact that that is a bad classname in CSS, we don't want to
break anybody.
"""
*/
$testcase = array('.column-left { float: left }');
$shouldbe = array('.column-left { float: right }');
test();

$testcase = array('#bright-light { float: left }');
$shouldbe = array('#bright-light { float: right }');
test();

$testcase = array('a.left:hover { float: left }');
$shouldbe = array('a.left:hover { float: right }');
test();

#tests newlines
$testcase = array("#bright-left,\n.test-me { float: left }");
$shouldbe = array("#bright-left,\n.test-me { float: right }");
test();

#tests newlines
$testcase = array("#bright-left,", '.test-me { float: left }');
$shouldbe = array("#bright-left,", '.test-me { float: right }');
test();

#tests multiple names and commas
$testcase = array('div.leftpill, div.leftpillon {margin-right: 0 !important}');
$shouldbe = array('div.leftpill, div.leftpillon {margin-left: 0 !important}');
test();

$testcase = array('div.left > span.right+span.left { float: left }');
$shouldbe = array('div.left > span.right+span.left { float: right }');
test();

$testcase = array('.thisclass .left .myclass {background:#fff;}');
$shouldbe = array('.thisclass .left .myclass {background:#fff;}');
test();

$testcase = array('.thisclass .left .myclass #myid {background:#fff;}');
$shouldbe = array('.thisclass .left .myclass #myid {background:#fff;}');
test();


$test = 'testLongLineWithMultipleDefs';
$testcase = array('body{direction:rtl;float:right}
          .b2{direction:ltr;float:right}');
$shouldbe = array('body{direction:ltr;float:left}
          .b2{direction:ltr;float:left}');
test();

$test = 'testNoFlip';
# """Tests the /* @noflip */ annotation on classnames."""
$testcase = array('/* @noflip */ div { float: left; }');
$shouldbe = array('/* @noflip */ div { float: left; }');
test();

$testcase = array('/* @noflip */ div, .notme { float: left; }');
$shouldbe = array('/* @noflip */ div, .notme { float: left; }');
test();

$testcase = array('/* @noflip */ div { float: left; } div { float: left; }');
$shouldbe = array('/* @noflip */ div { float: left; } div { float: right; }');
test();

$testcase = array('/* @noflip */\ndiv { float: left; }\ndiv { float: left; }');
$shouldbe = array('/* @noflip */\ndiv { float: left; }\ndiv { float: right; }');
test();

# Test @noflip on single rules within classes
$testcase = array('div { float: left; /* @noflip */ float: left; }');
$shouldbe = array('div { float: right; /* @noflip */ float: left; }');
test();

$testcase = array('div\n{ float: left;\n/* @noflip */\n float: left;\n }');
$shouldbe = array('div\n{ float: right;\n/* @noflip */\n float: left;\n }');
test();

$testcase = array('div\n{ float: left;\n/* @noflip */\n text-align: left\n }');
$shouldbe = array('div\n{ float: right;\n/* @noflip */\n text-align: left\n }');
test();

$testcase = array('div\n{ /* @noflip */\ntext-align: left;\nfloat: left\n  }');
$shouldbe = array('div\n{ /* @noflip */\ntext-align: left;\nfloat: right\n  }');
test();

$testcase = array('/* @noflip */div{float:left;text-align:left;}div{float:left}');
$shouldbe = array('/* @noflip */div{float:left;text-align:left;}div{float:right}');
test();

$testcase = array('/* @noflip */','div{float:left;text-align:left;}a{foo:left}');
$shouldbe = array('/* @noflip */','div{float:left;text-align:left;}a{foo:right}');
test();

$test = 'testBorderRadiusNotation';
$testcase = array('border-radius: .25em 15px 0pt 0ex');
$shouldbe = array('border-radius: 15px .25em 0ex 0pt');
test();

$testcase = array('border-radius: 10px 15px 0px');
$shouldbe = array('border-radius: 15px 10px 15px 0px');
test();

$testcase = array('border-radius: 7px 8px');
$shouldbe = array('border-radius: 8px 7px');
test();

$testcase = array('border-radius: 5px');
$shouldbe = array('border-radius: 5px');
test();

$test = 'testGradientNotation';
$testcase = array('background-image: -moz-linear-gradient(#326cc1, #234e8c)');
$shouldbe = array('background-image: -moz-linear-gradient(#326cc1, #234e8c)');
test();

$testcase = array('background-image: -webkit-gradient(linear, 100% 0%, 0% 0%, from(#666666), to(#ffffff))');
$shouldbe = array('background-image: -webkit-gradient(linear, 100% 0%, 0% 0%, from(#666666), to(#ffffff))');
test();
jacssjanus/ja.cssjanus.php000060400000065040152455303030011644 0ustar00<?php
/**
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 * http://www.gnu.org/copyleft/gpl.html
 *
 */

/**
 * This is a rewrite & update version of PHP port of CSSJanus, a utility that transforms CSS style sheets
 * written for LTR to RTL.
 *
 * The original Python version of CSSJanus is Copyright 2008 by Google Inc. and
 * is distributed under the Apache license.
 *
 * The original PHP version of CSSJanus: https://doc.wikimedia.org/mediawiki-core/master/php/html/CSSJanus_8php.html.
 *
 * Original code: http://code.google.com/p/cssjanus/source/browse/trunk/cssjanus.py
 * License of original code: http://code.google.com/p/cssjanus/source/browse/trunk/LICENSE
 * @author Khanh Le
 *
 */
require_once 'csslex.php';

class JACSSJanus {
	// Patterns defined as null are built dynamically by buildPatterns()

	private static $patterns = array(

	);

	public static function getPatterns () {
		self::buildPatterns();
		return self::$patterns;
	}
	/**
	 * Build patterns we can't define above because they depend on other patterns.
	 */
	private static function buildPatterns() {
		//increase the backtrack limit
		@ini_set('pcre.backtrack_limit', '2M');

		if ( isset( self::$patterns['token_delimiter'] ) ) {
			// Patterns have already been built
			return;
		}
		$csslex = new CSSLEX;

		$patterns =& self::$patterns;
		$patterns['token_delimiter'] = '`';
		$patterns['tmp_token'] = sprintf('%sTMP%s', $patterns['token_delimiter'], $patterns['token_delimiter']);
		$patterns['token_lines'] = sprintf('%sj%s', $patterns['token_delimiter'], $patterns['token_delimiter']);

		# global constant text strings for css value matches.
		$patterns['ltr'] = 'ltr';
		$patterns['rtl'] = 'rtl';
		$patterns['left'] = 'left';
		$patterns['right'] = 'right';

		# this is a lookbehind match to ensure that we don't replace instances
		# of our string token (left, rtl, etc...) if there's a letter in front of it.
		# specifically, this prevents replacements like 'background: url(bright.png)'.
		$patterns['lookbehind_not_letter'] = '(?<![a-za-z])';

		# this is a lookahead match to make sure we don't replace left and right
		# in actual classnames, so that we don't break the html/css dependencies.
		# read literally, it says ignore cases where the word left, for instance, is
		# directly followed by valid classname characters and a curly brace.
		# ex: .column-left {float: left} will become .column-left {float: right}
		$patterns['lookahead_not_open_brace'] = sprintf('(?!(?:%s|%s|%s|#|\:|\.|\,|\+|]|=|>)*?(\,|{))',
		                            $csslex->nmchar, $patterns['token_lines'], $csslex->space);


		# these two lookaheads are to test whether or not we are within a
		# background: url(here) situation.
		# ref: http://www.w3.org/tr/css21/syndata.html#uri
		$patterns['valid_after_uri_chars'] = sprintf("[\'\"]?%s", $csslex->whitespace);
		$patterns['lookahead_not_closing_paren'] = sprintf("(?!%s?%s\))", $csslex->url_chars,
		                                                $patterns['valid_after_uri_chars']);
		$patterns['lookahead_for_closing_paren'] = sprintf("(?=%s?%s\))", $csslex->url_chars,
		                                                $patterns['valid_after_uri_chars']);

		# compile a regex to swap left and right values in 4 part notations.
		# we need to match negatives and decimal numeric values.
		# the case of border-radius is extra complex, so we handle it separately below.
		# ex. 'margin: .25em -2px 3px 0' becomes 'margin: .25em 0 3px -2px'.

		$patterns['possibly_negative_quantity'] = sprintf('((?:-?%s)|(?:inherit|auto))', $csslex->quantity);
		$patterns['possibly_negative_quantity_space'] = sprintf('%s%s%s', $patterns['possibly_negative_quantity'],
		                                                $csslex->space,
		                                                $csslex->whitespace);
		$patterns['four_notation_quantity_re'] = sprintf('/%s%s%s%s/i',
		                                        $patterns['possibly_negative_quantity_space'],
		                                        $patterns['possibly_negative_quantity_space'],
		                                        $patterns['possibly_negative_quantity_space'],
		                                        $patterns['possibly_negative_quantity']
		                                       );
		$patterns['color'] = sprintf('(%s|%s)', $csslex->name, $csslex->hash);
		$patterns['color_space'] = sprintf('%s%s', $patterns['color'], $csslex->space);
		$patterns['four_notation_color_re'] = sprintf('/(-color%s:%s)%s%s%s(%s)/i',
		                                     $csslex->whitespace,
		                                     $csslex->whitespace,
		                                     $patterns['color_space'],
		                                     $patterns['color_space'],
		                                     $patterns['color_space'],
		                                     $patterns['color']
		                                    );

		# border-radius is very different from usual 4 part notation: abcd should
		# change to badc (while it would be adcb in normal 4 part notation), abc
		# should change to babc, and ab should change to ba
		$patterns['border_radius_re'] = sprintf('/((?:%s)?)border-radius(%s:%s)'
		                               .'(?:%s)?(?:%s)?(?:%s)?(?:%s)'
		                               .'(?:%s\/%s(?:%s)?(?:%s)?(?:%s)?(?:%s))?/i',$csslex->ident,
		                                                                          $csslex->whitespace,
		                                                                          $csslex->whitespace,
		                                                                          $patterns['possibly_negative_quantity_space'],
		                                                                          $patterns['possibly_negative_quantity_space'],
		                                                                          $patterns['possibly_negative_quantity_space'],
		                                                                          $patterns['possibly_negative_quantity'],
		                                                                          $csslex->whitespace,
		                                                                          $csslex->whitespace,
		                                                                          $patterns['possibly_negative_quantity_space'],
		                                                                          $patterns['possibly_negative_quantity_space'],
		                                                                          $patterns['possibly_negative_quantity_space'],
		                                                                          $patterns['possibly_negative_quantity']
		                              );

		# compile the cursor resize regexes
		$patterns['cursor_east_re'] = '/' . $patterns['lookbehind_not_letter'] . '([ns]?)e-resize/';
		$patterns['cursor_west_re'] = '/' . $patterns['lookbehind_not_letter'] . '([ns]?)w-resize/';

		# matches the condition where we need to replace the horizontal component
		# of a background-position value when expressed in horizontal percentage.
		# had to make two regexes because in the case of position-x there is only
		# one quantity, and otherwise we don't want to match and change cases with only
		# one quantity.
		$patterns['bg_horizontal_percentage_re'] = sprintf('/background(-position)?(%s:%s)'
		                                                   .'([^%%]*?)(%s)%%'
		                                                   .'(%s(?:%s|top|center|bottom))/',
		                                                   $csslex->whitespace,
		                                                   $csslex->whitespace,
		                                                   $csslex->num,
		                                                   $csslex->whitespace,
		                                                   $patterns['possibly_negative_quantity']
		                                                   );

		$patterns['bg_horizontal_percentage_x_re'] = sprintf('/background-position-x(%s:%s)(%s)%%/', $csslex->whitespace,
		                                                       $csslex->whitespace,
		                                                       $csslex->num);

		# non-percentage units used for css lengths
		$patterns['length_unit'] = '(?:em|ex|px|cm|mm|in|pt|pc)';
		# to make sure the lone 0 is not just starting a number (like "02") or a percentage like ("0 %");
		$patterns['lookahead_end_of_zero'] = sprintf('(?![0-9]|%s%%)', $csslex->whitespace);
		# a length with a unit specified. matches "0" too, as it's a length, not a percentage.
		$patterns['length'] = sprintf('(?:-?%s(?:%s%s)|0+%s)', $csslex->num,
		                                    $csslex->whitespace,
		                                    $patterns['length_unit'],
		                                    $patterns['lookahead_end_of_zero']);

		# zero length. used in the replacement functions.
		$patterns['zero_length'] = sprintf('/(?:-?0+(?:%s%s)|0+%s)$/', $csslex->whitespace,
		                                                      $patterns['length_unit'],
		                                                      $patterns['lookahead_end_of_zero']);

		# matches background, background-position, and background-position-x
		# properties when using a css length for its horizontal positioning.
		$patterns['bg_horizontal_length_re'] = sprintf('/background(-position)?(%s:%s)'
		                                      .'((?:.+?%s+)??)(%s)'
		                                      .'((?:%s+)(?:%s|top|center|bottom))/', $csslex->whitespace,
		                                                                            $csslex->whitespace,
		                                                                            $csslex->space,
		                                                                            $patterns['length'],
		                                                                            $csslex->space,
		                                                                            $patterns['possibly_negative_quantity']);

		$patterns['bg_horizontal_length_x_re'] = sprintf('/background-position-x(%s:%s)(%s)/', $csslex->whitespace,
		                                                  $csslex->whitespace,
		                                                  $patterns['length']);

		# matches the opening of a body selector.
		$patterns['body_selector'] = sprintf('body%s{%s', $csslex->whitespace, $csslex->whitespace);

		# matches anything up until the closing of a selector.
		$patterns['chars_within_selector'] = '[^\}]*?';

		# matches the direction property in a selector.
		$patterns['direction_re'] = sprintf('direction%s:%s', $csslex->whitespace, $csslex->whitespace);

		# these allow us to swap "ltr" with "rtl" and vice versa only within the
		# body selector and on the same line.
		$patterns['body_direction_ltr_re'] = sprintf('/(%s)(%s)(%s)(ltr)/i',
		                                    $patterns['body_selector'], 
		                                    $patterns['chars_within_selector'],
		                                    $patterns['direction_re']
		                                   );
		$patterns['body_direction_rtl_re'] = sprintf('/(%s)(%s)(%s)(rtl)/i',
		                                    $patterns['body_selector'],
		                                    $patterns['chars_within_selector'],
		                                    $patterns['direction_re']
		                                   );


		# allows us to swap "direction:ltr" with "direction:rtl" and
		# vice versa anywhere in a line.
		$patterns['direction_ltr_re'] = sprintf('/%s(ltr)/', $patterns['direction_re']);
		$patterns['direction_rtl_re'] = sprintf('/%s(rtl)/', $patterns['direction_re']);

		# we want to be able to switch left with right and vice versa anywhere
		# we encounter left/right strings, except inside the background:url(). the next
		# two regexes are for that purpose. we have alternate in_url versions of the
		# regexes compiled in case the user passes the flag that they do
		# actually want to have left and right swapped inside of background:urls.
		$patterns['left_re'] = sprintf('/%s((?:top|bottom)?)(%s)%s%s/i', $patterns['lookbehind_not_letter'],
		                                                      $patterns['left'],
		                                                      $patterns['lookahead_not_closing_paren'],
		                                                      $patterns['lookahead_not_open_brace']
		                     );
		$patterns['right_re'] = sprintf('/%s((?:top|bottom)?)(%s)%s%s/i', $patterns['lookbehind_not_letter'],
		                                                       $patterns['right'],
		                                                       $patterns['lookahead_not_closing_paren'],
		                                                       $patterns['lookahead_not_open_brace']);
		$patterns['left_in_url_re'] = sprintf('/%s(%s)%s/i', $patterns['lookbehind_not_letter'],
		                                          $patterns['left'],
		                                          $patterns['lookahead_for_closing_paren']);
		$patterns['right_in_url_re'] = sprintf('/%s(%s)%s/i', $patterns['lookbehind_not_letter'],
		                                           $patterns['right'],
		                                           $patterns['lookahead_for_closing_paren']);
		$patterns['ltr_in_url_re'] = sprintf('/%s(%s)%s/i', $patterns['lookbehind_not_letter'],
		                                         $patterns['ltr'],
		                                         $patterns['lookahead_for_closing_paren']);
		$patterns['rtl_in_url_re'] = sprintf('/%s(%s)%s/i', $patterns['lookbehind_not_letter'],
		                                         $patterns['rtl'],
		                                         $patterns['lookahead_for_closing_paren']);

		$patterns['comment_re'] = sprintf('/(%s)/i', $csslex->comment);

		$patterns['noflip_token'] = '\@noflip';
		# the noflip_token inside of a comment. for now, this requires that comments
		# be in the input, which means users of a css compiler would have to run
		# this script first if they want this functionality.
		$patterns['noflip_annotation'] = sprintf('\/\*%s%s%s\*\/', $csslex->whitespace,
		                                       $patterns['noflip_token'],
		                                       $csslex->whitespace);

		# after a noflip_annotation, and within a class selector, we want to be able
		# to set aside a single rule not to be flipped. we can do this by matching
		# our noflip annotation and then using a lookahead to make sure there is not
		# an opening brace before the match.
		$patterns['noflip_single_re'] = sprintf('/(%s%s[^;}]+;?)/i', $patterns['noflip_annotation'],
		                                                   $patterns['lookahead_not_open_brace']);

		# after a noflip_annotation, we want to grab anything up until the next } which
		# means the entire following class block. this will prevent all of its
		# declarations from being flipped.
		$patterns['noflip_class_re'] = sprintf('/(%s%s})/i', $patterns['noflip_annotation'],
		                                           $patterns['chars_within_selector']);

		# border-radis properties and their values
		$patterns['border_radius_tokenizer_re'] = sprintf('/((?:%s)?border-radius%s:[^;}]+;?)/i', $csslex->ident,
		                                                                                $csslex->whitespace);
		$patterns['gradient_re'] = sprintf('/%s[\.-]gradient%s\(/i', $csslex->ident, $csslex->whitespace);

	}

	/**
	 * Transform an LTR stylesheet to RTL
	 * @param $css String: stylesheet to transform
	 * @param $swapLtrRtlInURL Boolean: If true, swap 'ltr' and 'rtl' in URLs
	 * @param $swapLeftRightInURL Boolean: If true, swap 'left' and 'right' in URLs
	 * @return Transformed stylesheet
	 */
	public static function transform( $css, $swapLtrRtlInURL = false, $swapLeftRightInURL = false ) {
		self::buildPatterns();
		// We wrap tokens in ` , not ~ like the original implementation does.
		// This was done because ` is not a legal character in CSS and can only
		// occur in URLs, where we escape it to %60 before inserting our tokens.
		$css = str_replace( self::$patterns['token_delimiter'], '%60', $css );


		// Tokenize single line rules with /* @noflip */
		$noFlipSingle = new CSSJanus_Tokenizer( self::$patterns['noflip_single_re'], '`NOFLIP_SINGLE`' );
		$css = $noFlipSingle->tokenize( $css );

		// Tokenize class rules with /* @noflip */
		$noFlipClass = new CSSJanus_Tokenizer( self::$patterns['noflip_class_re'], '`NOFLIP_CLASS`' );
		$css = $noFlipClass->tokenize( $css );

		// Tokenize comments
		$comments = new CSSJanus_Tokenizer( self::$patterns['comment_re'], '`C`' );
		$css = $comments->tokenize( $css );

	  # Tokenize gradients since we don't want to mirror the values inside
		//$comments = new CSSJanus_Tokenizer( self::$patterns['comment_re']GradientMatcher(), '`GRADIENT`' );
		//$css = $comments->tokenize( $css );

		// LTR->RTL fixes start here
		$css = self::FixBodyDirectionLtrAndRtl( $css );

		if ( $swapLtrRtlInURL ) {
			$css = self::fixLtrRtlInURL( $css );
		}

		if ( $swapLeftRightInURL ) {
			$css = self::fixLeftRightInURL( $css );
		}
		$css = self::fixLeftAndRight( $css );
		$css = self::fixCursorProperties( $css );

		$css = self::fixBorderRadius( $css );
		# Since FourPartNotation conflicts with BorderRadius, we tokenize border-radius properties here.
		$border_radius_tokenizer = new CSSJanus_Tokenizer( self::$patterns['border_radius_tokenizer_re'], '`BORDER_RADIUS`' );
		$css = $border_radius_tokenizer->tokenize( $css );

		$css = self::fixFourPartNotation( $css );

		$css = $border_radius_tokenizer->detokenize( $css );

		$css = self::fixBackgroundPosition( $css );

		// Detokenize stuff we tokenized before
		$css = $comments->detokenize( $css );
		$css = $noFlipClass->detokenize( $css );
		$css = $noFlipSingle->detokenize( $css );

		return $css;
	}

	/**
	 * Replaces ltr with rtl and vice versa ONLY in the body direction.
	 *
	 */
	private static function FixBodyDirectionLtrAndRtl( $css ) {
		$css = preg_replace( self::$patterns['body_direction_ltr_re'], '\1\2\3' . self::$patterns['tmp_token'], $css );
		$css = preg_replace( self::$patterns['body_direction_rtl_re'], '\1\2\3' . self::$patterns['ltr'], $css );
		$css = str_replace( self::$patterns['tmp_token'], self::$patterns['rtl'], $css );

		return $css;
	}

	/**
	 * Flip rules like left: , padding-right: , etc.
	 */
	private static function fixLeftAndRight( $css ) {
		$css = preg_replace( self::$patterns['left_re'], '\1' . self::$patterns['tmp_token'], $css );
		$css = preg_replace( self::$patterns['right_re'], '\1' . self::$patterns['left'], $css );
		$css = str_replace( self::$patterns['tmp_token'], self::$patterns['right'], $css );

		return $css;
	}

	/**
	 * Replace 'left' with 'right' and vice versa in background URLs
	 */
	private static function fixleftrightinurl( $css ) {
		$css = preg_replace( self::$patterns['left_in_url_re'], self::$patterns['tmp_token'], $css );
		$css = preg_replace( self::$patterns['right_in_url_re'], self::$patterns['left'], $css );
		$css = str_replace( self::$patterns['tmp_token'], self::$patterns['right'], $css );

		return $css;
	}

	/**
	 * replace 'ltr' with 'rtl' and vice versa in background urls
	 */
	private static function fixltrrtlinurl( $css ) {
		$css = preg_replace( self::$patterns['ltr_in_url_re'], self::$patterns['tmp_token'], $css );
		$css = preg_replace( self::$patterns['rtl_in_url_re'], self::$patterns['ltr'], $css );
		$css = str_replace( self::$patterns['tmp_token'], self::$patterns['rtl'], $css );

		return $css;
	}

	/**
	 * flip east and west in rules like cursor: nw-resize;
	 */
	private static function fixcursorproperties( $css ) {
		$css = preg_replace( self::$patterns['cursor_east_re'], '\1' . self::$patterns['tmp_token'], $css );
		$css = preg_replace( self::$patterns['cursor_west_re'], '\1e-resize', $css );
		$css = str_replace( self::$patterns['tmp_token'], 'w-resize', $css );

		return $css;
	}

	/**
	 * Fixes border-radius and its browser-specific variants.
	 */
	private static function fixBorderRadius( $css ) {
//echo self::$patterns['border_radius_re']; die();		
		$css = preg_replace_callback(self::$patterns['border_radius_re'], array( 'self', 'reorderBorderRadius' ), $css );

		return $css;
	}

	/**
	 * Fixes border-radius and its browser-specific variants.
	 */
	private static function reorderBorderRadius( $matches ) {
	  $first_group = self::reorderBorderRadiusPart(array_slice ($matches, 3, 4));
  	$second_group = self::reorderBorderRadiusPart(array_slice  ($matches, 7));
  	if ($second_group == '') 
    	return sprintf('%sborder-radius%s%s', $matches[1], $matches[2], $first_group);
  	else
    	return sprintf('%sborder-radius%s%s / %s', $matches[1], $matches[2], $first_group, $second_group);
	}

	/**
	 * Fixes border-radius and its browser-specific variants.
	 */
	private static function reorderBorderRadiusPart( $ps ) {
	  # Remove any piece which may be 'None'
	  $part = array();
	  foreach ($ps as $p) {
	  	if ($p != '') $part[] = $p;
	  }
	  
	  if (count($part) == 4) {
	    return sprintf('%s %s %s %s', $part[1], $part[0], $part[3], $part[2]);
	  } elseif (count($part) == 3) {
	    return sprintf('%s %s %s %s', $part[1], $part[0], $part[1], $part[2]);
	  } elseif (count($part) == 2) {
	    return sprintf('%s %s', $part[1], $part[0]);
	  } elseif (count($part) == 1) {
	    return $part[0];
	  } elseif (count($part) == 0) {
	    return '';
	  } else {
	  	return null;
	  }
	}

	/**
	 * Swap the second and fourth parts in four-part notation rules like
	 * padding: 1px 2px 3px 4px;
	 *
	 * Unlike the original implementation, this function doesn't suffer from
	 * the bug where whitespace is not preserved when flipping four-part rules
	 * and four-part color rules with multiple whitespace characters between
	 * colors are not recognized.
	 * See http://code.google.com/p/cssjanus/issues/detail?id=16
	 */
	private static function fixFourPartNotation( $css ) {
		$css = preg_replace( self::$patterns['four_notation_quantity_re'], '\1 \4 \3 \2', $css );
		$css = preg_replace( self::$patterns['four_notation_color_re'], '\1\2 \5 \4 \3', $css );

		return $css;
	}

	/**
	 * Flip horizontal background percentages.
	 */
	private static function fixBackgroundPosition( $css ) {
		$css = preg_replace_callback( self::$patterns['bg_horizontal_percentage_re'],
			array( 'self', 'calculateNewBackgroundPosition' ), $css );
		$css = preg_replace_callback( self::$patterns['bg_horizontal_percentage_x_re'],
			array( 'self', 'calculateNewBackgroundPositionX' ), $css );
		$css = preg_replace_callback( self::$patterns['bg_horizontal_length_re'],
			array( 'self', 'calculateNewBackgroundLengthPosition' ), $css );
		$css = preg_replace_callback( self::$patterns['bg_horizontal_length_x_re'],
			array( 'self', 'calculateNewBackgroundLengthPositionX' ), $css );

		return $css;
	}

	/**
	 * Callback for calculateNewBackgroundPosition()
	 */
	private static function calculateNewBackgroundPosition( $matches ) {
	  # The flipped value is the offset from 100%
	  $new_x = 100-intval($matches[4]);

	  # Since m.group(1) may very well be None type and we need a string..
	  if ($matches[1]){
	    $position_string = $matches[1];
	  } else {
	    $position_string = '';
		}
	  return sprintf('background%s%s%s%s%%%s', $position_string, $matches[2], $matches[3], $new_x, $matches[5]);
	}

	/**
	 * Callback for calculateNewBackgroundPosition()
	 */
	private static function calculateNewBackgroundPositionX( $matches ) {
	  # The flipped value is the offset from 100%
	  $new_x = 100-intval($matches[2]);

	  return sprintf('background-position-x%s%s%%', $matches[1], $new_x);
	}

	/**
	 * Fixes horizontal background-position lengths.
	 * Return: A string with the horizontal background position set to 100%, if zero. 
	 */
	private static function calculateNewBackgroundLengthPosition( $matches ) {
	  # return original if error
	  if ($matches[4]) {
	    return $matches[0];
	  }

	  # Since m.group(1) may very well be None type and we need a string..
	  if ($matches[1]){
	    $position_string = $matches[1];
	  } else {
	    $position_string = '';
		}
	  return sprintf('background%s%s%s100%%%s', $position_string, $matches[2], $matches[3], $matches[5]);

	}

	/**
	 * Fixes background-position-x lengths
	 * Return: A string with the background-position-x set to 100%, if zero.
	 */
	private static function calculateNewBackgroundLengthPositionX( $matches ) {
	  # return original if error
	  if ($matches[2]) {
	    return $matches[0];
	  }
	  
  	return sprintf('background-position-x%s100%%', $matches[1]);
	}
}




/**
 * Utility class used by CSSJanus that tokenizes and untokenizes things we want
 * to protect from being janused.
 * @author Roan Kattouw
 */
class CSSJanus_Tokenizer {
	private $regex, $token;
	private $originals;

	/**
	 * Constructor
	 * @param $regex string Regular expression whose matches to replace by a token.
	 * @param $token string Token
	 */
	public function __construct( $regex, $token ) {
		$this->regex = $regex;
		$this->token = $token;
		$this->originals = array();
	}

	/**
	 * Replace all occurrences of $regex in $str with a token and remember
	 * the original strings.
	 * @param $str String to tokenize
	 * @return string Tokenized string
	 */
	public function tokenize( $str ) {
		return preg_replace_callback( $this->regex, array( $this, 'tokenizeCallback' ), $str );
	}

	private function tokenizeCallback( $matches ) {
		$this->originals[] = $matches[0];
		return $this->token;
	}

	/**
	 * Replace tokens with their originals. If multiple strings were tokenized, it's important they be
	 * detokenized in exactly the SAME ORDER.
	 * @param $str String: previously run through tokenize()
	 * @return string Original string
	 */
	public function detokenize( $str ) {
		// PHP has no function to replace only the first occurrence or to
		// replace occurrences of the same string with different values,
		// so we use preg_replace_callback() even though we don't really need a regex
		return preg_replace_callback( '/' . preg_quote( $this->token, '/' ) . '/',
			array( $this, 'detokenizeCallback' ), $str );
	}

	private function detokenizeCallback( $matches ) {
		$retval = current( $this->originals );
		next( $this->originals );

		return $retval;
	}
}lessphp/legacy.less.php000060400000002240152455303030011136 0ustar00<?php
/**
 *------------------------------------------------------------------------------
 * @package       T3 Framework for Joomla!
 *------------------------------------------------------------------------------
 * @copyright     Copyright (C) 2004-2013 JoomlArt.com. All Rights Reserved.
 * @license       GNU General Public License version 2 or later; see LICENSE.txt
 * @authors       JoomlArt, JoomlaBamboo, (contribute to this project at github
 *                & Google group to become co-author)
 * @Google group: https://groups.google.com/forum/#!forum/t3fw
 * @Link:         http://t3-framework.org
 *------------------------------------------------------------------------------
 */

// No direct access
defined('_JEXEC') or die();

if (!class_exists('lessc_formatter_compressed', false))
	T3::import('lessphp/lessc.inc');

/**
 * T3LessCompiler class compile less
 *
 * @package T3
 */
class T3LessCompiler
{
	public static function compile ($source, $importdirs) {
		// call Less to compile
		$parser = new lessc();
		$parser->setImportDir(array_keys($importdirs));
		$parser->setPreserveComments(true);
		$output = $parser->compile($source);
    return $output;
	}
}
lessphp/less/cache.php000060400000011113152455303030010735 0ustar00<?php

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

/**
 * Utility for handling the generation and caching of css files
 *
 * @package Less
 * @subpackage cache
 *
 */
class Less_Cache{

	public static $cache_dir = false;		// directory less.php can use for storing data


	/**
	 * Save and reuse the results of compiled less files.
	 * The first call to Get() will generate css and save it.
	 * Subsequent calls to Get() with the same arguments will return the same css filename
	 *
	 * @param array $less_files Array of .less files to compile
	 * @param array $parser_options Array of compiler options
	 * @param boolean $use_cache Set to false to regenerate the css file
	 * @return string Name of the css file
	 */
	public static function Get( $less_files, $parser_options = array(), $use_cache = true ){


		//check $cache_dir
		if( isset($parser_options['cache_dir']) ){
			Less_Cache::$cache_dir = $parser_options['cache_dir'];
		}

		if( empty(Less_Cache::$cache_dir) ){
			throw new Exception('cache_dir not set');
		}

		self::CheckCacheDir();

		// generate name for compiled css file
		$less_files = (array)$less_files;
		$hash = md5(json_encode($less_files));
 		$list_file = Less_Cache::$cache_dir.'lessphp_'.$hash.'.list';


		if( $use_cache === true ){

	 		// check cached content
	 		if( file_exists($list_file) ){


				$list = explode("\n",file_get_contents($list_file));
				$compiled_name = self::CompiledName($list);
				$compiled_file = Less_Cache::$cache_dir.$compiled_name;
				if( file_exists($compiled_file) ){
					@touch($list_file);
					@touch($compiled_file);
					return $compiled_name;
				}
			}

		}

		$compiled = self::Cache( $less_files, $parser_options );
		if( !$compiled ){
			return false;
		}


		//save the file list
		$cache = implode("\n",$less_files);
		file_put_contents( $list_file, $cache );


		//save the css
		$compiled_name = self::CompiledName( $less_files );
		file_put_contents( Less_Cache::$cache_dir.$compiled_name, $compiled );


		//clean up
		self::CleanCache();

		return $compiled_name;
	}

	/**
	 * Force the compiler to regenerate the cached css file
	 *
	 * @param array $less_files Array of .less files to compile
	 * @param array $parser_options Array of compiler options
	 * @return string Name of the css file
	 */
	public static function Regen( $less_files, $parser_options = array() ){
		return self::Get( $less_files, $parser_options, false );
	}

	public static function Cache( &$less_files, $parser_options = array() ){


		// get less.php if it exists
		$file = dirname(__FILE__) . '/Less.php';
		if( file_exists($file) && !class_exists('Less_Parser') ){
			require_once($file);
		}

		$parser_options['cache_dir'] = Less_Cache::$cache_dir;
		$parser = new Less_Parser($parser_options);


		// combine files
		foreach($less_files as $file_path => $uri_or_less ){

			//treat as less markup if there are newline characters
			if( strpos($uri_or_less,"\n") !== false ){
				$parser->Parse( $uri_or_less );
				continue;
			}

			$parser->ParseFile( $file_path, $uri_or_less );
		}

		$compiled = $parser->getCss();


		$less_files = $parser->allParsedFiles();

		return $compiled;
	}


	private static function CompiledName( $files ){

		//save the file list
		$temp = array(Less_Version::cache_version);
		foreach($files as $file){
			$temp[] = filemtime($file)."\t".filesize($file)."\t".$file;
		}

		return 'lessphp_'.sha1(json_encode($temp)).'.css';
	}


	public static function SetCacheDir( $dir ){
		Less_Cache::$cache_dir = $dir;
	}

	public static function CheckCacheDir(){

		Less_Cache::$cache_dir = str_replace('\\','/',Less_Cache::$cache_dir);
		Less_Cache::$cache_dir = rtrim(Less_Cache::$cache_dir,'/').'/';

		if( !file_exists(Less_Cache::$cache_dir) ){
			if( !mkdir(Less_Cache::$cache_dir) ){
				throw new Less_Exception_Parser('Less.php cache directory couldn\'t be created: '.Less_Cache::$cache_dir);
			}

		}elseif( !is_dir(Less_Cache::$cache_dir) ){
			throw new Less_Exception_Parser('Less.php cache directory doesn\'t exist: '.Less_Cache::$cache_dir);

		}elseif( !is_writable(Less_Cache::$cache_dir) ){
			throw new Less_Exception_Parser('Less.php cache directory isn\'t writable: '.Less_Cache::$cache_dir);

		}

	}


	public static function CleanCache(){
		static $clean = false;

		if( $clean ){
			return;
		}

		$files = scandir(Less_Cache::$cache_dir);
		if( $files ){
			$check_time = time() - 604800;
			foreach($files as $file){
				if( strpos($file,'lessphp_') !== 0 ){
					continue;
				}
				$full_path = Less_Cache::$cache_dir.'/'.$file;
				if( filemtime($full_path) > $check_time ){
					continue;
				}
				unlink($full_path);
			}
		}

		$clean = true;
	}

}lessphp/less/version.php000060400000000510152455303030011356 0ustar00<?php

/**
 * Release numbers
 *
 * @package Less
 * @subpackage version
 */
class Less_Version{

	const version = '1.7.0.1';			// The current build number of less.php
	const less_version = '1.7';			// The less.js version that this build should be compatible with
    const cache_version = '170';		// The parser cache version

}lessphp/less/less.php000060400000731674152455303030010665 0ustar00<?php

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

/**
 * Class for parsing and compiling less files into css
 *
 * @package Less
 * @subpackage parser
 *
 */
class Less_Parser{


	/**
	 * Default parser options
	 */
	public static $default_options = array(
		'compress'				=> false,			// option - whether to compress
		'strictUnits'			=> false,			// whether units need to evaluate correctly
		'strictMath'			=> false,			// whether math has to be within parenthesis
		'relativeUrls'			=> true,			// option - whether to adjust URL's to be relative
		'urlArgs'				=> array(),			// whether to add args into url tokens
		'numPrecision'			=> 8,

		'import_dirs'			=> array(),
		'import_callback'		=> null,
		'cache_dir'				=> null,
		'cache_method'			=> 'php', 			//false, 'serialize', 'php', 'var_export';

		'sourceMap'				=> false,			// whether to output a source map
		'sourceMapBasepath'		=> null,
		'sourceMapWriteTo'		=> null,
		'sourceMapURL'			=> null,

		'plugins'				=> array(),

	);

	public static $options = array();


	private $input;					// Less input string
	private $input_len;				// input string length
	private $pos;					// current index in `input`
	private $saveStack = array();	// holds state for backtracking
	private $furthest;

	/**
	 * @var Less_Environment
	 */
	private $env;

	private $rules = array();

	private static $imports = array();

	public static $has_extends = false;

	public static $next_id = 0;

	/**
	 * Filename to contents of all parsed the files
	 *
	 * @var array
	 */
	public static $contentsMap = array();

	public $parensInOp;


	/**
	 * @param Less_Environment|array|null $env
	 */
	public function __construct( $env = null ){

		// Top parser on an import tree must be sure there is one "env"
		// which will then be passed around by reference.
		if( $env instanceof Less_Environment ){
			$this->env = $env;
		}else{
			$this->SetOptions(Less_Parser::$default_options);
			$this->Reset( $env );
		}

	}


	/**
	 * Reset the parser state completely
	 *
	 */
	public function Reset( $options = null ){
		$this->rules = array();
		self::$imports = array();
		self::$has_extends = false;
		self::$imports = array();
		self::$contentsMap = array();

		$this->env = new Less_Environment($options);
		$this->env->Init();

		//set new options
		if( is_array($options) ){
			$this->SetOptions(Less_Parser::$default_options);
			$this->SetOptions($options);
		}
	}

	/**
	 * Set one or more compiler options
	 *  options: import_dirs, cache_dir, cache_method
	 *
	 */
	public function SetOptions( $options ){
		foreach($options as $option => $value){
			$this->SetOption($option,$value);
		}
	}

	/**
	 * Set one compiler option
	 *
	 */
	public function SetOption($option,$value){

		switch($option){

			case 'import_dirs':
				$this->SetImportDirs($value);
			return;

			case 'cache_dir':
				if( is_string($value) ){
					Less_Cache::SetCacheDir($value);
					Less_Cache::CheckCacheDir();
				}
			return;
		}

		Less_Parser::$options[$option] = $value;
	}




	/**
	 * Get the current css buffer
	 *
	 * @return string
	 */
	public function getCss(){

		$precision = ini_get('precision');
		@ini_set('precision',16);
		$locale = setlocale(LC_NUMERIC, 0);
		setlocale(LC_NUMERIC, "C");


 		$root = new Less_Tree_Ruleset(array(), $this->rules );
		$root->root = true;
		$root->firstRoot = true;


		$this->PreVisitors($root);

		self::$has_extends = false;
		$evaldRoot = $root->compile($this->env);



		$this->PostVisitors($evaldRoot);

		if( Less_Parser::$options['sourceMap'] ){
			$generator = new Less_SourceMap_Generator($evaldRoot, Less_Parser::$contentsMap, Less_Parser::$options );
			// will also save file
			// FIXME: should happen somewhere else?
			$css = $generator->generateCSS();
		}else{
			$css = $evaldRoot->toCSS();
		}

		if( Less_Parser::$options['compress'] ){
			$css = preg_replace('/(^(\s)+)|((\s)+$)/', '', $css);
		}

		//reset php settings
		@ini_set('precision',$precision);
		setlocale(LC_NUMERIC, $locale);

		return $css;
	}

	/**
	 * Run pre-compile visitors
	 *
	 */
	private function PreVisitors($root){

		if( Less_Parser::$options['plugins'] ){
			foreach(Less_Parser::$options['plugins'] as $plugin){
				if( !empty($plugin->isPreEvalVisitor) ){
					$plugin->run($root);
				}
			}
		}
	}


	/**
	 * Run post-compile visitors
	 *
	 */
	private function PostVisitors($evaldRoot){

		$visitors = array();
		$visitors[] = new Less_Visitor_joinSelector();
		if( self::$has_extends ){
			$visitors[] = new Less_Visitor_processExtends();
		}
		$visitors[] = new Less_Visitor_toCSS();


		if( Less_Parser::$options['plugins'] ){
			foreach(Less_Parser::$options['plugins'] as $plugin){
				if( property_exists($plugin,'isPreEvalVisitor') && $plugin->isPreEvalVisitor ){
					continue;
				}

				if( property_exists($plugin,'isPreVisitor') && $plugin->isPreVisitor ){
					array_unshift( $visitors, $plugin);
				}else{
					$visitors[] = $plugin;
				}
			}
		}


		for($i = 0; $i < count($visitors); $i++ ){
			$visitors[$i]->run($evaldRoot);
		}

	}


	/**
	 * Parse a Less string into css
	 *
	 * @param string $str The string to convert
	 * @param string $uri_root The url of the file
	 * @return Less_Tree_Ruleset|Less_Parser
	 */
	public function parse( $str, $file_uri = null ){

		if( !$file_uri ){
			$uri_root = '';
			$filename = 'anonymous-file-'.Less_Parser::$next_id++.'.less';
		}else{
			$file_uri = self::WinPath($file_uri);
			$filename = basename($file_uri);
			$uri_root = dirname($file_uri);
		}

		$previousFileInfo = $this->env->currentFileInfo;
		$uri_root = self::WinPath($uri_root);
		$this->SetFileInfo($filename, $uri_root);

		$this->input = $str;
		$this->_parse();

		if( $previousFileInfo ){
			$this->env->currentFileInfo = $previousFileInfo;
		}

		return $this;
	}


	/**
	 * Parse a Less string from a given file
	 *
	 * @throws Less_Exception_Parser
	 * @param string $filename The file to parse
	 * @param string $uri_root The url of the file
	 * @param bool $returnRoot Indicates whether the return value should be a css string a root node
	 * @return Less_Tree_Ruleset|Less_Parser
	 */
	public function parseFile( $filename, $uri_root = '', $returnRoot = false){

		if( !file_exists($filename) ){
			$this->Error(sprintf('File `%s` not found.', $filename));
		}


		// fix uri_root?
		// Instead of The mixture of file path for the first argument and directory path for the second argument has bee
		if( !$returnRoot && !empty($uri_root) && basename($uri_root) == basename($filename) ){
			$uri_root = dirname($uri_root);
		}


		$previousFileInfo = $this->env->currentFileInfo;
		$filename = self::WinPath($filename);
		$uri_root = self::WinPath($uri_root);
		$this->SetFileInfo($filename, $uri_root);

		self::AddParsedFile($filename);

		if( $returnRoot ){
			$rules = $this->GetRules( $filename );
			$return = new Less_Tree_Ruleset(array(), $rules );
		}else{
			$this->_parse( $filename );
			$return = $this;
		}

		if( $previousFileInfo ){
			$this->env->currentFileInfo = $previousFileInfo;
		}

		return $return;
	}


	/**
	 * Allows a user to set variables values
	 * @param array $vars
	 * @return Less_Parser
	 */
	public function ModifyVars( $vars ){

		$this->input = $this->serializeVars( $vars );
		$this->_parse();

		return $this;
	}


	/**
	 * @param string $filename
	 */
	public function SetFileInfo( $filename, $uri_root = ''){

		$filename = Less_Environment::normalizePath($filename);
		$dirname = preg_replace('/[^\/\\\\]*$/','',$filename);

		if( !empty($uri_root) ){
			$uri_root = rtrim($uri_root,'/').'/';
		}

		$currentFileInfo = array();

		//entry info
		if( isset($this->env->currentFileInfo) ){
			$currentFileInfo['entryPath'] = $this->env->currentFileInfo['entryPath'];
			$currentFileInfo['entryUri'] = $this->env->currentFileInfo['entryUri'];
			$currentFileInfo['rootpath'] = $this->env->currentFileInfo['rootpath'];

		}else{
			$currentFileInfo['entryPath'] = $dirname;
			$currentFileInfo['entryUri'] = $uri_root;
			$currentFileInfo['rootpath'] = $dirname;
		}

		$currentFileInfo['currentDirectory'] = $dirname;
		$currentFileInfo['currentUri'] = $uri_root.basename($filename);
		$currentFileInfo['filename'] = $filename;
		$currentFileInfo['uri_root'] = $uri_root;


		//inherit reference
		if( isset($this->env->currentFileInfo['reference']) && $this->env->currentFileInfo['reference'] ){
			$currentFileInfo['reference'] = true;
		}

		$this->env->currentFileInfo = $currentFileInfo;
	}


	/**
	 * @deprecated 1.5.1.2
	 *
	 */
	public function SetCacheDir( $dir ){

		if( !file_exists($dir) ){
			if( mkdir($dir) ){
				return true;
			}
			throw new Less_Exception_Parser('Less.php cache directory couldn\'t be created: '.$dir);

		}elseif( !is_dir($dir) ){
			throw new Less_Exception_Parser('Less.php cache directory doesn\'t exist: '.$dir);

		}elseif( !is_writable($dir) ){
			throw new Less_Exception_Parser('Less.php cache directory isn\'t writable: '.$dir);

		}else{
			$dir = self::WinPath($dir);
			Less_Cache::$cache_dir = rtrim($dir,'/').'/';
			return true;
		}
	}


	/**
	 * Set a list of directories or callbacks the parser should use for determining import paths
	 *
	 * @param array $dirs
	 */
	public function SetImportDirs( $dirs ){
		Less_Parser::$options['import_dirs'] = array();

		foreach($dirs as $path => $uri_root){

			$path = self::WinPath($path);
			if( !empty($path) ){
				$path = rtrim($path,'/').'/';
			}

			if ( !is_callable($uri_root) ){
				$uri_root = self::WinPath($uri_root);
				if( !empty($uri_root) ){
					$uri_root = rtrim($uri_root,'/').'/';
				}
			}

			Less_Parser::$options['import_dirs'][$path] = $uri_root;
		}
	}

	/**
	 * @param string $file_path
	 */
	private function _parse( $file_path = null ){
		$this->rules = array_merge($this->rules, $this->GetRules( $file_path ));
	}


	/**
	 * Return the results of parsePrimary for $file_path
	 * Use cache and save cached results if possible
	 *
	 * @param string|null $file_path
	 */
	private function GetRules( $file_path ){

		$this->SetInput($file_path);

		$cache_file = $this->CacheFile( $file_path );
		if( $cache_file && file_exists($cache_file) ){
			switch(Less_Parser::$options['cache_method']){

				// Using serialize
				// Faster but uses more memory
				case 'serialize':
					$cache = unserialize(file_get_contents($cache_file));
					if( $cache ){
						touch($cache_file);
						$this->UnsetInput();
						return $cache;
					}
				break;


				// Using generated php code
				case 'var_export':
				case 'php':
				$this->UnsetInput();
				return include($cache_file);
			}
		}

		$rules = $this->parsePrimary();

		if( $this->pos < $this->input_len ){
			throw new Less_Exception_Chunk($this->input, null, $this->furthest, $this->env->currentFileInfo);
		}

		$this->UnsetInput();


		//save the cache
		if( $cache_file ){

			//msg('write cache file');
			switch(Less_Parser::$options['cache_method']){
				case 'serialize':
					file_put_contents( $cache_file, serialize($rules) );
				break;
				case 'php':
					file_put_contents( $cache_file, '<?php return '.self::ArgString($rules).'; ?>' );
				break;
				case 'var_export':
					//Requires __set_state()
					file_put_contents( $cache_file, '<?php return '.var_export($rules,true).'; ?>' );
				break;
			}

			Less_Cache::CleanCache();
		}

		return $rules;
	}


	/**
	 * Set up the input buffer
	 *
	 */
	public function SetInput( $file_path ){

		if( $file_path ){
			$this->input = file_get_contents( $file_path );
		}

		$this->pos = $this->furthest = 0;

		// Remove potential UTF Byte Order Mark
		$this->input = preg_replace('/\\G\xEF\xBB\xBF/', '', $this->input);
		$this->input_len = strlen($this->input);


		if( Less_Parser::$options['sourceMap'] && $this->env->currentFileInfo ){
			$uri = $this->env->currentFileInfo['currentUri'];
			Less_Parser::$contentsMap[$uri] = $this->input;
		}

	}


	/**
	 * Free up some memory
	 *
	 */
	public function UnsetInput(){
		unset($this->input, $this->pos, $this->input_len, $this->furthest);
		$this->saveStack = array();
	}


	public function CacheFile( $file_path ){

		if( $file_path && Less_Parser::$options['cache_method'] && Less_Cache::$cache_dir ){

			$env = get_object_vars($this->env);
			unset($env['frames']);

			$parts = array();
			$parts[] = $file_path;
			$parts[] = filesize( $file_path );
			$parts[] = filemtime( $file_path );
			$parts[] = $env;
			$parts[] = Less_Version::cache_version;
			$parts[] = Less_Parser::$options['cache_method'];
			return Less_Cache::$cache_dir.'lessphp_'.base_convert( sha1(json_encode($parts) ), 16, 36).'.lesscache';
		}
	}


	static function AddParsedFile($file){
		self::$imports[] = $file;
	}

	static function AllParsedFiles(){
		return self::$imports;
	}

	/**
	 * @param string $file
	 */
	static function FileParsed($file){
		return in_array($file,self::$imports);
	}


	function save() {
		$this->saveStack[] = $this->pos;
	}

	private function restore() {
		$this->pos = array_pop($this->saveStack);
	}

	private function forget(){
		array_pop($this->saveStack);
	}


	private function isWhitespace($offset = 0) {
		return preg_match('/\s/',$this->input[ $this->pos + $offset]);
	}

	/**
	 * Parse from a token, regexp or string, and move forward if match
	 *
	 * @param array $toks
	 * @return array
	 */
	private function match($toks){

		// The match is confirmed, add the match length to `this::pos`,
		// and consume any extra white-space characters (' ' || '\n')
		// which come after that. The reason for this is that LeSS's
		// grammar is mostly white-space insensitive.
		//

		foreach($toks as $tok){

			$char = $tok[0];

			if( $char === '/' ){
				$match = $this->MatchReg($tok);

				if( $match ){
					return count($match) === 1 ? $match[0] : $match;
				}

			}elseif( $char === '#' ){
				$match = $this->MatchChar($tok[1]);

			}else{
				// Non-terminal, match using a function call
				$match = $this->$tok();

			}

			if( $match ){
				return $match;
			}
		}
	}

	/**
	 * @param string[] $toks
	 *
	 * @return string
	 */
	private function MatchFuncs($toks){

		foreach($toks as $tok){
			$match = $this->$tok();
			if( $match ){
				return $match;
			}
		}

	}

	// Match a single character in the input,
	private function MatchChar($tok){
		if( ($this->pos < $this->input_len) && ($this->input[$this->pos] === $tok) ){
			$this->skipWhitespace(1);
			return $tok;
		}
	}

	// Match a regexp from the current start point
	private function MatchReg($tok){

		if( preg_match($tok, $this->input, $match, 0, $this->pos) ){
			$this->skipWhitespace(strlen($match[0]));
			return $match;
		}
		return [];
	}


	/**
	 * Same as match(), but don't change the state of the parser,
	 * just return the match.
	 *
	 * @param string $tok
	 * @return integer
	 */
	public function PeekReg($tok){
		return preg_match($tok, $this->input, $match, 0, $this->pos);
	}

	/**
	 * @param string $tok
	 */
	public function PeekChar($tok){
		//return ($this->input[$this->pos] === $tok );
		return ($this->pos < $this->input_len) && ($this->input[$this->pos] === $tok );
	}


	/**
	 * @param integer $length
	 */
	public function skipWhitespace($length){

		$this->pos += $length;

		for(; $this->pos < $this->input_len; $this->pos++ ){
			$c = $this->input[$this->pos];

			if( ($c !== "\n") && ($c !== "\r") && ($c !== "\t") && ($c !== ' ') ){
				break;
			}
		}
	}


	/**
	 * @param string $tok
	 * @param string|null $msg
	 */
	public function expect($tok, $msg = NULL) {
		$result = $this->match( array($tok) );
		if (!$result) {
			$this->Error( $msg	? "Expected '" . $tok . "' got '" . $this->input[$this->pos] . "'" : $msg );
		} else {
			return $result;
		}
	}

	/**
	 * @param string $tok
	 */
	public function expectChar($tok, $msg = null ){
		$result = $this->MatchChar($tok);
		if( !$result ){
			$this->Error( $msg ? "Expected '" . $tok . "' got '" . $this->input[$this->pos] . "'" : $msg );
		}else{
			return $result;
		}
	}

	//
	// Here in, the parsing rules/functions
	//
	// The basic structure of the syntax tree generated is as follows:
	//
	//   Ruleset ->  Rule -> Value -> Expression -> Entity
	//
	// Here's some LESS code:
	//
	//	.class {
	//	  color: #fff;
	//	  border: 1px solid #000;
	//	  width: @w + 4px;
	//	  > .child {...}
	//	}
	//
	// And here's what the parse tree might look like:
	//
	//	 Ruleset (Selector '.class', [
	//		 Rule ("color",  Value ([Expression [Color #fff]]))
	//		 Rule ("border", Value ([Expression [Dimension 1px][Keyword "solid"][Color #000]]))
	//		 Rule ("width",  Value ([Expression [Operation "+" [Variable "@w"][Dimension 4px]]]))
	//		 Ruleset (Selector [Element '>', '.child'], [...])
	//	 ])
	//
	//  In general, most rules will try to parse a token with the `$()` function, and if the return
	//  value is truly, will return a new node, of the relevant type. Sometimes, we need to check
	//  first, before parsing, that's when we use `peek()`.
	//

	//
	// The `primary` rule is the *entry* and *exit* point of the parser.
	// The rules here can appear at any level of the parse tree.
	//
	// The recursive nature of the grammar is an interplay between the `block`
	// rule, which represents `{ ... }`, the `ruleset` rule, and this `primary` rule,
	// as represented by this simplified grammar:
	//
	//	 primary  →  (ruleset | rule)+
	//	 ruleset  →  selector+ block
	//	 block	→  '{' primary '}'
	//
	// Only at one point is the primary rule not called from the
	// block rule: at the root level.
	//
	private function parsePrimary(){
		$root = array();

		while( true ){

			if( $this->pos >= $this->input_len ){
				break;
			}

			$node = $this->parseExtend(true);
			if( $node ){
				$root = array_merge($root,$node);
				continue;
			}

			//$node = $this->MatchFuncs( array( 'parseMixinDefinition', 'parseRule', 'parseRuleset', 'parseMixinCall', 'parseComment', 'parseDirective'));
			$node = $this->MatchFuncs( array( 'parseMixinDefinition', 'parseNameValue', 'parseRule', 'parseRuleset', 'parseMixinCall', 'parseComment', 'parseRulesetCall', 'parseDirective'));

			if( $node ){
				$root[] = $node;
			}elseif( !$this->MatchReg('/\\G[\s\n;]+/') ){
				break;
			}

            if( $this->PeekChar('}') ){
				break;
			}
		}

		return $root;
	}



	// We create a Comment node for CSS comments `/* */`,
	// but keep the LeSS comments `//` silent, by just skipping
	// over them.
	private function parseComment(){

		if( $this->input[$this->pos] !== '/' ){
			return;
		}

		if( $this->input[$this->pos+1] === '/' ){
			$match = $this->MatchReg('/\\G\/\/.*/');
			return $this->NewObj4('Less_Tree_Comment',array($match[0], true, $this->pos, $this->env->currentFileInfo));
		}

		//$comment = $this->MatchReg('/\\G\/\*(?:[^*]|\*+[^\/*])*\*+\/\n?/');
		$comment = $this->MatchReg('/\\G\/\*(?s).*?\*+\/\n?/');//not the same as less.js to prevent fatal errors
		if( $comment ){
			return $this->NewObj4('Less_Tree_Comment',array($comment[0], false, $this->pos, $this->env->currentFileInfo));
		}
	}

	private function parseComments(){
		$comments = array();

		while( $this->pos < $this->input_len ){
			$comment = $this->parseComment();
			if( !$comment ){
				break;
			}

			$comments[] = $comment;
		}

		return $comments;
	}



	//
	// A string, which supports escaping " and '
	//
	//	 "milky way" 'he\'s the one!'
	//
	private function parseEntitiesQuoted() {
		$j = $this->pos;
		$e = false;
		$index = $this->pos;

		if( $this->input[$this->pos] === '~' ){
			$j++;
			$e = true; // Escaped strings
		}

		if( $this->input[$j] != '"' && $this->input[$j] !== "'" ){
			return;
		}

		if ($e) {
			$this->MatchChar('~');
		}
		$str = $this->MatchReg('/\\G"((?:[^"\\\\\r\n]|\\\\.)*)"|\'((?:[^\'\\\\\r\n]|\\\\.)*)\'/');
		if( $str ){
			$result = $str[0][0] == '"' ? $str[1] : $str[2];
			return $this->NewObj5('Less_Tree_Quoted',array($str[0], $result, $e, $index, $this->env->currentFileInfo) );
		}
		return;
	}


	//
	// A catch-all word, such as:
	//
	//	 black border-collapse
	//
	private function parseEntitiesKeyword(){

		//$k = $this->MatchReg('/\\G[_A-Za-z-][_A-Za-z0-9-]*/');
		$k = $this->MatchReg('/\\G%|\\G[_A-Za-z-][_A-Za-z0-9-]*/');
		if( $k ){
			$k = $k[0];
			$color = $this->fromKeyword($k);
			if( $color ){
				return $color;
			}
			return $this->NewObj1('Less_Tree_Keyword',$k);
		}
	}

	// duplicate of Less_Tree_Color::FromKeyword
	private function FromKeyword( $keyword ){
		$keyword = strtolower($keyword);

		if( Less_Colors::hasOwnProperty($keyword) ){
			// detect named color
			return $this->NewObj1('Less_Tree_Color',substr(Less_Colors::color($keyword), 1));
		}

		if( $keyword === 'transparent' ){
			return $this->NewObj3('Less_Tree_Color', array( array(0, 0, 0), 0, true));
		}
	}

	//
	// A function call
	//
	//	 rgb(255, 0, 255)
	//
	// We also try to catch IE's `alpha()`, but let the `alpha` parser
	// deal with the details.
	//
	// The arguments are parsed with the `entities.arguments` parser.
	//
	private function parseEntitiesCall(){
		$index = $this->pos;

		if( !preg_match('/\\G([\w-]+|%|progid:[\w\.]+)\(/', $this->input, $name,0,$this->pos) ){
			return;
		}
		$name = $name[1];
		$nameLC = strtolower($name);

		if ($nameLC === 'url') {
			return null;
		}

		$this->pos += strlen($name);

		if( $nameLC === 'alpha' ){
			$alpha_ret = $this->parseAlpha();
			if( $alpha_ret ){
				return $alpha_ret;
			}
		}

		$this->MatchChar('('); // Parse the '(' and consume whitespace.

		$args = $this->parseEntitiesArguments();

		if( !$this->MatchChar(')') ){
			return;
		}

		if ($name) {
			return $this->NewObj4('Less_Tree_Call',array($name, $args, $index, $this->env->currentFileInfo) );
		}
	}

	/**
	 * Parse a list of arguments
	 *
	 * @return array
	 */
	private function parseEntitiesArguments(){

		$args = array();
		while( true ){
			$arg = $this->MatchFuncs( array('parseEntitiesAssignment','parseExpression') );
			if( !$arg ){
				break;
			}

			$args[] = $arg;
			if( !$this->MatchChar(',') ){
				break;
			}
		}
		return $args;
	}

	private function parseEntitiesLiteral(){
		return $this->MatchFuncs( array('parseEntitiesDimension','parseEntitiesColor','parseEntitiesQuoted','parseUnicodeDescriptor') );
	}

	// Assignments are argument entities for calls.
	// They are present in ie filter properties as shown below.
	//
	//	 filter: progid:DXImageTransform.Microsoft.Alpha( *opacity=50* )
	//
	private function parseEntitiesAssignment() {

		$key = $this->MatchReg('/\\G\w+(?=\s?=)/');
		if( !$key ){
			return;
		}

		if( !$this->MatchChar('=') ){
			return;
		}

		$value = $this->parseEntity();
		if( $value ){
			return $this->NewObj2('Less_Tree_Assignment',array($key[0], $value));
		}
	}

	//
	// Parse url() tokens
	//
	// We use a specific rule for urls, because they don't really behave like
	// standard function calls. The difference is that the argument doesn't have
	// to be enclosed within a string, so it can't be parsed as an Expression.
	//
	private function parseEntitiesUrl(){


		if( $this->input[$this->pos] !== 'u' || !$this->matchReg('/\\Gurl\(/') ){
			return;
		}

		$value = $this->match( array('parseEntitiesQuoted','parseEntitiesVariable','/\\Gdata\:.*?[^\)]+/','/\\G(?:(?:\\\\[\(\)\'"])|[^\(\)\'"])+/') );
		if( !$value ){
			$value = '';
		}


		$this->expectChar(')');


		if( isset($value->value) || $value instanceof Less_Tree_Variable ){
			return $this->NewObj2('Less_Tree_Url',array($value, $this->env->currentFileInfo));
		}

		return $this->NewObj2('Less_Tree_Url', array( $this->NewObj1('Less_Tree_Anonymous',$value), $this->env->currentFileInfo) );
	}


	//
	// A Variable entity, such as `@fink`, in
	//
	//	 width: @fink + 2px
	//
	// We use a different parser for variable definitions,
	// see `parsers.variable`.
	//
	private function parseEntitiesVariable(){
		$index = $this->pos;
		if ($this->PeekChar('@') && ($name = $this->MatchReg('/\\G@@?[\w-]+/'))) {
			return $this->NewObj3('Less_Tree_Variable', array( $name[0], $index, $this->env->currentFileInfo));
		}
	}


	// A variable entity useing the protective {} e.g. @{var}
	private function parseEntitiesVariableCurly() {
		$index = $this->pos;

		if( $this->input_len > ($this->pos+1) && $this->input[$this->pos] === '@' && ($curly = $this->MatchReg('/\\G@\{([\w-]+)\}/')) ){
			return $this->NewObj3('Less_Tree_Variable',array('@'.$curly[1], $index, $this->env->currentFileInfo));
		}
	}

	//
	// A Hexadecimal color
	//
	//	 #4F3C2F
	//
	// `rgb` and `hsl` colors are parsed through the `entities.call` parser.
	//
	private function parseEntitiesColor(){
		if ($this->PeekChar('#') && ($rgb = $this->MatchReg('/\\G#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})/'))) {
			return $this->NewObj1('Less_Tree_Color',$rgb[1]);
		}
	}

	//
	// A Dimension, that is, a number and a unit
	//
	//	 0.5em 95%
	//
	private function parseEntitiesDimension(){

		$c = @ord($this->input[$this->pos]);

		//Is the first char of the dimension 0-9, '.', '+' or '-'
		if (($c > 57 || $c < 43) || $c === 47 || $c == 44){
			return;
		}

		$value = $this->MatchReg('/\\G([+-]?\d*\.?\d+)(%|[a-z]+)?/');
		if( $value ){

			if( isset($value[2]) ){
				return $this->NewObj2('Less_Tree_Dimension', array($value[1],$value[2]));
			}
			return $this->NewObj1('Less_Tree_Dimension',$value[1]);
		}
	}


	//
	// A unicode descriptor, as is used in unicode-range
	//
	// U+0?? or U+00A1-00A9
	//
	function parseUnicodeDescriptor() {
		$ud = $this->MatchReg('/\\G(U\+[0-9a-fA-F?]+)(\-[0-9a-fA-F?]+)?/');
		if( $ud ){
			return $this->NewObj1('Less_Tree_UnicodeDescriptor', $ud[0]);
		}
	}


	//
	// JavaScript code to be evaluated
	//
	//	 `window.location.href`
	//
	private function parseEntitiesJavascript(){
		$e = false;
		$j = $this->pos;
		if( $this->input[$j] === '~' ){
			$j++;
			$e = true;
		}
		if( $this->input[$j] !== '`' ){
			return;
		}
		if( $e ){
			$this->MatchChar('~');
		}
		$str = $this->MatchReg('/\\G`([^`]*)`/');
		if( $str ){
			return $this->NewObj3('Less_Tree_Javascript', array($str[1], $this->pos, $e));
		}
	}


	//
	// The variable part of a variable definition. Used in the `rule` parser
	//
	//	 @fink:
	//
	private function parseVariable(){
		if ($this->PeekChar('@') && ($name = $this->MatchReg('/\\G(@[\w-]+)\s*:/'))) {
			return $name[1];
		}
	}


	//
	// The variable part of a variable definition. Used in the `rule` parser
	//
	// @fink();
	//
	private function parseRulesetCall(){

		if( $this->input[$this->pos] === '@' && ($name = $this->MatchReg('/\\G(@[\w-]+)\s*\(\s*\)\s*;/')) ){
			return $this->NewObj1('Less_Tree_RulesetCall', $name[1] );
		}
	}


	//
	// extend syntax - used to extend selectors
	//
	function parseExtend($isRule = false){

		$index = $this->pos;
		$extendList = array();


		if( !$this->MatchReg( $isRule ? '/\\G&:extend\(/' : '/\\G:extend\(/' ) ){ return; }

		do{
			$option = null;
			$elements = array();
			while( true ){
				$option = $this->MatchReg('/\\G(all)(?=\s*(\)|,))/');
				if( $option ){ break; }
				$e = $this->parseElement();
				if( !$e ){ break; }
				$elements[] = $e;
			}

			if( $option ){
				$option = $option[1];
			}

			$extendList[] = $this->NewObj3('Less_Tree_Extend', array( $this->NewObj1('Less_Tree_Selector',$elements), $option, $index ));

		}while( $this->MatchChar(",") );

		$this->expect('/\\G\)/');

		if( $isRule ){
			$this->expect('/\\G;/');
		}

		return $extendList;
	}


	//
	// A Mixin call, with an optional argument list
	//
	//	 #mixins > .square(#fff);
	//	 .rounded(4px, black);
	//	 .button;
	//
	// The `while` loop is there because mixins can be
	// namespaced, but we only support the child and descendant
	// selector for now.
	//
	private function parseMixinCall(){

		$char = $this->input[$this->pos];
		if( $char !== '.' && $char !== '#' ){
			return;
		}

		$index = $this->pos;
		$this->save(); // stop us absorbing part of an invalid selector

		$elements = $this->parseMixinCallElements();

		if( $elements ){

			if( $this->MatchChar('(') ){
				$returned = $this->parseMixinArgs(true);
				$args = $returned['args'];
				$this->expectChar(')');
			}else{
				$args = array();
			}

			$important = $this->parseImportant();

			if( $this->parseEnd() ){
				$this->forget();
				return $this->NewObj5('Less_Tree_Mixin_Call', array( $elements, $args, $index, $this->env->currentFileInfo, $important));
			}
		}

		$this->restore();
	}


	private function parseMixinCallElements(){
		$elements = array();
		$c = null;

		while( true ){
			$elemIndex = $this->pos;
			$e = $this->MatchReg('/\\G[#.](?:[\w-]|\\\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/');
			if( !$e ){
				break;
			}
			$elements[] = $this->NewObj4('Less_Tree_Element', array($c, $e[0], $elemIndex, $this->env->currentFileInfo));
			$c = $this->MatchChar('>');
		}

		return $elements;
	}



	/**
	 * @param boolean $isCall
	 */
	private function parseMixinArgs( $isCall ){
		$expressions = array();
		$argsSemiColon = array();
		$isSemiColonSeperated = null;
		$argsComma = array();
		$expressionContainsNamed = null;
		$name = null;
		$returner = array('args'=>array(), 'variadic'=> false);

		$this->save();

		while( true ){
			if( $isCall ){
				$arg = $this->MatchFuncs( array( 'parseDetachedRuleset','parseExpression' ) );
			} else {
				$this->parseComments();
				if( $this->input[ $this->pos ] === '.' && $this->MatchReg('/\\G\.{3}/') ){
					$returner['variadic'] = true;
					if( $this->MatchChar(";") && !$isSemiColonSeperated ){
						$isSemiColonSeperated = true;
					}

					if( $isSemiColonSeperated ){
						$argsSemiColon[] = array('variadic'=>true);
					}else{
						$argsComma[] = array('variadic'=>true);
					}
					break;
				}
				$arg = $this->MatchFuncs( array('parseEntitiesVariable','parseEntitiesLiteral','parseEntitiesKeyword') );
			}

			if( !$arg ){
				break;
			}


			$nameLoop = null;
			if( $arg instanceof Less_Tree_Expression ){
				$arg->throwAwayComments();
			}
			$value = $arg;
			$val = null;

			if( $isCall ){
				// Variable
				if( property_exists($arg,'value') && count($arg->value) == 1 ){
					$val = $arg->value[0];
				}
			} else {
				$val = $arg;
			}


			if( $val instanceof Less_Tree_Variable ){

				if( $this->MatchChar(':') ){
					if( $expressions ){
						if( $isSemiColonSeperated ){
							$this->Error('Cannot mix ; and , as delimiter types');
						}
						$expressionContainsNamed = true;
					}

					// we do not support setting a ruleset as a default variable - it doesn't make sense
					// However if we do want to add it, there is nothing blocking it, just don't error
					// and remove isCall dependency below
					$value = null;
					if( $isCall ){
						$value = $this->parseDetachedRuleset();
					}
					if( !$value ){
						$value = $this->parseExpression();
					}

					if( !$value ){
						if( $isCall ){
							$this->Error('could not understand value for named argument');
						} else {
							$this->restore();
							$returner['args'] = array();
							return $returner;
						}
					}

					$nameLoop = ($name = $val->name);
				}elseif( !$isCall && $this->MatchReg('/\\G\.{3}/') ){
					$returner['variadic'] = true;
					if( $this->MatchChar(";") && !$isSemiColonSeperated ){
						$isSemiColonSeperated = true;
					}
					if( $isSemiColonSeperated ){
						$argsSemiColon[] = array('name'=> $arg->name, 'variadic' => true);
					}else{
						$argsComma[] = array('name'=> $arg->name, 'variadic' => true);
					}
					break;
				}elseif( !$isCall ){
					$name = $nameLoop = $val->name;
					$value = null;
				}
			}

			if( $value ){
				$expressions[] = $value;
			}

			$argsComma[] = array('name'=>$nameLoop, 'value'=>$value );

			if( $this->MatchChar(',') ){
				continue;
			}

			if( $this->MatchChar(';') || $isSemiColonSeperated ){

				if( $expressionContainsNamed ){
					$this->Error('Cannot mix ; and , as delimiter types');
				}

				$isSemiColonSeperated = true;

				if( count($expressions) > 1 ){
					$value = $this->NewObj1('Less_Tree_Value', $expressions);
				}
				$argsSemiColon[] = array('name'=>$name, 'value'=>$value );

				$name = null;
				$expressions = array();
				$expressionContainsNamed = false;
			}
		}

		$this->forget();
		$returner['args'] = ($isSemiColonSeperated ? $argsSemiColon : $argsComma);
		return $returner;
	}



	//
	// A Mixin definition, with a list of parameters
	//
	//	 .rounded (@radius: 2px, @color) {
	//		...
	//	 }
	//
	// Until we have a finer grained state-machine, we have to
	// do a look-ahead, to make sure we don't have a mixin call.
	// See the `rule` function for more information.
	//
	// We start by matching `.rounded (`, and then proceed on to
	// the argument list, which has optional default values.
	// We store the parameters in `params`, with a `value` key,
	// if there is a value, such as in the case of `@radius`.
	//
	// Once we've got our params list, and a closing `)`, we parse
	// the `{...}` block.
	//
	private function parseMixinDefinition(){
		$cond = null;

		$char = $this->input[$this->pos];
		if( ($char !== '.' && $char !== '#') || ($char === '{' && $this->PeekReg('/\\G[^{]*\}/')) ){
			return;
		}

		$this->save();

		$match = $this->MatchReg('/\\G([#.](?:[\w-]|\\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+)\s*\(/');
		if( $match ){
			$name = $match[1];

			$argInfo = $this->parseMixinArgs( false );
			$params = $argInfo['args'];
			$variadic = $argInfo['variadic'];


			// .mixincall("@{a}");
			// looks a bit like a mixin definition..
			// also
			// .mixincall(@a: {rule: set;});
			// so we have to be nice and restore
			if( !$this->MatchChar(')') ){
				$this->furthest = $this->pos;
				$this->restore();
				return;
			}


			$this->parseComments();

			if ($this->MatchReg('/\\Gwhen/')) { // Guard
				$cond = $this->expect('parseConditions', 'Expected conditions');
			}

			$ruleset = $this->parseBlock();

			if( is_array($ruleset) ){
				$this->forget();
				return $this->NewObj5('Less_Tree_Mixin_Definition', array( $name, $params, $ruleset, $cond, $variadic));
			}

			$this->restore();
		}else{
			$this->forget();
		}
	}

	//
	// Entities are the smallest recognized token,
	// and can be found inside a rule's value.
	//
	private function parseEntity(){

		return $this->MatchFuncs( array('parseEntitiesLiteral','parseEntitiesVariable','parseEntitiesUrl','parseEntitiesCall','parseEntitiesKeyword','parseEntitiesJavascript','parseComment') );
	}

	//
	// A Rule terminator. Note that we use `peek()` to check for '}',
	// because the `block` rule will be expecting it, but we still need to make sure
	// it's there, if ';' was ommitted.
	//
	private function parseEnd(){
		return $this->MatchChar(';') || $this->PeekChar('}');
	}

	//
	// IE's alpha function
	//
	//	 alpha(opacity=88)
	//
	private function parseAlpha(){

		if ( ! $this->MatchReg('/\\G\(opacity=/i')) {
			return;
		}

		$value = $this->MatchReg('/\\G[0-9]+/');
		if( $value ){
			$value = $value[0];
		}else{
			$value = $this->parseEntitiesVariable();
			if( !$value ){
				return;
			}
		}

		$this->expectChar(')');
		return $this->NewObj1('Less_Tree_Alpha',$value);
	}


	//
	// A Selector Element
	//
	//	 div
	//	 + h1
	//	 #socks
	//	 input[type="text"]
	//
	// Elements are the building blocks for Selectors,
	// they are made out of a `Combinator` (see combinator rule),
	// and an element name, such as a tag a class, or `*`.
	//
	private function parseElement(){
		$c = $this->parseCombinator();
		$index = $this->pos;

		$e = $this->match( array('/\\G(?:\d+\.\d+|\d+)%/', '/\\G(?:[.#]?|:*)(?:[\w-]|[^\x00-\x9f]|\\\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/',
			'#*', '#&', 'parseAttribute', '/\\G\([^()@]+\)/', '/\\G[\.#](?=@)/', 'parseEntitiesVariableCurly') );

		if( is_null($e) ){
			$this->save();
			if( $this->MatchChar('(') ){
				if( ($v = $this->parseSelector()) && $this->MatchChar(')') ){
					$e = $this->NewObj1('Less_Tree_Paren',$v);
					$this->forget();
				}else{
					$this->restore();
				}
			}else{
				$this->forget();
			}
		}

		if( !is_null($e) ){
			return $this->NewObj4('Less_Tree_Element',array( $c, $e, $index, $this->env->currentFileInfo));
		}
	}

	//
	// Combinators combine elements together, in a Selector.
	//
	// Because our parser isn't white-space sensitive, special care
	// has to be taken, when parsing the descendant combinator, ` `,
	// as it's an empty space. We have to check the previous character
	// in the input, to see if it's a ` ` character.
	//
	private function parseCombinator(){
		$c = $this->input[$this->pos];
		if ($c === '>' || $c === '+' || $c === '~' || $c === '|' || $c === '^' ){

			$this->pos++;
			if( $this->input[$this->pos] === '^' ){
				$c = '^^';
				$this->pos++;
			}

			$this->skipWhitespace(0);

			return $c;
		}

		if( $this->pos > 0 && $this->isWhitespace(-1) ){
			return ' ';
		}
	}

	//
	// A CSS selector (see selector below)
	// with less extensions e.g. the ability to extend and guard
	//
	private function parseLessSelector(){
		return $this->parseSelector(true);
	}

	//
	// A CSS Selector
	//
	//	 .class > div + h1
	//	 li a:hover
	//
	// Selectors are made out of one or more Elements, see above.
	//
	private function parseSelector( $isLess = false ){
		$elements = array();
		$extendList = array();
		$condition = null;
		$when = false;
		$extend = false;
		$e = null;
		$c = null;
		$index = $this->pos;

		while( ($isLess && ($extend = $this->parseExtend())) || ($isLess && ($when = $this->MatchReg('/\\Gwhen/') )) || ($e = $this->parseElement()) ){
			if( $when ){
				$condition = $this->expect('parseConditions', 'expected condition');
			}elseif( $condition ){
				//error("CSS guard can only be used at the end of selector");
			}elseif( $extend ){
				$extendList = array_merge($extendList,$extend);
			}else{
				//if( count($extendList) ){
					//error("Extend can only be used at the end of selector");
				//}
				$c = $this->input[ $this->pos ];
				$elements[] = $e;
				$e = null;
			}

			if( $c === '{' || $c === '}' || $c === ';' || $c === ',' || $c === ')') { break; }
		}

		if( $elements ){
			return $this->NewObj5('Less_Tree_Selector',array($elements, $extendList, $condition, $index, $this->env->currentFileInfo));
		}
		if( $extendList ) {
			$this->Error('Extend must be used to extend a selector, it cannot be used on its own');
		}
	}

	private function parseTag(){
		return ( $tag = $this->MatchReg('/\\G[A-Za-z][A-Za-z-]*[0-9]?/') ) ? $tag : $this->MatchChar('*');
	}

	private function parseAttribute(){

		$val = null;

		if( !$this->MatchChar('[') ){
			return;
		}

		$key = $this->parseEntitiesVariableCurly();
		if( !$key ){
			$key = $this->expect('/\\G(?:[_A-Za-z0-9-\*]*\|)?(?:[_A-Za-z0-9-]|\\\\.)+/');
		}

		$op = $this->MatchReg('/\\G[|~*$^]?=/');
		if( $op ){
			$val = $this->match( array('parseEntitiesQuoted','/\\G[0-9]+%/','/\\G[\w-]+/','parseEntitiesVariableCurly') );
		}

		$this->expectChar(']');
		// kiendt- fix check empty option
		$_op = !empty($op[0]) ? $op[0] : 0;
		return $this->NewObj3('Less_Tree_Attribute',array( $key, $_op, $val));
	}

	//
	// The `block` rule is used by `ruleset` and `mixin.definition`.
	// It's a wrapper around the `primary` rule, with added `{}`.
	//
	private function parseBlock(){
		if( $this->MatchChar('{') ){
			$content = $this->parsePrimary();
			if( $this->MatchChar('}') ){
				return $content;
			}
		}
	}

	private function parseBlockRuleset(){
		$block = $this->parseBlock();

		if( $block ){
			$block = $this->NewObj2('Less_Tree_Ruleset',array( null, $block));
		}

		return $block;
	}

	private function parseDetachedRuleset(){
		$blockRuleset = $this->parseBlockRuleset();
		if( $blockRuleset ){
			return $this->NewObj1('Less_Tree_DetachedRuleset',$blockRuleset);
		}
	}

	//
	// div, .class, body > p {...}
	//
	private function parseRuleset(){
		$selectors = array();

		$this->save();

		while( true ){
			$s = $this->parseLessSelector();
			if( !$s ){
				break;
			}
			$selectors[] = $s;
			$this->parseComments();

			if( $s->condition && count($selectors) > 1 ){
				$this->Error('Guards are only currently allowed on a single selector.');
			}

			if( !$this->MatchChar(',') ){
				break;
			}
			if( $s->condition ){
				$this->Error('Guards are only currently allowed on a single selector.');
			}
			$this->parseComments();
		}


		if( $selectors ){
			$rules = $this->parseBlock();
			if( is_array($rules) ){
				$this->forget();
				return $this->NewObj2('Less_Tree_Ruleset',array( $selectors, $rules)); //Less_Environment::$strictImports
			}
		}

		// Backtrack
		$this->furthest = $this->pos;
		$this->restore();
	}

	/**
	 * Custom less.php parse function for finding simple name-value css pairs
	 * ex: width:100px;
	 *
	 */
	private function parseNameValue(){

		$index = $this->pos;
		$this->save();


		//$match = $this->MatchReg('/\\G([a-zA-Z\-]+)\s*:\s*((?:\'")?[a-zA-Z0-9\-% \.,!]+?(?:\'")?)\s*([;}])/');
		$match = $this->MatchReg('/\\G([a-zA-Z\-]+)\s*:\s*([\'"]?[#a-zA-Z0-9\-%\.,]+?[\'"]?) *(! *important)?\s*([;}])/');
		if( $match ){

			if( $match[4] == '}' ){
				$this->pos = $index + strlen($match[0])-1;
			}

			if( $match[3] ){
				$match[2] .= ' !important';
			}

			return $this->NewObj4('Less_Tree_NameValue',array( $match[1], $match[2], $index, $this->env->currentFileInfo));
		}

		$this->restore();
	}


	private function parseRule( $tryAnonymous = null ){

		$merge = false;
		$startOfRule = $this->pos;

		$c = $this->input[$this->pos];
		if( $c === '.' || $c === '#' || $c === '&' ){
			return;
		}

		$this->save();
		$name = $this->MatchFuncs( array('parseVariable','parseRuleProperty'));

		if( $name ){

			$isVariable = is_string($name);

			$value = null;
			if( $isVariable ){
				$value = $this->parseDetachedRuleset();
			}

			$important = null;
			if( !$value ){

				// prefer to try to parse first if its a variable or we are compressing
				// but always fallback on the other one
				//if( !$tryAnonymous && is_string($name) && $name[0] === '@' ){
				if( !$tryAnonymous && (Less_Parser::$options['compress'] || $isVariable) ){
					$value = $this->MatchFuncs( array('parseValue','parseAnonymousValue'));
				}else{
					$value = $this->MatchFuncs( array('parseAnonymousValue','parseValue'));
				}

				$important = $this->parseImportant();

				// a name returned by this.ruleProperty() is always an array of the form:
				// [string-1, ..., string-n, ""] or [string-1, ..., string-n, "+"]
				// where each item is a tree.Keyword or tree.Variable
				if( !$isVariable && is_array($name) ){
					$nm = array_pop($name);
					if( $nm->value ){
						$merge = $nm->value;
					}
				}
			}


			if( $value && $this->parseEnd() ){
				$this->forget();
				return $this->NewObj6('Less_Tree_Rule',array( $name, $value, $important, $merge, $startOfRule, $this->env->currentFileInfo));
			}else{
				$this->furthest = $this->pos;
				$this->restore();
				if( $value && !$tryAnonymous ){
					return $this->parseRule(true);
				}
			}
		}else{
			$this->forget();
		}
	}

	function parseAnonymousValue(){

		if( preg_match('/\\G([^@+\/\'"*`(;{}-]*);/',$this->input, $match, 0, $this->pos) ){
			$this->pos += strlen($match[1]);
			return $this->NewObj1('Less_Tree_Anonymous',$match[1]);
		}
	}

	//
	// An @import directive
	//
	//	 @import "lib";
	//
	// Depending on our environment, importing is done differently:
	// In the browser, it's an XHR request, in Node, it would be a
	// file-system operation. The function used for importing is
	// stored in `import`, which we pass to the Import constructor.
	//
	private function parseImport(){

		$this->save();

		$dir = $this->MatchReg('/\\G@import?\s+/');

		if( $dir ){
			$options = $this->parseImportOptions();
			$path = $this->MatchFuncs( array('parseEntitiesQuoted','parseEntitiesUrl'));

			if( $path ){
				$features = $this->parseMediaFeatures();
				if( $this->MatchChar(';') ){
					if( $features ){
						$features = $this->NewObj1('Less_Tree_Value',$features);
					}

					$this->forget();
					return $this->NewObj5('Less_Tree_Import',array( $path, $features, $options, $this->pos, $this->env->currentFileInfo));
				}
			}
		}

		$this->restore();
	}

	private function parseImportOptions(){

		$options = array();

		// list of options, surrounded by parens
		if( !$this->MatchChar('(') ){
			return $options;
		}
		do{
			$optionName = $this->parseImportOption();
			if( $optionName ){
				$value = true;
				switch( $optionName ){
					case "css":
						$optionName = "less";
						$value = false;
					break;
					case "once":
						$optionName = "multiple";
						$value = false;
					break;
				}
				$options[$optionName] = $value;
				if( !$this->MatchChar(',') ){ break; }
			}
		}while( $optionName );
		$this->expectChar(')');
		return $options;
	}

	private function parseImportOption(){
		$opt = $this->MatchReg('/\\G(less|css|multiple|once|inline|reference)/');
		if( $opt ){
			return $opt[1];
		}
	}

	private function parseMediaFeature() {
		$nodes = array();

		do{
			$e = $this->MatchFuncs(array('parseEntitiesKeyword','parseEntitiesVariable'));
			if( $e ){
				$nodes[] = $e;
			} elseif ($this->MatchChar('(')) {
				$p = $this->parseProperty();
				$e = $this->parseValue();
				if ($this->MatchChar(')')) {
					if ($p && $e) {
						$r = $this->NewObj7('Less_Tree_Rule', array( $p, $e, null, null, $this->pos, $this->env->currentFileInfo, true));
						$nodes[] = $this->NewObj1('Less_Tree_Paren',$r);
					} elseif ($e) {
						$nodes[] = $this->NewObj1('Less_Tree_Paren',$e);
					} else {
						return null;
					}
				} else
					return null;
			}
		} while ($e);

		if ($nodes) {
			return $this->NewObj1('Less_Tree_Expression',$nodes);
		}
	}

	private function parseMediaFeatures() {
		$features = array();

		do{
			$e = $this->parseMediaFeature();
			if( $e ){
				$features[] = $e;
				if (!$this->MatchChar(',')) break;
			}else{
				$e = $this->parseEntitiesVariable();
				if( $e ){
					$features[] = $e;
					if (!$this->MatchChar(',')) break;
				}
			}
		} while ($e);

		return $features ? $features : null;
	}

	private function parseMedia() {
		if( $this->MatchReg('/\\G@media/') ){
			$features = $this->parseMediaFeatures();
			$rules = $this->parseBlock();

			if( is_array($rules) ){
				return $this->NewObj4('Less_Tree_Media',array( $rules, $features, $this->pos, $this->env->currentFileInfo));
			}
		}
	}


	//
	// A CSS Directive
	//
	// @charset "utf-8";
	//
	private function parseDirective(){

		if( !$this->PeekChar('@') ){
			return;
		}

		$rules = null;
		$index = $this->pos;
		$hasBlock = true;
		$hasIdentifier = false;
		$hasExpression = false;
		$hasUnknown = false;


		$value = $this->MatchFuncs(array('parseImport','parseMedia'));
		if( $value ){
			return $value;
		}

		$this->save();

		$name = $this->MatchReg('/\\G@[a-z-]+/');

		if( !$name ) return;
		$name = $name[0];


		$nonVendorSpecificName = $name;
		$pos = strpos($name,'-', 2);
		if( $name[1] == '-' && $pos > 0 ){
			$nonVendorSpecificName = "@" . substr($name, $pos + 1);
		}


		switch( $nonVendorSpecificName ){
			/*
			case "@font-face":
			case "@viewport":
			case "@top-left":
			case "@top-left-corner":
			case "@top-center":
			case "@top-right":
			case "@top-right-corner":
			case "@bottom-left":
			case "@bottom-left-corner":
			case "@bottom-center":
			case "@bottom-right":
			case "@bottom-right-corner":
			case "@left-top":
			case "@left-middle":
			case "@left-bottom":
			case "@right-top":
			case "@right-middle":
			case "@right-bottom":
			hasBlock = true;
			break;
			*/
			case "@charset":
				$hasIdentifier = true;
				$hasBlock = false;
				break;
			case "@namespace":
				$hasExpression = true;
				$hasBlock = false;
				break;
			case "@keyframes":
				$hasIdentifier = true;
				break;
			case "@host":
			case "@page":
			case "@document":
			case "@supports":
				$hasUnknown = true;
				break;
		}

		if( $hasIdentifier ){
			$value = $this->parseEntity();
			if( !$value ){
				$this->error("expected " . $name . " identifier");
			}
		} else if( $hasExpression ){
			$value = $this->parseExpression();
			if( !$value ){
				$this->error("expected " . $name. " expression");
			}
		} else if ($hasUnknown) {

			$value = $this->MatchReg('/\\G[^{;]+/');
			if( $value ){
				$value = $this->NewObj1('Less_Tree_Anonymous',trim($value[0]));
			}
		}

		if( $hasBlock ){
			$rules = $this->parseBlockRuleset();
		}

		if( $rules || (!$hasBlock && $value && $this->MatchChar(';'))) {
			$this->forget();
			return $this->NewObj5('Less_Tree_Directive',array($name, $value, $rules, $index, $this->env->currentFileInfo));
		}

		$this->restore();
	}


	//
	// A Value is a comma-delimited list of Expressions
	//
	//	 font-family: Baskerville, Georgia, serif;
	//
	// In a Rule, a Value represents everything after the `:`,
	// and before the `;`.
	//
	private function parseValue(){
		$expressions = array();

		do{
			$e = $this->parseExpression();
			if( $e ){
				$expressions[] = $e;
				if (! $this->MatchChar(',')) {
					break;
				}
			}
		}while($e);

		if( $expressions ){
			return $this->NewObj1('Less_Tree_Value',$expressions);
		}
	}

	private function parseImportant (){
		if( $this->PeekChar('!') && $this->MatchReg('/\\G! *important/') ){
			return ' !important';
		}
	}

	private function parseSub (){

		if( $this->MatchChar('(') ){
			$a = $this->parseAddition();
			if( $a ){
				$this->expectChar(')');
				return $this->NewObj2('Less_Tree_Expression',array( array($a), true) ); //instead of $e->parens = true so the value is cached
			}
		}
	}


	/**
	 * Parses multiplication operation
	 *
	 * @return Less_Tree_Operation|null
	 */
	function parseMultiplication(){

		$return = $m = $this->parseOperand();
		if( $return ){
			while( true ){

				$isSpaced = $this->isWhitespace( -1 );

				if( $this->PeekReg('/\\G\/[*\/]/') ){
					break;
				}

				$op = $this->MatchChar('/');
				if( !$op ){
					$op = $this->MatchChar('*');
					if( !$op ){
						break;
					}
				}

				$a = $this->parseOperand();

				if(!$a) { break; }

				$m->parensInOp = true;
				$a->parensInOp = true;
				$return = $this->NewObj3('Less_Tree_Operation',array( $op, array( $return, $a ), $isSpaced) );
			}
		}
		return $return;

	}


	/**
	 * Parses an addition operation
	 *
	 * @return Less_Tree_Operation|null
	 */
	private function parseAddition (){

		$return = $m = $this->parseMultiplication();
		if( $return ){
			while( true ){

				$isSpaced = $this->isWhitespace( -1 );

				$op = $this->MatchReg('/\\G[-+]\s+/');
				if( $op ){
					$op = $op[0];
				}else{
					if( !$isSpaced ){
						$op = $this->match(array('#+','#-'));
					}
					if( !$op ){
						break;
					}
				}

				$a = $this->parseMultiplication();
				if( !$a ){
					break;
				}

				$m->parensInOp = true;
				$a->parensInOp = true;
				$return = $this->NewObj3('Less_Tree_Operation',array($op, array($return, $a), $isSpaced));
			}
		}

		return $return;
	}


	/**
	 * Parses the conditions
	 *
	 * @return Less_Tree_Condition|null
	 */
	private function parseConditions() {
		$index = $this->pos;
		$return = $a = $this->parseCondition();
		if( $a ){
			while( true ){
				if( !$this->PeekReg('/\\G,\s*(not\s*)?\(/') ||  !$this->MatchChar(',') ){
					break;
				}
				$b = $this->parseCondition();
				if( !$b ){
					break;
				}

				$return = $this->NewObj4('Less_Tree_Condition',array('or', $return, $b, $index));
			}
			return $return;
		}
	}

	private function parseCondition() {
		$index = $this->pos;
		$negate = false;
		$c = null;

		if ($this->MatchReg('/\\Gnot/')) $negate = true;
		$this->expectChar('(');
		$a = $this->MatchFuncs(array('parseAddition','parseEntitiesKeyword','parseEntitiesQuoted'));

		if( $a ){
			$op = $this->MatchReg('/\\G(?:>=|<=|=<|[<=>])/');
			if( $op ){
				$b = $this->MatchFuncs(array('parseAddition','parseEntitiesKeyword','parseEntitiesQuoted'));
				if( $b ){
					$c = $this->NewObj5('Less_Tree_Condition',array($op[0], $a, $b, $index, $negate));
				} else {
					$this->Error('Unexpected expression');
				}
			} else {
				$k = $this->NewObj1('Less_Tree_Keyword','true');
				$c = $this->NewObj5('Less_Tree_Condition',array('=', $a, $k, $index, $negate));
			}
			$this->expectChar(')');
			return $this->MatchReg('/\\Gand/') ? $this->NewObj3('Less_Tree_Condition',array('and', $c, $this->parseCondition())) : $c;
		}
	}

	/**
	 * An operand is anything that can be part of an operation,
	 * such as a Color, or a Variable
	 *
	 */
	private function parseOperand (){

		$negate = false;
		$offset = $this->pos+1;
		if( $offset >= $this->input_len ){
			return;
		}
		$char = $this->input[$offset];
		if( $char === '@' || $char === '(' ){
			$negate = $this->MatchChar('-');
		}

		$o = $this->MatchFuncs(array('parseSub','parseEntitiesDimension','parseEntitiesColor','parseEntitiesVariable','parseEntitiesCall'));

		if( $negate ){
			$o->parensInOp = true;
			$o = $this->NewObj1('Less_Tree_Negative',$o);
		}

		return $o;
	}


	/**
	 * Expressions either represent mathematical operations,
	 * or white-space delimited Entities.
	 *
	 *	 1px solid black
	 *	 @var * 2
	 *
	 * @return Less_Tree_Expression|null
	 */
	private function parseExpression (){
		$entities = array();

		do{
			$e = $this->MatchFuncs(array('parseAddition','parseEntity'));
			if( $e ){
				$entities[] = $e;
				// operations do not allow keyword "/" dimension (e.g. small/20px) so we support that here
				if( !$this->PeekReg('/\\G\/[\/*]/') ){
					$delim = $this->MatchChar('/');
					if( $delim ){
						$entities[] = $this->NewObj1('Less_Tree_Anonymous',$delim);
					}
				}
			}
		}while($e);

		if( $entities ){
			return $this->NewObj1('Less_Tree_Expression',$entities);
		}
	}


	/**
	 * Parse a property
	 * eg: 'min-width', 'orientation', etc
	 *
	 * @return string
	 */
	private function parseProperty (){
		$name = $this->MatchReg('/\\G(\*?-?[_a-zA-Z0-9-]+)\s*:/');
		if( $name ){
			return $name[1];
		}
	}


	/**
	 * Parse a rule property
	 * eg: 'color', 'width', 'height', etc
	 *
	 * @return string
	 */
	private function parseRuleProperty(){
		$offset = $this->pos;
		$name = array();
		$index = array();
		$length = 0;


		$this->rulePropertyMatch('/\\G(\*?)/', $offset, $length, $index, $name );
		while( $this->rulePropertyMatch('/\\G((?:[\w-]+)|(?:@\{[\w-]+\}))/', $offset, $length, $index, $name )); // !

		if( (count($name) > 1) && $this->rulePropertyMatch('/\\G\s*((?:\+_|\+)?)\s*:/', $offset, $length, $index, $name) ){
			// at last, we have the complete match now. move forward,
			// convert name particles to tree objects and return:
			$this->skipWhitespace($length);

			if( $name[0] === '' ){
				array_shift($name);
				array_shift($index);
			}
			foreach($name as $k => $s ){
				if( !$s || $s[0] !== '@' ){
					$name[$k] = $this->NewObj1('Less_Tree_Keyword',$s);
				}else{
					$name[$k] = $this->NewObj3('Less_Tree_Variable',array('@' . substr($s,2,-1), $index[$k], $this->env->currentFileInfo));
				}
			}
			return $name;
		}


	}

	private function rulePropertyMatch( $re, &$offset, &$length,  &$index, &$name ){
		preg_match($re, $this->input, $a, 0, $offset);
		if( $a ){
			$index[] = $this->pos + $length;
			$length += strlen($a[0]);
			$offset += strlen($a[0]);
			$name[] = $a[1];
			return true;
		}
	}

	public function serializeVars( $vars ){
		$s = '';

		foreach($vars as $name => $value){
			$s .= (($name[0] === '@') ? '' : '@') . $name .': '. $value . ((substr($value,-1) === ';') ? '' : ';');
		}

		return $s;
	}


	/**
	 * Some versions of php have trouble with method_exists($a,$b) if $a is not an object
	 *
	 * @param string $b
	 */
	public static function is_method($a,$b){
		return is_object($a) && method_exists($a,$b);
	}


	/**
	 * Round numbers similarly to javascript
	 * eg: 1.499999 to 1 instead of 2
	 *
	 */
	public static function round($i, $precision = 0){

		$precision = pow(10,$precision);
		$i = $i*$precision;

		$ceil = ceil($i);
		$floor = floor($i);
		if( ($ceil - $i) <= ($i - $floor) ){
			return $ceil/$precision;
		}else{
			return $floor/$precision;
		}
	}


	/**
	 * Create Less_Tree_* objects and optionally generate a cache string
	 *
	 * @return mixed
	 */
	public function NewObj0($class){
		$obj = new $class();
		if( Less_Cache::$cache_dir ){
			$obj->cache_string = ' new '.$class.'()';
		}
		return $obj;
	}

	public function NewObj1($class, $arg){
		$obj = new $class( $arg );
		if( Less_Cache::$cache_dir ){
			$obj->cache_string = ' new '.$class.'('.Less_Parser::ArgString($arg).')';
		}
		return $obj;
	}

	public function NewObj2($class, $args){
		$obj = new $class( $args[0], $args[1] );
		if( Less_Cache::$cache_dir ){
			$this->ObjCache( $obj, $class, $args);
		}
		return $obj;
	}

	public function NewObj3($class, $args){
		$obj = new $class( $args[0], $args[1], $args[2] );
		if( Less_Cache::$cache_dir ){
			$this->ObjCache( $obj, $class, $args);
		}
		return $obj;
	}

	public function NewObj4($class, $args){
		$obj = new $class( $args[0], $args[1], $args[2], $args[3] );
		if( Less_Cache::$cache_dir ){
			$this->ObjCache( $obj, $class, $args);
		}
		return $obj;
	}

	public function NewObj5($class, $args){
		$obj = new $class( $args[0], $args[1], $args[2], $args[3], $args[4] );
		if( Less_Cache::$cache_dir ){
			$this->ObjCache( $obj, $class, $args);
		}
		return $obj;
	}

	public function NewObj6($class, $args){
		$obj = new $class( $args[0], $args[1], $args[2], $args[3], $args[4], $args[5] );
		if( Less_Cache::$cache_dir ){
			$this->ObjCache( $obj, $class, $args);
		}
		return $obj;
	}

	public function NewObj7($class, $args){
		$obj = new $class( $args[0], $args[1], $args[2], $args[3], $args[4], $args[5], $args[6] );
		if( Less_Cache::$cache_dir ){
			$this->ObjCache( $obj, $class, $args);
		}
		return $obj;
	}

	//caching
	public function ObjCache($obj, $class, $args=array()){
		$obj->cache_string = ' new '.$class.'('. self::ArgCache($args).')';
	}

	public function ArgCache($args){
		return implode(',',array_map( array('Less_Parser','ArgString'),$args));
	}


	/**
	 * Convert an argument to a string for use in the parser cache
	 *
	 * @return string
	 */
	public static function ArgString($arg){

		$type = gettype($arg);

		if( $type === 'object'){
			$string = $arg->cache_string;
			unset($arg->cache_string);
			return $string;

		}elseif( $type === 'array' ){
			$string = ' Array(';
			foreach($arg as $k => $a){
				$string .= var_export($k,true).' => '.self::ArgString($a).',';
			}
			return $string . ')';
		}

		return var_export($arg,true);
	}

	public function Error($msg){
		throw new Less_Exception_Parser($msg, null, $this->furthest, $this->env->currentFileInfo);
	}

	public static function WinPath($path){
		return str_replace('\\', '/', $path);
	}

}


 

/**
 * Utility for css colors
 *
 * @package Less
 * @subpackage color
 */
class Less_Colors {

	public static $colors = array(
			'aliceblue'=>'#f0f8ff',
			'antiquewhite'=>'#faebd7',
			'aqua'=>'#00ffff',
			'aquamarine'=>'#7fffd4',
			'azure'=>'#f0ffff',
			'beige'=>'#f5f5dc',
			'bisque'=>'#ffe4c4',
			'black'=>'#000000',
			'blanchedalmond'=>'#ffebcd',
			'blue'=>'#0000ff',
			'blueviolet'=>'#8a2be2',
			'brown'=>'#a52a2a',
			'burlywood'=>'#deb887',
			'cadetblue'=>'#5f9ea0',
			'chartreuse'=>'#7fff00',
			'chocolate'=>'#d2691e',
			'coral'=>'#ff7f50',
			'cornflowerblue'=>'#6495ed',
			'cornsilk'=>'#fff8dc',
			'crimson'=>'#dc143c',
			'cyan'=>'#00ffff',
			'darkblue'=>'#00008b',
			'darkcyan'=>'#008b8b',
			'darkgoldenrod'=>'#b8860b',
			'darkgray'=>'#a9a9a9',
			'darkgrey'=>'#a9a9a9',
			'darkgreen'=>'#006400',
			'darkkhaki'=>'#bdb76b',
			'darkmagenta'=>'#8b008b',
			'darkolivegreen'=>'#556b2f',
			'darkorange'=>'#ff8c00',
			'darkorchid'=>'#9932cc',
			'darkred'=>'#8b0000',
			'darksalmon'=>'#e9967a',
			'darkseagreen'=>'#8fbc8f',
			'darkslateblue'=>'#483d8b',
			'darkslategray'=>'#2f4f4f',
			'darkslategrey'=>'#2f4f4f',
			'darkturquoise'=>'#00ced1',
			'darkviolet'=>'#9400d3',
			'deeppink'=>'#ff1493',
			'deepskyblue'=>'#00bfff',
			'dimgray'=>'#696969',
			'dimgrey'=>'#696969',
			'dodgerblue'=>'#1e90ff',
			'firebrick'=>'#b22222',
			'floralwhite'=>'#fffaf0',
			'forestgreen'=>'#228b22',
			'fuchsia'=>'#ff00ff',
			'gainsboro'=>'#dcdcdc',
			'ghostwhite'=>'#f8f8ff',
			'gold'=>'#ffd700',
			'goldenrod'=>'#daa520',
			'gray'=>'#808080',
			'grey'=>'#808080',
			'green'=>'#008000',
			'greenyellow'=>'#adff2f',
			'honeydew'=>'#f0fff0',
			'hotpink'=>'#ff69b4',
			'indianred'=>'#cd5c5c',
			'indigo'=>'#4b0082',
			'ivory'=>'#fffff0',
			'khaki'=>'#f0e68c',
			'lavender'=>'#e6e6fa',
			'lavenderblush'=>'#fff0f5',
			'lawngreen'=>'#7cfc00',
			'lemonchiffon'=>'#fffacd',
			'lightblue'=>'#add8e6',
			'lightcoral'=>'#f08080',
			'lightcyan'=>'#e0ffff',
			'lightgoldenrodyellow'=>'#fafad2',
			'lightgray'=>'#d3d3d3',
			'lightgrey'=>'#d3d3d3',
			'lightgreen'=>'#90ee90',
			'lightpink'=>'#ffb6c1',
			'lightsalmon'=>'#ffa07a',
			'lightseagreen'=>'#20b2aa',
			'lightskyblue'=>'#87cefa',
			'lightslategray'=>'#778899',
			'lightslategrey'=>'#778899',
			'lightsteelblue'=>'#b0c4de',
			'lightyellow'=>'#ffffe0',
			'lime'=>'#00ff00',
			'limegreen'=>'#32cd32',
			'linen'=>'#faf0e6',
			'magenta'=>'#ff00ff',
			'maroon'=>'#800000',
			'mediumaquamarine'=>'#66cdaa',
			'mediumblue'=>'#0000cd',
			'mediumorchid'=>'#ba55d3',
			'mediumpurple'=>'#9370d8',
			'mediumseagreen'=>'#3cb371',
			'mediumslateblue'=>'#7b68ee',
			'mediumspringgreen'=>'#00fa9a',
			'mediumturquoise'=>'#48d1cc',
			'mediumvioletred'=>'#c71585',
			'midnightblue'=>'#191970',
			'mintcream'=>'#f5fffa',
			'mistyrose'=>'#ffe4e1',
			'moccasin'=>'#ffe4b5',
			'navajowhite'=>'#ffdead',
			'navy'=>'#000080',
			'oldlace'=>'#fdf5e6',
			'olive'=>'#808000',
			'olivedrab'=>'#6b8e23',
			'orange'=>'#ffa500',
			'orangered'=>'#ff4500',
			'orchid'=>'#da70d6',
			'palegoldenrod'=>'#eee8aa',
			'palegreen'=>'#98fb98',
			'paleturquoise'=>'#afeeee',
			'palevioletred'=>'#d87093',
			'papayawhip'=>'#ffefd5',
			'peachpuff'=>'#ffdab9',
			'peru'=>'#cd853f',
			'pink'=>'#ffc0cb',
			'plum'=>'#dda0dd',
			'powderblue'=>'#b0e0e6',
			'purple'=>'#800080',
			'red'=>'#ff0000',
			'rosybrown'=>'#bc8f8f',
			'royalblue'=>'#4169e1',
			'saddlebrown'=>'#8b4513',
			'salmon'=>'#fa8072',
			'sandybrown'=>'#f4a460',
			'seagreen'=>'#2e8b57',
			'seashell'=>'#fff5ee',
			'sienna'=>'#a0522d',
			'silver'=>'#c0c0c0',
			'skyblue'=>'#87ceeb',
			'slateblue'=>'#6a5acd',
			'slategray'=>'#708090',
			'slategrey'=>'#708090',
			'snow'=>'#fffafa',
			'springgreen'=>'#00ff7f',
			'steelblue'=>'#4682b4',
			'tan'=>'#d2b48c',
			'teal'=>'#008080',
			'thistle'=>'#d8bfd8',
			'tomato'=>'#ff6347',
			'turquoise'=>'#40e0d0',
			'violet'=>'#ee82ee',
			'wheat'=>'#f5deb3',
			'white'=>'#ffffff',
			'whitesmoke'=>'#f5f5f5',
			'yellow'=>'#ffff00',
			'yellowgreen'=>'#9acd32'
		);

	public static function hasOwnProperty($color) {
		return isset(self::$colors[$color]);
	}


	public static function color($color) {
		return self::$colors[$color];
	}

}
 


/**
 * Environment
 *
 * @package Less
 * @subpackage environment
 */
class Less_Environment{

	//public $paths = array();				// option - unmodified - paths to search for imports on
	//public static $files = array();		// list of files that have been imported, used for import-once
	//public $rootpath;						// option - rootpath to append to URL's
	//public static $strictImports = null;	// option -
	//public $insecure;						// option - whether to allow imports from insecure ssl hosts
	//public $processImports;				// option - whether to process imports. if false then imports will not be imported
	//public $javascriptEnabled;			// option - whether JavaScript is enabled. if undefined, defaults to true
	//public $useFileCache;					// browser only - whether to use the per file session cache
	public $currentFileInfo;				// information about the current file - for error reporting and importing and making urls relative etc.

	public $importMultiple = false; 		// whether we are currently importing multiple copies


	/**
	 * @var array
	 */
	public $frames = array();

	/**
	 * @var array
	 */
	public $mediaBlocks = array();

	/**
	 * @var array
	 */
	public $mediaPath = array();

	public static $parensStack = 0;

	public static $tabLevel = 0;

	public static $lastRule = false;

	public static $_outputMap;

	public static $mixin_stack = 0;


	public function Init(){

		self::$parensStack = 0;
		self::$tabLevel = 0;
		self::$lastRule = false;
		self::$mixin_stack = 0;

		if( Less_Parser::$options['compress'] ){

			Less_Environment::$_outputMap = array(
				','	=> ',',
				': ' => ':',
				''  => '',
				' ' => ' ',
				':' => ' :',
				'+' => '+',
				'~' => '~',
				'>' => '>',
				'|' => '|',
		        '^' => '^',
		        '^^' => '^^'
			);

		}else{

			Less_Environment::$_outputMap = array(
				','	=> ', ',
				': ' => ': ',
				''  => '',
				' ' => ' ',
				':' => ' :',
				'+' => ' + ',
				'~' => ' ~ ',
				'>' => ' > ',
				'|' => '|',
		        '^' => ' ^ ',
		        '^^' => ' ^^ '
			);

		}
	}


	public function copyEvalEnv($frames = array() ){
		$new_env = new Less_Environment();
		$new_env->frames = $frames;
		return $new_env;
	}


	public static function isMathOn(){
		return !Less_Parser::$options['strictMath'] || Less_Environment::$parensStack;
	}

	public static function isPathRelative($path){
		return !preg_match('/^(?:[a-z-]+:|\/)/',$path);
	}


	/**
	 * Canonicalize a path by resolving references to '/./', '/../'
	 * Does not remove leading "../"
	 * @param string path or url
	 * @return string Canonicalized path
	 *
	 */
	static function normalizePath($path){

		$segments = explode('/',$path);
		$segments = array_reverse($segments);

		$path = array();
		$path_len = 0;

		while( $segments ){
			$segment = array_pop($segments);
			switch( $segment ) {

				case '.':
				break;

				case '..':
					if( !$path_len || ( $path[$path_len-1] === '..') ){
						$path[] = $segment;
						$path_len++;
					}else{
						array_pop($path);
						$path_len--;
					}
				break;

				default:
					$path[] = $segment;
					$path_len++;
				break;
			}
		}

		return implode('/',$path);
	}


	public function unshiftFrame($frame){
		array_unshift($this->frames, $frame);
	}

	public function shiftFrame(){
		return array_shift($this->frames);
	}

}
 

/**
 * Builtin functions
 *
 * @package Less
 * @subpackage function
 * @see http://lesscss.org/functions/
 */
class Less_Functions{

	public $env;
	public $currentFileInfo;

	function __construct($env, $currentFileInfo = null ){
		$this->env = $env;
		$this->currentFileInfo = $currentFileInfo;
	}


	/**
	 * @param string $op
	 */
	static public function operate( $op, $a, $b ){
		switch ($op) {
			case '+': return $a + $b;
			case '-': return $a - $b;
			case '*': return $a * $b;
			case '/': return $a / $b;
		}
	}

	static public function clamp($val, $max = 1){
		return min( max($val, 0), $max);
	}

	static function fround( $value ){

		if( $value === 0 ){
			return $value;
		}

		if( Less_Parser::$options['numPrecision'] ){
			$p = pow(10, Less_Parser::$options['numPrecision']);
			return round( $value * $p) / $p;
		}
		return $value;
	}

	static public function number($n){

		if ($n instanceof Less_Tree_Dimension) {
			return floatval( $n->unit->is('%') ? $n->value / 100 : $n->value);
		} else if (is_numeric($n)) {
			return $n;
		} else {
			throw new Less_Exception_Compiler("color functions take numbers as parameters");
		}
	}

	static public function scaled($n, $size = 255 ){
		if( $n instanceof Less_Tree_Dimension && $n->unit->is('%') ){
			return (float)$n->value * $size / 100;
		} else {
			return Less_Functions::number($n);
		}
	}

	public function rgb ($r, $g, $b){
		return $this->rgba($r, $g, $b, 1.0);
	}

	public function rgba($r, $g, $b, $a){
		$rgb = array($r, $g, $b);
		$rgb = array_map(array('Less_Functions','scaled'),$rgb);

		$a = self::number($a);
		return new Less_Tree_Color($rgb, $a);
	}

	public function hsl($h, $s, $l){
		return $this->hsla($h, $s, $l, 1.0);
	}

	public function hsla($h, $s, $l, $a){

		$h = fmod(self::number($h), 360) / 360; // Classic % operator will change float to int
		$s = self::clamp(self::number($s));
		$l = self::clamp(self::number($l));
		$a = self::clamp(self::number($a));

		$m2 = $l <= 0.5 ? $l * ($s + 1) : $l + $s - $l * $s;

		$m1 = $l * 2 - $m2;

		return $this->rgba( self::hsla_hue($h + 1/3, $m1, $m2) * 255,
							self::hsla_hue($h, $m1, $m2) * 255,
							self::hsla_hue($h - 1/3, $m1, $m2) * 255,
							$a);
	}

	/**
	 * @param double $h
	 */
	function hsla_hue($h, $m1, $m2){
		$h = $h < 0 ? $h + 1 : ($h > 1 ? $h - 1 : $h);
		if	  ($h * 6 < 1) return $m1 + ($m2 - $m1) * $h * 6;
		else if ($h * 2 < 1) return $m2;
		else if ($h * 3 < 2) return $m1 + ($m2 - $m1) * (2/3 - $h) * 6;
		else				 return $m1;
	}

	public function hsv($h, $s, $v) {
		return $this->hsva($h, $s, $v, 1.0);
	}

	/**
	 * @param double $a
	 */
	public function hsva($h, $s, $v, $a) {
		$h = ((Less_Functions::number($h) % 360) / 360 ) * 360;
		$s = Less_Functions::number($s);
		$v = Less_Functions::number($v);
		$a = Less_Functions::number($a);

		$i = floor(($h / 60) % 6);
		$f = ($h / 60) - $i;

		$vs = array( $v,
				  $v * (1 - $s),
				  $v * (1 - $f * $s),
				  $v * (1 - (1 - $f) * $s));

		$perm = array(array(0, 3, 1),
					array(2, 0, 1),
					array(1, 0, 3),
					array(1, 2, 0),
					array(3, 1, 0),
					array(0, 1, 2));

		return $this->rgba($vs[$perm[$i][0]] * 255,
						 $vs[$perm[$i][1]] * 255,
						 $vs[$perm[$i][2]] * 255,
						 $a);
	}

	public function hue($color){
		$c = $color->toHSL();
		return new Less_Tree_Dimension(Less_Parser::round($c['h']));
	}

	public function saturation($color){
		$c = $color->toHSL();
		return new Less_Tree_Dimension(Less_Parser::round($c['s'] * 100), '%');
	}

	public function lightness($color){
		$c = $color->toHSL();
		return new Less_Tree_Dimension(Less_Parser::round($c['l'] * 100), '%');
	}

	public function hsvhue( $color ){
		$hsv = $color->toHSV();
		return new Less_Tree_Dimension( Less_Parser::round($hsv['h']) );
	}


	public function hsvsaturation( $color ){
		$hsv = $color->toHSV();
		return new Less_Tree_Dimension( Less_Parser::round($hsv['s'] * 100), '%' );
	}

	public function hsvvalue( $color ){
		$hsv = $color->toHSV();
		return new Less_Tree_Dimension( Less_Parser::round($hsv['v'] * 100), '%' );
	}

	public function red($color) {
		return new Less_Tree_Dimension( $color->rgb[0] );
	}

	public function green($color) {
		return new Less_Tree_Dimension( $color->rgb[1] );
	}

	public function blue($color) {
		return new Less_Tree_Dimension( $color->rgb[2] );
	}

	public function alpha($color){
		$c = $color->toHSL();
		return new Less_Tree_Dimension($c['a']);
	}

	public function luma ($color) {
		return new Less_Tree_Dimension(Less_Parser::round( $color->luma() * $color->alpha * 100), '%');
	}

	public function luminance( $color ){
		$luminance =
			(0.2126 * $color->rgb[0] / 255)
		  + (0.7152 * $color->rgb[1] / 255)
		  + (0.0722 * $color->rgb[2] / 255);

		return new Less_Tree_Dimension(Less_Parser::round( $luminance * $color->alpha * 100), '%');
	}

	public function saturate($color, $amount = null){
		// filter: saturate(3.2);
		// should be kept as is, so check for color
		if( !property_exists($color,'rgb') ){
			return null;
		}
		$hsl = $color->toHSL();

		$hsl['s'] += $amount->value / 100;
		$hsl['s'] = self::clamp($hsl['s']);

		return $this->hsla($hsl['h'], $hsl['s'], $hsl['l'], $hsl['a']);
	}

	/**
	 * @param Less_Tree_Dimension $amount
	 */
	public function desaturate($color, $amount){
		$hsl = $color->toHSL();

		$hsl['s'] -= $amount->value / 100;
		$hsl['s'] = self::clamp($hsl['s']);

		return $this->hsla($hsl['h'], $hsl['s'], $hsl['l'], $hsl['a']);
	}



	public function lighten($color, $amount){
		$hsl = $color->toHSL();

		$hsl['l'] += $amount->value / 100;
		$hsl['l'] = self::clamp($hsl['l']);

		return $this->hsla($hsl['h'], $hsl['s'], $hsl['l'], $hsl['a']);
	}

	public function darken($color, $amount){

		if( $color instanceof Less_Tree_Color ){
			$hsl = $color->toHSL();
			$hsl['l'] -= $amount->value / 100;
			$hsl['l'] = self::clamp($hsl['l']);

			return $this->hsla($hsl['h'], $hsl['s'], $hsl['l'], $hsl['a']);
		}

		Less_Functions::Expected('color',$color);
	}

	public function fadein($color, $amount){
		$hsl = $color->toHSL();
		$hsl['a'] += $amount->value / 100;
		$hsl['a'] = self::clamp($hsl['a']);
		return $this->hsla($hsl['h'], $hsl['s'], $hsl['l'], $hsl['a']);
	}

	public function fadeout($color, $amount){
		$hsl = $color->toHSL();
		$hsl['a'] -= $amount->value / 100;
		$hsl['a'] = self::clamp($hsl['a']);
		return $this->hsla($hsl['h'], $hsl['s'], $hsl['l'], $hsl['a']);
	}

	public function fade($color, $amount){
		$hsl = $color->toHSL();

		$hsl['a'] = $amount->value / 100;
		$hsl['a'] = self::clamp($hsl['a']);
		return $this->hsla($hsl['h'], $hsl['s'], $hsl['l'], $hsl['a']);
	}



	public function spin($color, $amount){
		$hsl = $color->toHSL();
		$hue = fmod($hsl['h'] + $amount->value, 360);

		$hsl['h'] = $hue < 0 ? 360 + $hue : $hue;

		return $this->hsla($hsl['h'], $hsl['s'], $hsl['l'], $hsl['a']);
	}

	//
	// Copyright (c) 2006-2009 Hampton Catlin, Nathan Weizenbaum, and Chris Eppstein
	// http://sass-lang.com
	//

	/**
	 * @param Less_Tree_Color $color1
	 */
	public function mix($color1, $color2, $weight = null){
		if (!$weight) {
			$weight = new Less_Tree_Dimension('50', '%');
		}

		$p = $weight->value / 100.0;
		$w = $p * 2 - 1;
		$hsl1 = $color1->toHSL();
		$hsl2 = $color2->toHSL();
		$a = $hsl1['a'] - $hsl2['a'];

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

		$rgb = array($color1->rgb[0] * $w1 + $color2->rgb[0] * $w2,
					 $color1->rgb[1] * $w1 + $color2->rgb[1] * $w2,
					 $color1->rgb[2] * $w1 + $color2->rgb[2] * $w2);

		$alpha = $color1->alpha * $p + $color2->alpha * (1 - $p);

		return new Less_Tree_Color($rgb, $alpha);
	}

	public function greyscale($color){
		return $this->desaturate($color, new Less_Tree_Dimension(100));
	}


	public function contrast( $color, $dark = null, $light = null, $threshold = null){
		// filter: contrast(3.2);
		// should be kept as is, so check for color
		if( !property_exists($color,'rgb') ){
			return null;
		}
		if( !$light ){
			$light = $this->rgba(255, 255, 255, 1.0);
		}
		if( !$dark ){
			$dark = $this->rgba(0, 0, 0, 1.0);
		}
		//Figure out which is actually light and dark!
		if( $dark->luma() > $light->luma() ){
			$t = $light;
			$light = $dark;
			$dark = $t;
		}
		if( !$threshold ){
			$threshold = 0.43;
		} else {
			$threshold = Less_Functions::number($threshold);
		}

		if( $color->luma() < $threshold ){
			return $light;
		} else {
			return $dark;
		}
	}

	public function e ($str){
		if( is_string($str) ){
			return new Less_Tree_Anonymous($str);
		}
		return new Less_Tree_Anonymous($str instanceof Less_Tree_JavaScript ? $str->expression : $str->value);
	}

	public function escape ($str){

		$revert = array('%21'=>'!', '%2A'=>'*', '%27'=>"'",'%3F'=>'?','%26'=>'&','%2C'=>',','%2F'=>'/','%40'=>'@','%2B'=>'+','%24'=>'$');

		return new Less_Tree_Anonymous(strtr(rawurlencode($str->value), $revert));
	}


	/**
	 * todo: This function will need some additional work to make it work the same as less.js
	 *
	 */
	public function replace( $string, $pattern, $replacement, $flags = null ){
		$result = $string->value;

		$expr = '/'.str_replace('/','\\/',$pattern->value).'/';
		if( $flags && $flags->value){
			$expr .= self::replace_flags($flags->value);
		}

		$result = preg_replace($expr,$replacement->value,$result);


		if( property_exists($string,'quote') ){
			return new Less_Tree_Quoted( $string->quote, $result, $string->escaped);
		}
		return new Less_Tree_Quoted( '', $result );
	}

	public static function replace_flags($flags){
		$flags = str_split($flags,1);
		$new_flags = '';

		foreach($flags as $flag){
			switch($flag){
				case 'e':
				case 'g':
				break;

				default:
				$new_flags .= $flag;
				break;
			}
		}

		return $new_flags;
	}

	public function _percent(){
		$string = func_get_arg(0);

		$args = func_get_args();
		array_shift($args);
		$result = $string->value;

		foreach($args as $arg){
			if( preg_match('/%[sda]/i',$result, $token) ){
				$token = $token[0];
				$value = stristr($token, 's') ? $arg->value : $arg->toCSS();
				$value = preg_match('/[A-Z]$/', $token) ? urlencode($value) : $value;
				$result = preg_replace('/%[sda]/i',$value, $result, 1);
			}
		}
		$result = str_replace('%%', '%', $result);

		return new Less_Tree_Quoted( $string->quote , $result, $string->escaped);
	}

    public function unit( $val, $unit = null) {
		if( !($val instanceof Less_Tree_Dimension) ){
			throw new Less_Exception_Compiler('The first argument to unit must be a number' . ($val instanceof Less_Tree_Operation ? '. Have you forgotten parenthesis?' : '.') );
		}

		if( $unit ){
			if( $unit instanceof Less_Tree_Keyword ){
				$unit = $unit->value;
			} else {
				$unit = $unit->toCSS();
			}
		} else {
			$unit = "";
		}
		return new Less_Tree_Dimension($val->value, $unit );
    }

	public function convert($val, $unit){
		return $val->convertTo($unit->value);
	}

	public function round($n, $f = false) {

		$fraction = 0;
		if( $f !== false ){
			$fraction = $f->value;
		}

		return $this->_math('Less_Parser::round',null, $n, $fraction);
	}

	public function pi(){
		return new Less_Tree_Dimension(M_PI);
	}

	public function mod($a, $b) {
		return new Less_Tree_Dimension( $a->value % $b->value, $a->unit);
	}



	public function pow($x, $y) {
		if( is_numeric($x) && is_numeric($y) ){
			$x = new Less_Tree_Dimension($x);
			$y = new Less_Tree_Dimension($y);
		}elseif( !($x instanceof Less_Tree_Dimension) || !($y instanceof Less_Tree_Dimension) ){
			throw new Less_Exception_Compiler('Arguments must be numbers');
		}

		return new Less_Tree_Dimension( pow($x->value, $y->value), $x->unit );
	}

	// var mathFunctions = [{name:"ce ...
	public function ceil( $n ){		return $this->_math('ceil', null, $n); }
	public function floor( $n ){	return $this->_math('floor', null, $n); }
	public function sqrt( $n ){		return $this->_math('sqrt', null, $n); }
	public function abs( $n ){		return $this->_math('abs', null, $n); }

	public function tan( $n ){		return $this->_math('tan', '', $n);	}
	public function sin( $n ){		return $this->_math('sin', '', $n);	}
	public function cos( $n ){		return $this->_math('cos', '', $n);	}

	public function atan( $n ){		return $this->_math('atan', 'rad', $n);	}
	public function asin( $n ){		return $this->_math('asin', 'rad', $n);	}
	public function acos( $n ){		return $this->_math('acos', 'rad', $n);	}

	private function _math() {
		$args = func_get_args();
		$fn = array_shift($args);
		$unit = array_shift($args);

		if ($args[0] instanceof Less_Tree_Dimension) {

			if( $unit === null ){
				$unit = $args[0]->unit;
			}else{
				$args[0] = $args[0]->unify();
			}
			$args[0] = (float)$args[0]->value;
			return new Less_Tree_Dimension( call_user_func_array($fn, $args), $unit);
		} else if (is_numeric($args[0])) {
			return call_user_func_array($fn,$args);
		} else {
			throw new Less_Exception_Compiler("math functions take numbers as parameters");
		}
	}

	/**
	 * @param boolean $isMin
	 */
	function _minmax( $isMin, $args ){

		$arg_count = count($args);

		if( $arg_count < 1 ){
			throw new Less_Exception_Compiler( 'one or more arguments required');
		}

		$j = null;
		$unitClone = null;
		$unitStatic = null;


		$order = array();	// elems only contains original argument values.
		$values = array();	// key is the unit.toString() for unified tree.Dimension values,
							// value is the index into the order array.


		for( $i = 0; $i < $arg_count; $i++ ){
			$current = $args[$i];
			if( !($current instanceof Less_Tree_Dimension) ){
				if( is_array($args[$i]->value) ){
					$args[] = $args[$i]->value;
				}
				continue;
			}

			if( $current->unit->toString() === '' && !$unitClone ){
				$temp = new Less_Tree_Dimension($current->value, $unitClone);
				$currentUnified = $temp->unify();
			}else{
				$currentUnified = $current->unify();
			}

			if( $currentUnified->unit->toString() === "" && !$unitStatic ){
				$unit = $unitStatic;
			}else{
				$unit = $currentUnified->unit->toString();
			}

			if( $unit !== '' && !$unitStatic || $unit !== '' && $order[0]->unify()->unit->toString() === "" ){
				$unitStatic = $unit;
			}

			if( $unit != '' && !$unitClone ){
				$unitClone = $current->unit->toString();
			}

			if( isset($values['']) && $unit !== '' && $unit === $unitStatic ){
				$j = $values[''];
			}elseif( isset($values[$unit]) ){
				$j = $values[$unit];
			}else{

				if( $unitStatic && $unit !== $unitStatic ){
					throw new Less_Exception_Compiler( 'incompatible types');
				}
				$values[$unit] = count($order);
				$order[] = $current;
				continue;
			}


			if( $order[$j]->unit->toString() === "" && $unitClone ){
				$temp = new Less_Tree_Dimension( $order[$j]->value, $unitClone);
				$referenceUnified = $temp->unifiy();
			}else{
				$referenceUnified = $order[$j]->unify();
			}
			if( ($isMin && $currentUnified->value < $referenceUnified->value) || (!$isMin && $currentUnified->value > $referenceUnified->value) ){
				$order[$j] = $current;
			}
		}

		if( count($order) == 1 ){
			return $order[0];
		}
		$args = array();
		foreach($order as $a){
			$args[] = $a->toCSS($this->env);
		}
		return new Less_Tree_Anonymous( ($isMin?'min(':'max(') . implode(Less_Environment::$_outputMap[','],$args).')');
	}

	public function min(){
		$args = func_get_args();
		return $this->_minmax( true, $args );
	}

	public function max(){
		$args = func_get_args();
		return $this->_minmax( false, $args );
	}

	public function getunit($n){
		return new Less_Tree_Anonymous($n->unit);
	}

	public function argb($color) {
		return new Less_Tree_Anonymous($color->toARGB());
	}

	public function percentage($n) {
		return new Less_Tree_Dimension($n->value * 100, '%');
	}

	public function color($n) {

		if( $n instanceof Less_Tree_Quoted ){
			$colorCandidate = $n->value;
			$returnColor = Less_Tree_Color::fromKeyword($colorCandidate);
			if( $returnColor ){
				return $returnColor;
			}
			if( preg_match('/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})/',$colorCandidate) ){
				return new Less_Tree_Color(substr($colorCandidate, 1));
			}
			throw new Less_Exception_Compiler("argument must be a color keyword or 3/6 digit hex e.g. #FFF");
		} else {
			throw new Less_Exception_Compiler("argument must be a string");
		}
	}


	public function iscolor($n) {
		return $this->_isa($n, 'Less_Tree_Color');
	}

	public function isnumber($n) {
		return $this->_isa($n, 'Less_Tree_Dimension');
	}

	public function isstring($n) {
		return $this->_isa($n, 'Less_Tree_Quoted');
	}

	public function iskeyword($n) {
		return $this->_isa($n, 'Less_Tree_Keyword');
	}

	public function isurl($n) {
		return $this->_isa($n, 'Less_Tree_Url');
	}

	public function ispixel($n) {
		return $this->isunit($n, 'px');
	}

	public function ispercentage($n) {
		return $this->isunit($n, '%');
	}

	public function isem($n) {
		return $this->isunit($n, 'em');
	}

	/**
	 * @param string $unit
	 */
	public function isunit( $n, $unit ){
		return ($n instanceof Less_Tree_Dimension) && $n->unit->is( ( property_exists($unit,'value') ? $unit->value : $unit) ) ? new Less_Tree_Keyword('true') : new Less_Tree_Keyword('false');
	}

	/**
	 * @param string $type
	 */
	private function _isa($n, $type) {
		return is_a($n, $type) ? new Less_Tree_Keyword('true') : new Less_Tree_Keyword('false');
	}

	public function tint($color, $amount) {
		return $this->mix( $this->rgb(255,255,255), $color, $amount);
	}

	public function shade($color, $amount) {
		return $this->mix($this->rgb(0, 0, 0), $color, $amount);
	}

	public function extract($values, $index ){
		$index = (int)$index->value - 1; // (1-based index)
		// handle non-array values as an array of length 1
		// return 'undefined' if index is invalid
		if( property_exists($values,'value') && is_array($values->value) ){
			if( isset($values->value[$index]) ){
				return $values->value[$index];
			}
			return null;

		}elseif( (int)$index === 0 ){
			return $values;
		}

		return null;
	}

	function length($values){
		$n = (property_exists($values,'value') && is_array($values->value)) ? count($values->value) : 1;
		return new Less_Tree_Dimension($n);
	}

	function datauri($mimetypeNode, $filePathNode = null ) {

		$filePath = ( $filePathNode ? $filePathNode->value : null );
		$mimetype = $mimetypeNode->value;

		$args = 2;
		if( !$filePath ){
			$filePath = $mimetype;
			$args = 1;
		}

		$filePath = str_replace('\\','/',$filePath);
		if( Less_Environment::isPathRelative($filePath) ){

			if( Less_Parser::$options['relativeUrls'] ){
				$temp = $this->currentFileInfo['currentDirectory'];
			} else {
				$temp = $this->currentFileInfo['entryPath'];
			}

			if( !empty($temp) ){
				$filePath = Less_Environment::normalizePath(rtrim($temp,'/').'/'.$filePath);
			}

		}


		// detect the mimetype if not given
		if( $args < 2 ){

			/* incomplete
			$mime = require('mime');
			mimetype = mime.lookup(path);

			// use base 64 unless it's an ASCII or UTF-8 format
			var charset = mime.charsets.lookup(mimetype);
			useBase64 = ['US-ASCII', 'UTF-8'].indexOf(charset) < 0;
			if (useBase64) mimetype += ';base64';
			*/

			$mimetype = Less_Mime::lookup($filePath);

			$charset = Less_Mime::charsets_lookup($mimetype);
			$useBase64 = !in_array($charset,array('US-ASCII', 'UTF-8'));
			if( $useBase64 ){ $mimetype .= ';base64'; }

		}else{
			$useBase64 = preg_match('/;base64$/',$mimetype);
		}


		if( file_exists($filePath) ){
			$buf = @file_get_contents($filePath);
		}else{
			$buf = false;
		}


		// IE8 cannot handle a data-uri larger than 32KB. If this is exceeded
		// and the --ieCompat flag is enabled, return a normal url() instead.
		$DATA_URI_MAX_KB = 32;
		$fileSizeInKB = round( strlen($buf) / 1024 );
		if( $fileSizeInKB >= $DATA_URI_MAX_KB ){
			$url = new Less_Tree_Url( ($filePathNode ? $filePathNode : $mimetypeNode), $this->currentFileInfo);
			return $url->compile($this);
		}

		if( $buf ){
			$buf = $useBase64 ? base64_encode($buf) : rawurlencode($buf);
			$filePath = '"data:' . $mimetype . ',' . $buf . '"';
		}

		return new Less_Tree_Url( new Less_Tree_Anonymous($filePath) );
	}

	//svg-gradient
	function svggradient( $direction ){

		$throw_message = 'svg-gradient expects direction, start_color [start_position], [color position,]..., end_color [end_position]';
		$arguments = func_get_args();

		if( count($arguments) < 3 ){
			throw new Less_Exception_Compiler( $throw_message );
		}

		$stops = array_slice($arguments,1);
		$gradientType = 'linear';
		$rectangleDimension = 'x="0" y="0" width="1" height="1"';
		$useBase64 = true;
		$directionValue = $direction->toCSS();


		switch( $directionValue ){
			case "to bottom":
				$gradientDirectionSvg = 'x1="0%" y1="0%" x2="0%" y2="100%"';
				break;
			case "to right":
				$gradientDirectionSvg = 'x1="0%" y1="0%" x2="100%" y2="0%"';
				break;
			case "to bottom right":
				$gradientDirectionSvg = 'x1="0%" y1="0%" x2="100%" y2="100%"';
				break;
			case "to top right":
				$gradientDirectionSvg = 'x1="0%" y1="100%" x2="100%" y2="0%"';
				break;
			case "ellipse":
			case "ellipse at center":
				$gradientType = "radial";
				$gradientDirectionSvg = 'cx="50%" cy="50%" r="75%"';
				$rectangleDimension = 'x="-50" y="-50" width="101" height="101"';
				break;
			default:
				throw new Less_Exception_Compiler( "svg-gradient direction must be 'to bottom', 'to right', 'to bottom right', 'to top right' or 'ellipse at center'" );
		}

		$returner = '<?xml version="1.0" ?>' .
			'<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="100%" height="100%" viewBox="0 0 1 1" preserveAspectRatio="none">' .
			'<' . $gradientType . 'Gradient id="gradient" gradientUnits="userSpaceOnUse" ' . $gradientDirectionSvg . '>';

		for( $i = 0; $i < count($stops); $i++ ){
			if( is_object($stops[$i]) && property_exists($stops[$i],'value') ){
				$color = $stops[$i]->value[0];
				$position = $stops[$i]->value[1];
			}else{
				$color = $stops[$i];
				$position = null;
			}

			if( !($color instanceof Less_Tree_Color) || (!(($i === 0 || $i+1 === count($stops)) && $position === null) && !($position instanceof Less_Tree_Dimension)) ){
				throw new Less_Exception_Compiler( $throw_message );
			}
			if( $position ){
				$positionValue = $position->toCSS();
			}elseif( $i === 0 ){
				$positionValue = '0%';
			}else{
				$positionValue = '100%';
			}
			$alpha = $color->alpha;
			$returner .= '<stop offset="' . $positionValue . '" stop-color="' . $color->toRGB() . '"' . ($alpha < 1 ? ' stop-opacity="' . $alpha . '"' : '') . '/>';
		}

		$returner .= '</' . $gradientType . 'Gradient><rect ' . $rectangleDimension . ' fill="url(#gradient)" /></svg>';


		if( $useBase64 ){
			$returner = "'data:image/svg+xml;base64,".base64_encode($returner)."'";
		}else{
			$returner = "'data:image/svg+xml,".$returner."'";
		}

		return new Less_Tree_URL( new Less_Tree_Anonymous( $returner ) );
	}


	/**
	 * @param string $type
	 */
	private static function Expected( $type, $arg ){

		$debug = debug_backtrace();
		array_shift($debug);
		$last = array_shift($debug);
		$last = array_intersect_key($last,array('function'=>'','class'=>'','line'=>''));

		$message = 'Object of type '.get_class($arg).' passed to darken function. Expecting `'.$type.'`. '.$arg->toCSS().'. '.print_r($last,true);
		throw new Less_Exception_Compiler($message);

	}

	/**
	 * Php version of javascript's `encodeURIComponent` function
	 *
	 * @param string $string The string to encode
	 * @return string The encoded string
	 */
	public static function encodeURIComponent($string){
		$revert = array('%21' => '!', '%2A' => '*', '%27' => "'", '%28' => '(', '%29' => ')');
		return strtr(rawurlencode($string), $revert);
	}


	// Color Blending
	// ref: http://www.w3.org/TR/compositing-1

	public function colorBlend( $mode, $color1, $color2 ){
		$ab = $color1->alpha;	// backdrop
		$as = $color2->alpha;	// source
		$r = array();			// result

		$ar = $as + $ab * (1 - $as);
		for( $i = 0; $i < 3; $i++ ){
			$cb = $color1->rgb[$i] / 255;
			$cs = $color2->rgb[$i] / 255;
			$cr = call_user_func( $mode, $cb, $cs );
			if( $ar ){
				$cr = ($as * $cs + $ab * ($cb - $as * ($cb + $cs - $cr))) / $ar;
			}
			$r[$i] = $cr * 255;
		}

		return new Less_Tree_Color($r, $ar);
	}

	public function multiply($color1, $color2 ){
		return $this->colorBlend( array($this,'colorBlendMultiply'),  $color1, $color2 );
	}

	private function colorBlendMultiply($cb, $cs){
		return $cb * $cs;
	}

	public function screen($color1, $color2 ){
		return $this->colorBlend( array($this,'colorBlendScreen'),  $color1, $color2 );
	}

	private function colorBlendScreen( $cb, $cs){
		return $cb + $cs - $cb * $cs;
	}

	public function overlay($color1, $color2){
		return $this->colorBlend( array($this,'colorBlendOverlay'),  $color1, $color2 );
	}

	private function colorBlendOverlay($cb, $cs ){
		$cb *= 2;
		return ($cb <= 1)
			? $this->colorBlendMultiply($cb, $cs)
			: $this->colorBlendScreen($cb - 1, $cs);
	}

	public function softlight($color1, $color2){
		return $this->colorBlend( array($this,'colorBlendSoftlight'),  $color1, $color2 );
	}

	private function colorBlendSoftlight($cb, $cs ){
		$d = 1;
		$e = $cb;
		if( $cs > 0.5 ){
			$e = 1;
			$d = ($cb > 0.25) ? sqrt($cb)
				: ((16 * $cb - 12) * $cb + 4) * $cb;
		}
		return $cb - (1 - 2 * $cs) * $e * ($d - $cb);
	}

	public function hardlight($color1, $color2){
		return $this->colorBlend( array($this,'colorBlendHardlight'),  $color1, $color2 );
	}

	private function colorBlendHardlight( $cb, $cs ){
		return $this->colorBlendOverlay($cs, $cb);
	}

	public function difference($color1, $color2) {
		return $this->colorBlend( array($this,'colorBlendDifference'),  $color1, $color2 );
	}

	private function colorBlendDifference( $cb, $cs ){
		return abs($cb - $cs);
	}

	public function exclusion( $color1, $color2 ){
		return $this->colorBlend( array($this,'colorBlendExclusion'),  $color1, $color2 );
	}

	private function colorBlendExclusion( $cb, $cs ){
		return $cb + $cs - 2 * $cb * $cs;
	}

	public function average($color1, $color2){
		return $this->colorBlend( array($this,'colorBlendAverage'),  $color1, $color2 );
	}

	// non-w3c functions:
	function colorBlendAverage($cb, $cs ){
		return ($cb + $cs) / 2;
	}

	public function negation($color1, $color2 ){
		return $this->colorBlend( array($this,'colorBlendNegation'),  $color1, $color2 );
	}

	function colorBlendNegation($cb, $cs){
		return 1 - abs($cb + $cs - 1);
	}

	// ~ End of Color Blending

}
 

/**
 * Mime lookup
 *
 * @package Less
 * @subpackage node
 */
class Less_Mime{

	// this map is intentionally incomplete
	// if you want more, install 'mime' dep
	static $_types = array(
	        '.htm' => 'text/html',
	        '.html'=> 'text/html',
	        '.gif' => 'image/gif',
	        '.jpg' => 'image/jpeg',
	        '.jpeg'=> 'image/jpeg',
	        '.png' => 'image/png'
	        );

	static function lookup( $filepath ){
		$parts = explode('.',$filepath);
		$ext = '.'.strtolower(array_pop($parts));

		if( !isset(self::$_types[$ext]) ){
			return null;
		}
		return self::$_types[$ext];
	}

	static function charsets_lookup( $type = null ){
		// assumes all text types are UTF-8
		return $type && preg_match('/^text\//',$type) ? 'UTF-8' : '';
	}
} 

/**
 * Tree
 *
 * @package Less
 * @subpackage tree
 */
class Less_Tree{

	public $cache_string;

	public function toCSS(){
		$output = new Less_Output();
		$this->genCSS($output);
		return $output->toString();
	}


    /**
     * Generate CSS by adding it to the output object
     *
     * @param Less_Output $output The output
     * @return void
     */
    public function genCSS($output){}


	/**
	 * @param Less_Tree_Ruleset[] $rules
	 */
	public static function outputRuleset( $output, $rules ){

		$ruleCnt = count($rules);
		Less_Environment::$tabLevel++;


		// Compressed
		if( Less_Parser::$options['compress'] ){
			$output->add('{');
			for( $i = 0; $i < $ruleCnt; $i++ ){
				$rules[$i]->genCSS( $output );
			}

			$output->add( '}' );
			Less_Environment::$tabLevel--;
			return;
		}


		// Non-compressed
		$tabSetStr = "\n".str_repeat( '  ' , Less_Environment::$tabLevel-1 );
		$tabRuleStr = $tabSetStr.'  ';

		$output->add( " {" );
		for($i = 0; $i < $ruleCnt; $i++ ){
			$output->add( $tabRuleStr );
			$rules[$i]->genCSS( $output );
		}
		Less_Environment::$tabLevel--;
		$output->add( $tabSetStr.'}' );

	}

	public function accept($visitor){}


	public static function ReferencedArray($rules){
		foreach($rules as $rule){
			if( method_exists($rule, 'markReferenced') ){
				$rule->markReferenced();
			}
		}
	}


	/**
	 * Requires php 5.3+
	 */
	public static function __set_state($args){

		$class = get_called_class();
		$obj = new $class(null,null,null,null);
		foreach($args as $key => $val){
			$obj->$key = $val;
		}
		return $obj;
	}

} 

/**
 * Parser output
 *
 * @package Less
 * @subpackage output
 */
class Less_Output{

	/**
	 * Output holder
	 *
	 * @var string
	 */
	protected $strs = array();

	/**
	 * Adds a chunk to the stack
	 *
	 * @param string $chunk The chunk to output
	 * @param Less_FileInfo $fileInfo The file information
	 * @param integer $index The index
	 * @param mixed $mapLines
	 */
	public function add($chunk, $fileInfo = null, $index = 0, $mapLines = null){
		$this->strs[] = $chunk;
	}

	/**
	 * Is the output empty?
	 *
	 * @return boolean
	 */
	public function isEmpty(){
		return count($this->strs) === 0;
	}


	/**
	 * Converts the output to string
	 *
	 * @return string
	 */
	public function toString(){
		return implode('',$this->strs);
	}

} 

/**
 * Visitor
 *
 * @package Less
 * @subpackage visitor
 */
class Less_Visitor{

	var $methods = array();
	var $_visitFnCache = array();

	function __construct(){
		$this->_visitFnCache = get_class_methods(get_class($this));
		$this->_visitFnCache = array_flip($this->_visitFnCache);
	}

	function visitObj( $node ){

		$funcName = 'visit'.$node->type;
		if( isset($this->_visitFnCache[$funcName]) ){

			$visitDeeper = true;
			$this->$funcName( $node, $visitDeeper );

			if( $visitDeeper ){
				$node->accept($this);
			}

			$funcName = $funcName . "Out";
			if( isset($this->_visitFnCache[$funcName]) ){
				$this->$funcName( $node );
			}

		}else{
			$node->accept($this);
		}

		return $node;
	}

	function visitArray( $nodes ){

		array_map( array($this,'visitObj'), $nodes);
		return $nodes;
	}
}

 

/**
 * Replacing Visitor
 *
 * @package Less
 * @subpackage visitor
 */
class Less_VisitorReplacing extends Less_Visitor{

	function visitObj( $node ){

		$funcName = 'visit'.$node->type;
		if( isset($this->_visitFnCache[$funcName]) ){

			$visitDeeper = true;
			$node = $this->$funcName( $node, $visitDeeper );

			if( $node ){
				if( $visitDeeper && is_object($node) ){
					$node->accept($this);
				}

				$funcName = $funcName . "Out";
				if( isset($this->_visitFnCache[$funcName]) ){
					$this->$funcName( $node );
				}
			}

		}else{
			$node->accept($this);
		}

		return $node;
	}

	function visitArray( $nodes ){

		$newNodes = array();
		foreach($nodes as $node){
			$evald = $this->visitObj($node);
			if( $evald ){
				if( is_array($evald) ){
					self::flatten($evald,$newNodes);
				}else{
					$newNodes[] = $evald;
				}
			}
		}
		return $newNodes;
	}

	function flatten( $arr, &$out ){

		foreach($arr as $item){
			if( !is_array($item) ){
				$out[] = $item;
				continue;
			}

			foreach($item as $nestedItem){
				if( is_array($nestedItem) ){
					self::flatten( $nestedItem, $out);
				}else{
					$out[] = $nestedItem;
				}
			}
		}

		return $out;
	}

}


 

/**
 * Configurable
 *
 * @package Less
 * @subpackage Core
 */
abstract class Less_Configurable {

	/**
	 * Array of options
	 *
	 * @var array
	 */
	protected $options = array();

	/**
	 * Array of default options
	 *
	 * @var array
	 */
	protected $defaultOptions = array();


	/**
	 * Set options
	 *
	 * If $options is an object it will be converted into an array by called
	 * it's toArray method.
	 *
	 * @throws Exception
	 * @param array|object $options
	 *
	 */
	public function setOptions($options){
		$options = array_intersect_key($options,$this->defaultOptions);
		$this->options = array_merge($this->defaultOptions, $this->options, $options);
	}


	/**
	 * Get an option value by name
	 *
	 * If the option is empty or not set a NULL value will be returned.
	 *
	 * @param string $name
	 * @param mixed $default Default value if confiuration of $name is not present
	 * @return mixed
	 */
	public function getOption($name, $default = null){
		if(isset($this->options[$name])){
			return $this->options[$name];
		}
		return $default;
	}


	/**
	 * Set an option
	 *
	 * @param string $name
	 * @param mixed $value
	 */
	public function setOption($name, $value){
		$this->options[$name] = $value;
	}

} 

/**
 * Alpha
 *
 * @package Less
 * @subpackage tree
 */
class Less_Tree_Alpha extends Less_Tree{
	public $value;
	public $type = 'Alpha';

	public function __construct($val){
		$this->value = $val;
	}

	//function accept( $visitor ){
	//	$this->value = $visitor->visit( $this->value );
	//}

	public function compile($env){

		if( is_object($this->value) ){
			$this->value = $this->value->compile($env);
		}

		return $this;
	}

    /**
     * @see Less_Tree::genCSS
     */
	public function genCSS( $output ){

		$output->add( "alpha(opacity=" );

		if( is_string($this->value) ){
			$output->add( $this->value );
		}else{
			$this->value->genCSS( $output);
		}

		$output->add( ')' );
	}

	public function toCSS(){
		return "alpha(opacity=" . (is_string($this->value) ? $this->value : $this->value->toCSS()) . ")";
	}


} 

/**
 * Anonymous
 *
 * @package Less
 * @subpackage tree
 */
class Less_Tree_Anonymous extends Less_Tree{
	public $value;
	public $quote;
	public $index;
	public $mapLines;
	public $currentFileInfo;
	public $type = 'Anonymous';

	/**
	 * @param integer $index
	 * @param boolean $mapLines
	 */
	public function __construct($value, $index = null, $currentFileInfo = null, $mapLines = null ){
		$this->value = $value;
		$this->index = $index;
		$this->mapLines = $mapLines;
		$this->currentFileInfo = $currentFileInfo;
	}

	public function compile(){
		return new Less_Tree_Anonymous($this->value, $this->index, $this->currentFileInfo, $this->mapLines);
	}

	function compare($x){
		if( !is_object($x) ){
			return -1;
		}

		$left = $this->toCSS();
		$right = $x->toCSS();

		if( $left === $right ){
			return 0;
		}

		return $left < $right ? -1 : 1;
	}

    /**
     * @see Less_Tree::genCSS
     */
	public function genCSS( $output ){
		$output->add( $this->value, $this->currentFileInfo, $this->index, $this->mapLines );
	}

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

}
 

/**
 * Assignment
 *
 * @package Less
 * @subpackage tree
 */
class Less_Tree_Assignment extends Less_Tree{

	public $key;
	public $value;
	public $type = 'Assignment';

	function __construct($key, $val) {
		$this->key = $key;
		$this->value = $val;
	}

	function accept( $visitor ){
		$this->value = $visitor->visitObj( $this->value );
	}

	public function compile($env) {
		return new Less_Tree_Assignment( $this->key, $this->value->compile($env));
	}

    /**
     * @see Less_Tree::genCSS
     */
	public function genCSS( $output ){
		$output->add( $this->key . '=' );
		$this->value->genCSS( $output );
	}

	public function toCss(){
		return $this->key . '=' . $this->value->toCSS();
	}
}
 

/**
 * Attribute
 *
 * @package Less
 * @subpackage tree
 */
class Less_Tree_Attribute extends Less_Tree{

	public $key;
	public $op;
	public $value;
	public $type = 'Attribute';

	function __construct($key, $op, $value){
		$this->key = $key;
		$this->op = $op;
		$this->value = $value;
	}

	function compile($env){

		$key_obj = is_object($this->key);
		$val_obj = is_object($this->value);

		if( !$key_obj && !$val_obj ){
			return $this;
		}

		return new Less_Tree_Attribute(
			$key_obj ? $this->key->compile($env) : $this->key ,
			$this->op,
			$val_obj ? $this->value->compile($env) : $this->value);
	}

    /**
     * @see Less_Tree::genCSS
     */
	function genCSS( $output ){
		$output->add( $this->toCSS() );
	}

	function toCSS(){
		$value = $this->key;

		if( $this->op ){
			$value .= $this->op;
			$value .= (is_object($this->value) ? $this->value->toCSS() : $this->value);
		}

		return '[' . $value . ']';
	}
} 


/**
 * Call
 *
 * @package Less
 * @subpackage tree
 */
class Less_Tree_Call extends Less_Tree{
    public $value;

    var $name;
    var $args;
    var $index;
    var $currentFileInfo;
    public $type = 'Call';
	public $parensInOp;

	public function __construct($name, $args, $index, $currentFileInfo = null ){
		$this->name = $name;
		$this->args = $args;
		$this->index = $index;
		$this->currentFileInfo = $currentFileInfo;
	}

	function accept( $visitor ){
		$this->args = $visitor->visitArray( $this->args );
	}

    //
    // When evaluating a function call,
    // we either find the function in `tree.functions` [1],
    // in which case we call it, passing the  evaluated arguments,
    // or we simply print it out as it appeared originally [2].
    //
    // The *functions.js* file contains the built-in functions.
    //
    // The reason why we evaluate the arguments, is in the case where
    // we try to pass a variable to a function, like: `saturate(@color)`.
    // The function should receive the value, not the variable.
    //
    public function compile($env=null){
		$args = array();
		foreach($this->args as $a){
			$args[] = $a->compile($env);
		}

		$nameLC = strtolower($this->name);
		switch($nameLC){
			case '%':
			$nameLC = '_percent';
			break;

			case 'get-unit':
			$nameLC = 'getunit';
			break;

			case 'data-uri':
			$nameLC = 'datauri';
			break;

			case 'svg-gradient':
			$nameLC = 'svggradient';
			break;
		}

		$result = null;
		if( $nameLC === 'default' ){
			$result = Less_Tree_DefaultFunc::compile();

		}else{

			if( method_exists('Less_Functions',$nameLC) ){ // 1.
				try {

					$func = new Less_Functions($env, $this->currentFileInfo);
					$result = call_user_func_array( array($func,$nameLC),$args);

				} catch (Exception $e) {
					throw new Less_Exception_Compiler('error evaluating function `' . $this->name . '` '.$e->getMessage().' index: '. $this->index);
				}
			}
		}

		if( $result !== null ){
			return $result;
		}


		return new Less_Tree_Call( $this->name, $args, $this->index, $this->currentFileInfo );
    }

    /**
     * @see Less_Tree::genCSS
     */
	public function genCSS( $output ){

		$output->add( $this->name . '(', $this->currentFileInfo, $this->index );
		$args_len = count($this->args);
		for($i = 0; $i < $args_len; $i++ ){
			$this->args[$i]->genCSS( $output );
			if( $i + 1 < $args_len ){
				$output->add( ', ' );
			}
		}

		$output->add( ')' );
	}


    //public function toCSS(){
    //    return $this->compile()->toCSS();
    //}

}
 

/**
 * Color
 *
 * @package Less
 * @subpackage tree
 */
class Less_Tree_Color extends Less_Tree{
	public $rgb;
	public $alpha;
	public $isTransparentKeyword;
	public $type = 'Color';

	public function __construct($rgb, $a = 1, $isTransparentKeyword = null ){

		if( $isTransparentKeyword ){
			$this->rgb = $rgb;
			$this->alpha = $a;
			$this->isTransparentKeyword = true;
			return;
		}

		$this->rgb = array();
		if( is_array($rgb) ){
			$this->rgb = $rgb;
		}else if( strlen($rgb) == 6 ){
			foreach(str_split($rgb, 2) as $c){
				$this->rgb[] = hexdec($c);
			}
		}else{
			foreach(str_split($rgb, 1) as $c){
				$this->rgb[] = hexdec($c.$c);
			}
		}
		$this->alpha = is_numeric($a) ? $a : 1;
	}

	public function compile(){
		return $this;
	}

	public function luma(){
		$r = $this->rgb[0] / 255;
		$g = $this->rgb[1] / 255;
		$b = $this->rgb[2] / 255;

		$r = ($r <= 0.03928) ? $r / 12.92 : pow((($r + 0.055) / 1.055), 2.4);
		$g = ($g <= 0.03928) ? $g / 12.92 : pow((($g + 0.055) / 1.055), 2.4);
		$b = ($b <= 0.03928) ? $b / 12.92 : pow((($b + 0.055) / 1.055), 2.4);

		return 0.2126 * $r + 0.7152 * $g + 0.0722 * $b;
	}

	/**
	 * @see Less_Tree::genCSS
	 */
	public function genCSS( $output ){
		$output->add( $this->toCSS() );
	}

	public function toCSS( $doNotCompress = false ){
		$compress = Less_Parser::$options['compress'] && !$doNotCompress;
		$alpha = Less_Functions::fround( $this->alpha );


		//
		// If we have some transparency, the only way to represent it
		// is via `rgba`. Otherwise, we use the hex representation,
		// which has better compatibility with older browsers.
		// Values are capped between `0` and `255`, rounded and zero-padded.
		//
		if( $alpha < 1 ){
			if( $alpha === 0 && isset($this->isTransparentKeyword) && $this->isTransparentKeyword ){
				return 'transparent';
			}

			$values = array();
			foreach($this->rgb as $c){
				$values[] = Less_Functions::clamp( round($c), 255);
			}
			$values[] = $alpha;

			$glue = ($compress ? ',' : ', ');
			return "rgba(" . implode($glue, $values) . ")";
		}else{

			$color = $this->toRGB();

			if( $compress ){

				// Convert color to short format
				if( $color[1] === $color[2] && $color[3] === $color[4] && $color[5] === $color[6]) {
					$color = '#'.$color[1] . $color[3] . $color[5];
				}
			}

			return $color;
		}
	}

	//
	// Operations have to be done per-channel, if not,
	// channels will spill onto each other. Once we have
	// our result, in the form of an integer triplet,
	// we create a new Color node to hold the result.
	//

	/**
	 * @param string $op
	 */
	public function operate( $op, $other) {
		$rgb = array();
		$alpha = $this->alpha * (1 - $other->alpha) + $other->alpha;
		for ($c = 0; $c < 3; $c++) {
			$rgb[$c] = Less_Functions::operate( $op, $this->rgb[$c], $other->rgb[$c]);
		}
		return new Less_Tree_Color($rgb, $alpha);
	}

	public function toRGB(){
		return $this->toHex($this->rgb);
	}

	public function toHSL(){
		$r = $this->rgb[0] / 255;
		$g = $this->rgb[1] / 255;
		$b = $this->rgb[2] / 255;
		$a = $this->alpha;

		$max = max($r, $g, $b);
		$min = min($r, $g, $b);
		$l = ($max + $min) / 2;
		$d = $max - $min;

		$h = $s = 0;
		if( $max !== $min ){
			$s = $l > 0.5 ? $d / (2 - $max - $min) : $d / ($max + $min);

			switch ($max) {
				case $r: $h = ($g - $b) / $d + ($g < $b ? 6 : 0); break;
				case $g: $h = ($b - $r) / $d + 2;				 break;
				case $b: $h = ($r - $g) / $d + 4;				 break;
			}
			$h /= 6;
		}
		return array('h' => $h * 360, 's' => $s, 'l' => $l, 'a' => $a );
	}

	//Adapted from http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript
	function toHSV() {
		$r = $this->rgb[0] / 255;
		$g = $this->rgb[1] / 255;
		$b = $this->rgb[2] / 255;
		$a = $this->alpha;

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

		$v = $max;

		$d = $max - $min;
		if ($max === 0) {
			$s = 0;
		} else {
			$s = $d / $max;
		}

		$h = 0;
		if( $max !== $min ){
			switch($max){
				case $r: $h = ($g - $b) / $d + ($g < $b ? 6 : 0); break;
				case $g: $h = ($b - $r) / $d + 2; break;
				case $b: $h = ($r - $g) / $d + 4; break;
			}
			$h /= 6;
		}
		return array('h'=> $h * 360, 's'=> $s, 'v'=> $v, 'a' => $a );
	}

	public function toARGB(){
		$argb = array_merge( (array) Less_Parser::round($this->alpha * 255), $this->rgb);
		return $this->toHex( $argb );
	}

	public function compare($x){

		if( !property_exists( $x, 'rgb' ) ){
			return -1;
		}


		return ($x->rgb[0] === $this->rgb[0] &&
			$x->rgb[1] === $this->rgb[1] &&
			$x->rgb[2] === $this->rgb[2] &&
			$x->alpha === $this->alpha) ? 0 : -1;
	}

	function toHex( $v ){

		$ret = '#';
		foreach($v as $c){
			$c = Less_Functions::clamp( Less_Parser::round($c), 255);
			if( $c < 16 ){
				$ret .= '0';
			}
			$ret .= dechex($c);
		}

		return $ret;
	}


	/**
	 * @param string $keyword
	 */
	public static function fromKeyword( $keyword ){
		$keyword = strtolower($keyword);

		if( Less_Colors::hasOwnProperty($keyword) ){
			// detect named color
			return new Less_Tree_Color(substr(Less_Colors::color($keyword), 1));
		}

		if( $keyword === 'transparent' ){
			return new Less_Tree_Color( array(0, 0, 0), 0, true);
		}
	}

}
 

/**
 * Comment
 *
 * @package Less
 * @subpackage tree
 */
class Less_Tree_Comment extends Less_Tree{

	public $value;
	public $silent;
	public $isReferenced;
	public $currentFileInfo;
	public $type = 'Comment';

	public function __construct($value, $silent, $index = null, $currentFileInfo = null ){
		$this->value = $value;
		$this->silent = !! $silent;
		$this->currentFileInfo = $currentFileInfo;
	}

    /**
     * @see Less_Tree::genCSS
     */
	public function genCSS( $output ){
		//if( $this->debugInfo ){
			//$output->add( tree.debugInfo($env, $this), $this->currentFileInfo, $this->index);
		//}
		$output->add( trim($this->value) );//TODO shouldn't need to trim, we shouldn't grab the \n
	}

	public function toCSS(){
		return Less_Parser::$options['compress'] ? '' : $this->value;
	}

	public function isSilent(){
		$isReference = ($this->currentFileInfo && isset($this->currentFileInfo['reference']) && (!isset($this->isReferenced) || !$this->isReferenced) );
		$isCompressed = Less_Parser::$options['compress'] && !preg_match('/^\/\*!/', $this->value);
		return $this->silent || $isReference || $isCompressed;
	}

	public function compile(){
		return $this;
	}

	public function markReferenced(){
		$this->isReferenced = true;
	}

}
 

/**
 * Condition
 *
 * @package Less
 * @subpackage tree
 */
class Less_Tree_Condition extends Less_Tree{

	public $op;
	public $lvalue;
	public $rvalue;
	public $index;
	public $negate;
	public $type = 'Condition';

	public function __construct($op, $l, $r, $i = 0, $negate = false) {
		$this->op = trim($op);
		$this->lvalue = $l;
		$this->rvalue = $r;
		$this->index = $i;
		$this->negate = $negate;
	}

	public function accept($visitor){
		$this->lvalue = $visitor->visitObj( $this->lvalue );
		$this->rvalue = $visitor->visitObj( $this->rvalue );
	}

    public function compile($env) {
		$a = $this->lvalue->compile($env);
		$b = $this->rvalue->compile($env);

		switch( $this->op ){
			case 'and':
				$result = $a && $b;
			break;

			case 'or':
				$result = $a || $b;
			break;

			default:
				if( Less_Parser::is_method($a, 'compare') ){
					$result = $a->compare($b);
				}elseif( Less_Parser::is_method($b, 'compare') ){
					$result = $b->compare($a);
				}else{
					throw new Less_Exception_Compiler('Unable to perform comparison', null, $this->index);
				}

				switch ($result) {
					case -1:
					$result = $this->op === '<' || $this->op === '=<' || $this->op === '<=';
					break;

					case  0:
					$result = $this->op === '=' || $this->op === '>=' || $this->op === '=<' || $this->op === '<=';
					break;

					case  1:
					$result = $this->op === '>' || $this->op === '>=';
					break;
				}
			break;
		}

		return $this->negate ? !$result : $result;
    }

}
 

/**
 * DefaultFunc
 *
 * @package Less
 * @subpackage tree
 */
class Less_Tree_DefaultFunc{

	static $error_;
	static $value_;

	static function compile(){
		if( self::$error_ ){
			throw Exception(self::$error_);
		}
		if( self::$value_ !== null ){
			return self::$value_ ? new Less_Tree_Keyword('true') : new Less_Tree_Keyword('false');
		}
	}

	static function value( $v ){
		self::$value_ = $v;
	}

	static function error( $e ){
		self::$error_ = $e;
	}

	static function reset(){
		self::$value_ = self::$error_ = null;
	}
} 

/**
 * DetachedRuleset
 *
 * @package Less
 * @subpackage tree
 */
class Less_Tree_DetachedRuleset extends Less_Tree{

	public $ruleset;
	public $frames;
	public $type = 'DetachedRuleset';

	function __construct( $ruleset, $frames = null ){
		$this->ruleset = $ruleset;
		$this->frames = $frames;
	}

	function accept($visitor) {
		$this->ruleset = $visitor->visitObj($this->ruleset);
	}

	function compile($env){
		if( $this->frames ){
			$frames = $this->frames;
		}else{
			$frames = $env->frames;
		}
		return new Less_Tree_DetachedRuleset($this->ruleset, $frames);
	}

	function callEval($env) {
		if( $this->frames ){
			return $this->ruleset->compile( $env->copyEvalEnv( array_merge($this->frames,$env->frames) ) );
		}
		return $this->ruleset->compile( $env );
	}
}

 

/**
 * Dimension
 *
 * @package Less
 * @subpackage tree
 */
class Less_Tree_Dimension extends Less_Tree{

	public $value;
	public $unit;
	public $type = 'Dimension';
	public $parensInOp;

    public function __construct($value, $unit = null){
        $this->value = floatval($value);

		if( $unit && ($unit instanceof Less_Tree_Unit) ){
			$this->unit = $unit;
		}elseif( $unit ){
			$this->unit = new Less_Tree_Unit( array($unit) );
		}else{
			$this->unit = new Less_Tree_Unit( );
		}
    }

	function accept( $visitor ){
		$this->unit = $visitor->visitObj( $this->unit );
	}

    public function compile(){
        return $this;
    }

    public function toColor() {
        return new Less_Tree_Color(array($this->value, $this->value, $this->value));
    }

    /**
     * @see Less_Tree::genCSS
     */
	public function genCSS( $output ){

		if( Less_Parser::$options['strictUnits'] && !$this->unit->isSingular() ){
			throw new Less_Exception_Compiler("Multiple units in dimension. Correct the units or use the unit function. Bad unit: ".$this->unit->toString());
		}

		$value = Less_Functions::fround( $this->value );
		$strValue = (string)$value;

		if( $value !== 0 && $value < 0.000001 && $value > -0.000001 ){
			// would be output 1e-6 etc.
			$strValue = number_format($strValue,10);
			$strValue = preg_replace('/\.?0+$/','', $strValue);
		}

		if( Less_Parser::$options['compress'] ){
			// Zero values doesn't need a unit
			if( $value === 0 && $this->unit->isLength() ){
				$output->add( $strValue );
				return $strValue;
			}

			// Float values doesn't need a leading zero
			if( $value > 0 && $value < 1 && $strValue[0] === '0' ){
				$strValue = substr($strValue,1);
			}
		}

		$output->add( $strValue );
		$this->unit->genCSS( $output );
	}

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

    // In an operation between two Dimensions,
    // we default to the first Dimension's unit,
    // so `1px + 2em` will yield `3px`.

    /**
     * @param string $op
     */
    public function operate( $op, $other){

		$value = Less_Functions::operate( $op, $this->value, $other->value);
		$unit = clone $this->unit;

		if( $op === '+' || $op === '-' ){

			if( !$unit->numerator && !$unit->denominator ){
				$unit->numerator = $other->unit->numerator;
				$unit->denominator = $other->unit->denominator;
			}elseif( !$other->unit->numerator && !$other->unit->denominator ){
				// do nothing
			}else{
				$other = $other->convertTo( $this->unit->usedUnits());

				if( Less_Parser::$options['strictUnits'] && $other->unit->toString() !== $unit->toCSS() ){
					throw new Less_Exception_Compiler("Incompatible units. Change the units or use the unit function. Bad units: '".$unit->toString() . "' and ".$other->unit->toString()+"'.");
				}

				$value = Less_Functions::operate( $op, $this->value, $other->value);
			}
		}elseif( $op === '*' ){
			$unit->numerator = array_merge($unit->numerator, $other->unit->numerator);
			$unit->denominator = array_merge($unit->denominator, $other->unit->denominator);
			sort($unit->numerator);
			sort($unit->denominator);
			$unit->cancel();
		}elseif( $op === '/' ){
			$unit->numerator = array_merge($unit->numerator, $other->unit->denominator);
			$unit->denominator = array_merge($unit->denominator, $other->unit->numerator);
			sort($unit->numerator);
			sort($unit->denominator);
			$unit->cancel();
		}
		return new Less_Tree_Dimension( $value, $unit);
    }

	public function compare($other) {
		if ($other instanceof Less_Tree_Dimension) {

			if( $this->unit->isEmpty() || $other->unit->isEmpty() ){
				$a = $this;
				$b = $other;
			} else {
				$a = $this->unify();
				$b = $other->unify();
				if( $a->unit->compare($b->unit) !== 0 ){
					return -1;
				}
			}
			$aValue = $a->value;
			$bValue = $b->value;

			if ($bValue > $aValue) {
				return -1;
			} elseif ($bValue < $aValue) {
				return 1;
			} else {
				return 0;
			}
		} else {
			return -1;
		}
	}

	function unify() {
		return $this->convertTo(array('length'=> 'px', 'duration'=> 's', 'angle' => 'rad' ));
	}

    function convertTo($conversions) {
		$value = $this->value;
		$unit = clone $this->unit;

		if( is_string($conversions) ){
			$derivedConversions = array();
			foreach( Less_Tree_UnitConversions::$groups as $i ){
				if( isset(Less_Tree_UnitConversions::${$i}[$conversions]) ){
					$derivedConversions = array( $i => $conversions);
				}
			}
			$conversions = $derivedConversions;
		}


		foreach($conversions as $groupName => $targetUnit){
			$group = Less_Tree_UnitConversions::${$groupName};

			//numerator
			foreach($unit->numerator as $i => $atomicUnit){
				$atomicUnit = $unit->numerator[$i];
				if( !isset($group[$atomicUnit]) ){
					continue;
				}

				$value = $value * ($group[$atomicUnit] / $group[$targetUnit]);

				$unit->numerator[$i] = $targetUnit;
			}

			//denominator
			foreach($unit->denominator as $i => $atomicUnit){
				$atomicUnit = $unit->denominator[$i];
				if( !isset($group[$atomicUnit]) ){
					continue;
				}

				$value = $value / ($group[$atomicUnit] / $group[$targetUnit]);

				$unit->denominator[$i] = $targetUnit;
			}
		}

		$unit->cancel();

		return new Less_Tree_Dimension( $value, $unit);
    }
}
 

/**
 * Directive
 *
 * @package Less
 * @subpackage tree
 */
class Less_Tree_Directive extends Less_Tree{

	public $name;
	public $value;
	public $rules;
	public $index;
	public $isReferenced;
	public $currentFileInfo;
	public $debugInfo;
	public $type = 'Directive';
	public $allExtends;

	public function __construct($name, $value, $rules, $index = null, $currentFileInfo = null, $debugInfo = null ){
		$this->name = $name;
		$this->value = $value;
		if( $rules ){
			$this->rules = $rules;
			$this->rules->allowImports = true;
		}

		$this->index = $index;
		$this->currentFileInfo = $currentFileInfo;
		$this->debugInfo = $debugInfo;
	}


	function accept( $visitor ){
		if( $this->rules ){
			$this->rules = $visitor->visitObj( $this->rules );
		}
		if( $this->value ){
			$this->value = $visitor->visitObj( $this->value );
		}
	}


    /**
     * @see Less_Tree::genCSS
     */
	function genCSS( $output ){
		$value = $this->value;
		$rules = $this->rules;
		$output->add( $this->name, $this->currentFileInfo, $this->index );
		if( $this->value ){
			$output->add(' ');
			$this->value->genCSS($output);
		}
		if( $this->rules ){
			Less_Tree::outputRuleset( $output, array($this->rules));
		} else {
			$output->add(';');
		}
	}

	public function compile($env){

		$value = $this->value;
		$rules = $this->rules;
		if( $value ){
			$value = $value->compile($env);
		}

		if( $rules ){
			$rules = $rules->compile($env);
			$rules->root = true;
		}

		return new Less_Tree_Directive( $this->name, $value, $rules, $this->index, $this->currentFileInfo, $this->debugInfo );
	}


	public function variable($name){
		if( $this->rules ){
			return $this->rules->variable($name);
		}
	}

	public function find($selector){
		if( $this->rules ){
			return $this->rules->find($selector, $this);
		}
	}

	//rulesets: function () { if (this.rules) return tree.Ruleset.prototype.rulesets.apply(this.rules); },

	public function markReferenced(){
		$this->isReferenced = true;
		if( $this->rules ){
			Less_Tree::ReferencedArray($this->rules->rules);
		}
	}

}
 

/**
 * Element
 *
 * @package Less
 * @subpackage tree
 */
class Less_Tree_Element extends Less_Tree{

	public $combinator = '';
	public $value = '';
	public $index;
	public $currentFileInfo;
	public $type = 'Element';

	public $value_is_object = false;

	public function __construct($combinator, $value, $index = null, $currentFileInfo = null ){

		$this->value = $value;
		$this->value_is_object = is_object($value);

		if( $combinator ){
			$this->combinator = $combinator;
		}

		$this->index = $index;
		$this->currentFileInfo = $currentFileInfo;
	}

	function accept( $visitor ){
		if( $this->value_is_object ){ //object or string
			$this->value = $visitor->visitObj( $this->value );
		}
	}

	public function compile($env){

		if( Less_Environment::$mixin_stack ){
			return new Less_Tree_Element($this->combinator, ($this->value_is_object ? $this->value->compile($env) : $this->value), $this->index, $this->currentFileInfo );
		}

		if( $this->value_is_object ){
			$this->value = $this->value->compile($env);
		}

		return $this;
	}

    /**
     * @see Less_Tree::genCSS
     */
	public function genCSS( $output ){
		$output->add( $this->toCSS(), $this->currentFileInfo, $this->index );
	}

	public function toCSS(){

		if( $this->value_is_object ){
			$value = $this->value->toCSS();
		}else{
			$value = $this->value;
		}


		if( $value === '' && $this->combinator && $this->combinator === '&' ){
			return '';
		}


		return Less_Environment::$_outputMap[$this->combinator] . $value;
	}

}
 

/**
 * Expression
 *
 * @package Less
 * @subpackage tree
 */
class Less_Tree_Expression extends Less_Tree{

	public $value = array();
	public $parens = false;
	public $parensInOp = false;
	public $type = 'Expression';

	public function __construct( $value, $parens = null ){
		$this->value = $value;
		$this->parens = $parens;
	}

	function accept( $visitor ){
		$this->value = $visitor->visitArray( $this->value );
	}

	public function compile($env) {

		$doubleParen = false;

		if( $this->parens && !$this->parensInOp ){
			Less_Environment::$parensStack++;
		}

		$returnValue = null;
		if( $this->value ){

			$count = count($this->value);

			if( $count > 1 ){

				$ret = array();
				foreach($this->value as $e){
					$ret[] = $e->compile($env);
				}
				$returnValue = new Less_Tree_Expression($ret);

			}else{

				if( ($this->value[0] instanceof Less_Tree_Expression) && $this->value[0]->parens && !$this->value[0]->parensInOp ){
					$doubleParen = true;
				}

				$returnValue = $this->value[0]->compile($env);
			}

		} else {
			$returnValue = $this;
		}

		if( $this->parens ){
			if( !$this->parensInOp ){
				Less_Environment::$parensStack--;

			}elseif( !Less_Environment::isMathOn() && !$doubleParen ){
				$returnValue = new Less_Tree_Paren($returnValue);

			}
		}
		return $returnValue;
	}

    /**
     * @see Less_Tree::genCSS
     */
	function genCSS( $output ){
		$val_len = count($this->value);
		for( $i = 0; $i < $val_len; $i++ ){
			$this->value[$i]->genCSS( $output );
			if( $i + 1 < $val_len ){
				$output->add( ' ' );
			}
		}
	}

	function throwAwayComments() {

		if( is_array($this->value) ){
			$new_value = array();
			foreach($this->value as $v){
				if( $v instanceof Less_Tree_Comment ){
					continue;
				}
				$new_value[] = $v;
			}
			$this->value = $new_value;
		}
	}
}
 

/**
 * Extend
 *
 * @package Less
 * @subpackage tree
 */
class Less_Tree_Extend extends Less_Tree{

	public $selector;
	public $option;
	public $index;
	public $selfSelectors = array();
	public $allowBefore;
	public $allowAfter;
	public $firstExtendOnThisSelectorPath;
	public $type = 'Extend';
	public $ruleset;


	public $object_id;
	public $parent_ids = array();

	/**
	 * @param integer $index
	 */
	function __construct($selector, $option, $index){
		static $i = 0;
		$this->selector = $selector;
		$this->option = $option;
		$this->index = $index;

		switch($option){
			case "all":
				$this->allowBefore = true;
				$this->allowAfter = true;
			break;
			default:
				$this->allowBefore = false;
				$this->allowAfter = false;
			break;
		}

		$this->object_id = $i++;
		$this->parent_ids = array($this->object_id);
	}

	function accept( $visitor ){
		$this->selector = $visitor->visitObj( $this->selector );
	}

	function compile( $env ){
		Less_Parser::$has_extends = true;
		$this->selector = $this->selector->compile($env);
		return $this;
		//return new Less_Tree_Extend( $this->selector->compile($env), $this->option, $this->index);
	}

	function findSelfSelectors( $selectors ){
		$selfElements = array();


		for( $i = 0, $selectors_len = count($selectors); $i < $selectors_len; $i++ ){
			$selectorElements = $selectors[$i]->elements;
			// duplicate the logic in genCSS function inside the selector node.
			// future TODO - move both logics into the selector joiner visitor
			if( $i && $selectorElements && $selectorElements[0]->combinator === "") {
				$selectorElements[0]->combinator = ' ';
			}
			$selfElements = array_merge( $selfElements, $selectors[$i]->elements );
		}

		$this->selfSelectors = array(new Less_Tree_Selector($selfElements));
	}

} 

/**
 * CSS @import node
 *
 * The general strategy here is that we don't want to wait
 * for the parsing to be completed, before we start importing
 * the file. That's because in the context of a browser,
 * most of the time will be spent waiting for the server to respond.
 *
 * On creation, we push the import path to our import queue, though
 * `import,push`, we also pass it a callback, which it'll call once
 * the file has been fetched, and parsed.
 *
 * @package Less
 * @subpackage tree
 */
class Less_Tree_Import extends Less_Tree{

	public $options;
	public $index;
	public $path;
	public $features;
	public $currentFileInfo;
	public $css;
	public $skip;
	public $root;
	public $type = 'Import';

	function __construct($path, $features, $options, $index, $currentFileInfo = null ){
		$this->options = $options;
		$this->index = $index;
		$this->path = $path;
		$this->features = $features;
		$this->currentFileInfo = $currentFileInfo;

		if( is_array($options) ){
			$this->options += array('inline'=>false);

			if( isset($this->options['less']) || $this->options['inline'] ){
				$this->css = !isset($this->options['less']) || !$this->options['less'] || $this->options['inline'];
			} else {
				$pathValue = $this->getPath();
				if( $pathValue && preg_match('/css([\?;].*)?$/',$pathValue) ){
					$this->css = true;
				}
			}
		}
	}

//
// The actual import node doesn't return anything, when converted to CSS.
// The reason is that it's used at the evaluation stage, so that the rules
// it imports can be treated like any other rules.
//
// In `eval`, we make sure all Import nodes get evaluated, recursively, so
// we end up with a flat structure, which can easily be imported in the parent
// ruleset.
//

	function accept($visitor){

		if( $this->features ){
			$this->features = $visitor->visitObj($this->features);
		}
		$this->path = $visitor->visitObj($this->path);

		if( !$this->options['inline'] && $this->root ){
			$this->root = $visitor->visit($this->root);
		}
	}

    /**
     * @see Less_Tree::genCSS
     */
	function genCSS( $output ){
		if( $this->css ){

			$output->add( '@import ', $this->currentFileInfo, $this->index );

			$this->path->genCSS( $output );
			if( $this->features ){
				$output->add( ' ' );
				$this->features->genCSS( $output );
			}
			$output->add( ';' );
		}
	}

	function toCSS(){
		$features = $this->features ? ' ' . $this->features->toCSS() : '';

		if ($this->css) {
			return "@import " . $this->path->toCSS() . $features . ";\n";
		} else {
			return "";
		}
	}

	/**
	 * @return string
	 */
	function getPath(){
		if ($this->path instanceof Less_Tree_Quoted) {
			$path = $this->path->value;
			return ( isset($this->css) || preg_match('/(\.[a-z]*$)|([\?;].*)$/',$path)) ? $path : $path . '.less';
		} else if ($this->path instanceof Less_Tree_URL) {
			return $this->path->value->value;
		}
		return null;
	}

	function compileForImport( $env ){
		return new Less_Tree_Import( $this->path->compile($env), $this->features, $this->options, $this->index, $this->currentFileInfo);
	}

	function compilePath($env) {
		$path = $this->path->compile($env);
		$rootpath = '';
		if( $this->currentFileInfo && $this->currentFileInfo['rootpath'] ){
			$rootpath = $this->currentFileInfo['rootpath'];
		}


		if( !($path instanceof Less_Tree_URL) ){
			if( $rootpath ){
				$pathValue = $path->value;
				// Add the base path if the import is relative
				if( $pathValue && Less_Environment::isPathRelative($pathValue) ){
					$path->value = $this->currentFileInfo['uri_root'].$pathValue;
				}
			}
			$path->value = Less_Environment::normalizePath($path->value);
		}



		return $path;
	}

	function compile( $env ){

		$evald = $this->compileForImport($env);

		//get path & uri
		$path_and_uri = null;
		if( is_callable(Less_Parser::$options['import_callback']) ){
			$path_and_uri = call_user_func(Less_Parser::$options['import_callback'],$evald);
		}

		if( !$path_and_uri ){
			$path_and_uri = $evald->PathAndUri();
		}

		if( $path_and_uri ){
			list($full_path, $uri) = $path_and_uri;
		}else{
			$full_path = $uri = $evald->getPath();
		}


		//import once
		if( $evald->skip( $full_path, $env) ){
			return array();
		}

		if( $this->options['inline'] ){
			//todo needs to reference css file not import
			//$contents = new Less_Tree_Anonymous($this->root, 0, array('filename'=>$this->importedFilename), true );

			Less_Parser::AddParsedFile($full_path);
			$contents = new Less_Tree_Anonymous( file_get_contents($full_path), 0, array(), true );

			if( $this->features ){
				return new Less_Tree_Media( array($contents), $this->features->value );
			}

			return array( $contents );
		}


		// css ?
		if( $evald->css ){
			$features = ( $evald->features ? $evald->features->compile($env) : null );
			return new Less_Tree_Import( $this->compilePath( $env), $features, $this->options, $this->index);
		}


		return $this->ParseImport( $full_path, $uri, $env );
	}


	/**
	 * Using the import directories, get the full absolute path and uri of the import
	 *
	 * @param Less_Tree_Import $evald
	 */
	function PathAndUri(){

		$evald_path = $this->getPath();

		if( $evald_path ){

			$import_dirs = array();

			if( Less_Environment::isPathRelative($evald_path) ){
				//if the path is relative, the file should be in the current directory
				$import_dirs[ $this->currentFileInfo['currentDirectory'] ] = $this->currentFileInfo['uri_root'];

			}else{
				//otherwise, the file should be relative to the server root
				$import_dirs[ $this->currentFileInfo['entryPath'] ] = $this->currentFileInfo['entryUri'];

				//if the user supplied entryPath isn't the actual root
				$import_dirs[ $_SERVER['DOCUMENT_ROOT'] ] = '';

			}

			// always look in user supplied import directories
			$import_dirs = array_merge( $import_dirs, Less_Parser::$options['import_dirs'] );


			foreach( $import_dirs as $rootpath => $rooturi){
				if( is_callable($rooturi) ){
					list($path, $uri) = call_user_func($rooturi, $evald_path);
					if( is_string($path) ){
						$full_path = $path;
						return array( $full_path, $uri );
					}
				}else{
					$path = rtrim($rootpath,'/\\').'/'.ltrim($evald_path,'/\\');

					if( file_exists($path) ){
						$full_path = Less_Environment::normalizePath($path);
						$uri = Less_Environment::normalizePath(dirname($rooturi.$evald_path));
						return array( $full_path, $uri );
					}
				}
			}
		}
	}


	/**
	 * Parse the import url and return the rules
	 *
	 * @return Less_Tree_Media|array
	 */
	function ParseImport( $full_path, $uri, $env ){

		$import_env = clone $env;
		if( (isset($this->options['reference']) && $this->options['reference']) || isset($this->currentFileInfo['reference']) ){
			$import_env->currentFileInfo['reference'] = true;
		}

		if( (isset($this->options['multiple']) && $this->options['multiple']) ){
			$import_env->importMultiple = true;
		}

		$parser = new Less_Parser($import_env);
		$root = $parser->parseFile($full_path, $uri, true);


		$ruleset = new Less_Tree_Ruleset(array(), $root->rules );
		$ruleset->evalImports($import_env);

		return $this->features ? new Less_Tree_Media($ruleset->rules, $this->features->value) : $ruleset->rules;
	}


	/**
	 * Should the import be skipped?
	 *
	 * @return boolean|null
	 */
	private function Skip($path, $env){

		$path = realpath($path);

		if( $path && Less_Parser::FileParsed($path) ){

			if( isset($this->currentFileInfo['reference']) ){
				return true;
			}

			return !isset($this->options['multiple']) && !$env->importMultiple;
		}

	}
}

 

/**
 * Javascript
 *
 * @package Less
 * @subpackage tree
 */
class Less_Tree_Javascript extends Less_Tree{

	public $type = 'Javascript';
	public $escaped;
	public $expression;
	public $index;

	/**
	 * @param boolean $index
	 * @param boolean $escaped
	 */
	public function __construct($string, $index, $escaped){
		$this->escaped = $escaped;
		$this->expression = $string;
		$this->index = $index;
	}

	public function compile(){
		return new Less_Tree_Anonymous('/* Sorry, can not do JavaScript evaluation in PHP... :( */');
	}

}
 

/**
 * Keyword
 *
 * @package Less
 * @subpackage tree
 */
class Less_Tree_Keyword extends Less_Tree{

	public $value;
	public $type = 'Keyword';

	/**
	 * @param string $value
	 */
	public function __construct($value){
		$this->value = $value;
	}

	public function compile(){
		return $this;
	}

    /**
     * @see Less_Tree::genCSS
     */
	public function genCSS( $output ){

		if( $this->value === '%') {
			throw new Less_Exception_Compiler("Invalid % without number");
		}

		$output->add( $this->value );
	}

	public function compare($other) {
		if ($other instanceof Less_Tree_Keyword) {
			return $other->value === $this->value ? 0 : 1;
		} else {
			return -1;
		}
	}
}
 

/**
 * Media
 *
 * @package Less
 * @subpackage tree
 */
class Less_Tree_Media extends Less_Tree{

	public $features;
	public $rules;
	public $index;
	public $currentFileInfo;
	public $isReferenced;
	public $type = 'Media';
	public $allExtends;

	public function __construct($value = array(), $features = array(), $index = null, $currentFileInfo = null ){

		$this->index = $index;
		$this->currentFileInfo = $currentFileInfo;

		$selectors = $this->emptySelectors();

		$this->features = new Less_Tree_Value($features);

		$this->rules = array(new Less_Tree_Ruleset($selectors, $value));
		$this->rules[0]->allowImports = true;
	}

	function accept( $visitor ){
		$this->features = $visitor->visitObj($this->features);
		$this->rules = $visitor->visitArray($this->rules);
	}

    /**
     * @see Less_Tree::genCSS
     */
	function genCSS( $output ){

		$output->add( '@media ', $this->currentFileInfo, $this->index );
		$this->features->genCSS( $output );
		Less_Tree::outputRuleset( $output, $this->rules);

	}

	public function compile($env) {

		$media = new Less_Tree_Media(array(), array(), $this->index, $this->currentFileInfo );

		$strictMathBypass = false;
		if( Less_Parser::$options['strictMath'] === false) {
			$strictMathBypass = true;
			Less_Parser::$options['strictMath'] = true;
		}

		$media->features = $this->features->compile($env);

		if( $strictMathBypass ){
			Less_Parser::$options['strictMath'] = false;
		}

		$env->mediaPath[] = $media;
		$env->mediaBlocks[] = $media;

		array_unshift($env->frames, $this->rules[0]);
		$media->rules = array($this->rules[0]->compile($env));
		array_shift($env->frames);

		array_pop($env->mediaPath);

		return !$env->mediaPath ? $media->compileTop($env) : $media->compileNested($env);
	}

	public function variable($name) {
		return $this->rules[0]->variable($name);
	}

	public function find($selector) {
		return $this->rules[0]->find($selector, $this);
	}

	public function emptySelectors(){
		$el = new Less_Tree_Element('','&', $this->index, $this->currentFileInfo );
		$sels = array( new Less_Tree_Selector(array($el), array(), null, $this->index, $this->currentFileInfo) );
		$sels[0]->mediaEmpty = true;
        return $sels;
	}

	public function markReferenced(){
		$this->rules[0]->markReferenced();
		$this->isReferenced = true;
		Less_Tree::ReferencedArray($this->rules[0]->rules);
	}

	// evaltop
	public function compileTop($env) {
		$result = $this;

		if (count($env->mediaBlocks) > 1) {
			$selectors = $this->emptySelectors();
			$result = new Less_Tree_Ruleset($selectors, $env->mediaBlocks);
			$result->multiMedia = true;
		}

		$env->mediaBlocks = array();
		$env->mediaPath = array();

		return $result;
	}

	public function compileNested($env) {
		$path = array_merge($env->mediaPath, array($this));

		// Extract the media-query conditions separated with `,` (OR).
		foreach ($path as $key => $p) {
			$value = $p->features instanceof Less_Tree_Value ? $p->features->value : $p->features;
			$path[$key] = is_array($value) ? $value : array($value);
		}

		// Trace all permutations to generate the resulting media-query.
		//
		// (a, b and c) with nested (d, e) ->
		//	a and d
		//	a and e
		//	b and c and d
		//	b and c and e

		$permuted = $this->permute($path);
		$expressions = array();
		foreach($permuted as $path){

			for( $i=0, $len=count($path); $i < $len; $i++){
				$path[$i] = Less_Parser::is_method($path[$i], 'toCSS') ? $path[$i] : new Less_Tree_Anonymous($path[$i]);
			}

			for( $i = count($path) - 1; $i > 0; $i-- ){
				array_splice($path, $i, 0, array(new Less_Tree_Anonymous('and')));
			}

			$expressions[] = new Less_Tree_Expression($path);
		}
		$this->features = new Less_Tree_Value($expressions);



		// Fake a tree-node that doesn't output anything.
		return new Less_Tree_Ruleset(array(), array());
	}

	public function permute($arr) {
		if (!$arr)
			return array();

		if (count($arr) == 1)
			return $arr[0];

		$result = array();
		$rest = $this->permute(array_slice($arr, 1));
		foreach ($rest as $r) {
			foreach ($arr[0] as $a) {
				$result[] = array_merge(
					is_array($a) ? $a : array($a),
					is_array($r) ? $r : array($r)
				);
			}
		}

		return $result;
	}

	function bubbleSelectors($selectors) {

		if( !$selectors) return;

		$this->rules = array(new Less_Tree_Ruleset( $selectors, array($this->rules[0])));
	}

}
 

/**
 * A simple css name-value pair
 * ex: width:100px;
 *
 * In bootstrap, there are about 600-1,000 simple name-value pairs (depending on how forgiving the match is) -vs- 6,020 dynamic rules (Less_Tree_Rule)
 * Using the name-value object can speed up bootstrap compilation slightly, but it breaks color keyword interpretation: color:red -> color:#FF0000;
 *
 * @package Less
 * @subpackage tree
 */
class Less_Tree_NameValue extends Less_Tree{

	public $name;
	public $value;
	public $index;
	public $currentFileInfo;
	public $type = 'NameValue';

	public function __construct($name, $value = null, $index = null, $currentFileInfo = null ){
		$this->name = $name;
		$this->value = $value;
		$this->index = $index;
		$this->currentFileInfo = $currentFileInfo;
	}

	function genCSS( $output ){

		$output->add(
			$this->name
			. Less_Environment::$_outputMap[': ']
			. $this->value
			. (((Less_Environment::$lastRule && Less_Parser::$options['compress'])) ? "" : ";")
			, $this->currentFileInfo, $this->index);
	}

	public function compile ($env){
		return $this;
	}
}
 

/**
 * Negative
 *
 * @package Less
 * @subpackage tree
 */
class Less_Tree_Negative extends Less_Tree{

	public $parensInOp;
	public $value;
	public $type = 'Negative';

	function __construct($node){
		$this->value = $node;
	}

	//function accept($visitor) {
	//	$this->value = $visitor->visit($this->value);
	//}

    /**
     * @see Less_Tree::genCSS
     */
	function genCSS( $output ){
		$output->add( '-' );
		$this->value->genCSS( $output );
	}

	function compile($env) {
		if( Less_Environment::isMathOn() ){
			$ret = new Less_Tree_Operation('*', array( new Less_Tree_Dimension(-1), $this->value ) );
			return $ret->compile($env);
		}
		return new Less_Tree_Negative( $this->value->compile($env) );
	}
} 

/**
 * Operation
 *
 * @package Less
 * @subpackage tree
 */
class Less_Tree_Operation extends Less_Tree{

	public $parensInOp;
	public $op;
	public $operands;
	public $isSpaced;
	public $type = 'Operation';

	/**
	 * @param string $op
	 */
	public function __construct($op, $operands, $isSpaced = false){
		$this->op = trim($op);
		$this->operands = $operands;
		$this->isSpaced = $isSpaced;
	}

	function accept($visitor) {
		$this->operands = $visitor->visitArray($this->operands);
	}

	public function compile($env){
		$a = $this->operands[0]->compile($env);
		$b = $this->operands[1]->compile($env);


		if( Less_Environment::isMathOn() ){

			if( $a instanceof Less_Tree_Dimension && $b instanceof Less_Tree_Color ){
				$a = $a->toColor();

			}elseif( $b instanceof Less_Tree_Dimension && $a instanceof Less_Tree_Color ){
				$b = $b->toColor();

			}

			if( !method_exists($a,'operate') ){
				throw new Less_Exception_Compiler("Operation on an invalid type");
			}

			return $a->operate( $this->op, $b);
		}

		return new Less_Tree_Operation($this->op, array($a, $b), $this->isSpaced );
	}


    /**
     * @see Less_Tree::genCSS
     */
	function genCSS( $output ){
		$this->operands[0]->genCSS( $output );
		if( $this->isSpaced ){
			$output->add( " " );
		}
		$output->add( $this->op );
		if( $this->isSpaced ){
			$output->add( ' ' );
		}
		$this->operands[1]->genCSS( $output );
	}

}
 

/**
 * Paren
 *
 * @package Less
 * @subpackage tree
 */
class Less_Tree_Paren extends Less_Tree{

	public $value;
	public $type = 'Paren';

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

	function accept($visitor){
		$this->value = $visitor->visitObj($this->value);
	}

    /**
     * @see Less_Tree::genCSS
     */
	function genCSS( $output ){
		$output->add( '(' );
		$this->value->genCSS( $output );
		$output->add( ')' );
	}

	public function compile($env) {
		return new Less_Tree_Paren($this->value->compile($env));
	}

}
 

/**
 * Quoted
 *
 * @package Less
 * @subpackage tree
 */
class Less_Tree_Quoted extends Less_Tree{
	public $escaped;
	public $value;
	public $quote;
	public $index;
	public $currentFileInfo;
	public $type = 'Quoted';

	/**
	 * @param string $str
	 */
	public function __construct($str, $content = '', $escaped = false, $index = false, $currentFileInfo = null ){
		$this->escaped = $escaped;
		$this->value = $content;
		if( $str ){
			$this->quote = $str[0];
		}
		$this->index = $index;
		$this->currentFileInfo = $currentFileInfo;
	}

    /**
     * @see Less_Tree::genCSS
     */
    public function genCSS( $output ){
		if( !$this->escaped ){
			$output->add( $this->quote, $this->currentFileInfo, $this->index );
        }
        $output->add( $this->value );
        if( !$this->escaped ){
			$output->add( $this->quote );
        }
    }

	public function compile($env){

		$value = $this->value;
		if( preg_match_all('/`([^`]+)`/', $this->value, $matches) ){
			foreach($matches as $i => $match){
				$js = new Less_Tree_JavaScript($matches[1], $this->index, true);
				$js = $js->compile()->value;
				$value = str_replace($matches[0][$i], $js, $value);
			}
		}

		if( preg_match_all('/@\{([\w-]+)\}/',$value,$matches) ){
			foreach($matches[1] as $i => $match){
				$v = new Less_Tree_Variable('@' . $match, $this->index, $this->currentFileInfo );
				$v = $v->compile($env);
				$v = ($v instanceof Less_Tree_Quoted) ? $v->value : $v->toCSS();
				$value = str_replace($matches[0][$i], $v, $value);
			}
		}

		return new Less_Tree_Quoted($this->quote . $value . $this->quote, $value, $this->escaped, $this->index, $this->currentFileInfo);
	}

	function compare($x) {

		if( !Less_Parser::is_method($x, 'toCSS') ){
			return -1;
		}

		$left = $this->toCSS();
		$right = $x->toCSS();

		if ($left === $right) {
			return 0;
		}

		return $left < $right ? -1 : 1;
	}
}
 

/**
 * Rule
 *
 * @package Less
 * @subpackage tree
 */
class Less_Tree_Rule extends Less_Tree{

	public $name;
	public $value;
	public $important;
	public $merge;
	public $index;
	public $inline;
	public $variable;
	public $currentFileInfo;
	public $type = 'Rule';

	/**
	 * @param string $important
	 */
	public function __construct($name, $value = null, $important = null, $merge = null, $index = null, $currentFileInfo = null,  $inline = false){
		$this->name = $name;
		$this->value = ($value instanceof Less_Tree_Value || $value instanceof Less_Tree_Ruleset) ? $value : new Less_Tree_Value(array($value));
		$this->important = $important ? ' ' . trim($important) : '';
		$this->merge = $merge;
		$this->index = $index;
		$this->currentFileInfo = $currentFileInfo;
		$this->inline = $inline;
		$this->variable = ( is_string($name) && $name[0] === '@');
	}

	function accept($visitor) {
		$this->value = $visitor->visitObj( $this->value );
	}

    /**
     * @see Less_Tree::genCSS
     */
	function genCSS( $output ){

		$output->add( $this->name . Less_Environment::$_outputMap[': '], $this->currentFileInfo, $this->index);
		try{
			$this->value->genCSS( $output);

		}catch( Less_Exception_Parser $e ){
			$e->index = $this->index;
			$e->currentFile = $this->currentFileInfo;
			throw $e;
		}
		$output->add( $this->important . (($this->inline || (Less_Environment::$lastRule && Less_Parser::$options['compress'])) ? "" : ";"), $this->currentFileInfo, $this->index);
	}

	public function compile ($env){

		$name = $this->name;
		if( is_array($name) ){
			// expand 'primitive' name directly to get
			// things faster (~10% for benchmark.less):
			if( count($name) === 1 && $name[0] instanceof Less_Tree_Keyword ){
				$name = $name[0]->value;
			}else{
				$name = $this->CompileName($env,$name);
			}
		}

		$strictMathBypass = Less_Parser::$options['strictMath'];
		if( $name === "font" && !Less_Parser::$options['strictMath'] ){
			Less_Parser::$options['strictMath'] = true;
		}

		try {
			$evaldValue = $this->value->compile($env);

			if( !$this->variable && $evaldValue->type === "DetachedRuleset") {
				throw new Less_Exception_Compiler("Rulesets cannot be evaluated on a property.", null, $this->index, $this->currentFileInfo);
			}

			if( Less_Environment::$mixin_stack ){
				$return = new Less_Tree_Rule($name, $evaldValue, $this->important, $this->merge, $this->index, $this->currentFileInfo, $this->inline);
			}else{
				$this->name = $name;
				$this->value = $evaldValue;
				$return = $this;
			}

		}catch( Less_Exception_Parser $e ){
			if( !is_numeric($e->index) ){
				$e->index = $this->index;
				$e->currentFile = $this->currentFileInfo;
			}
			throw $e;
		}

		Less_Parser::$options['strictMath'] = $strictMathBypass;

		return $return;
	}


	function CompileName( $env, $name ){
		$output = new Less_Output();
		foreach($name as $n){
			$n->compile($env)->genCSS($output);
		}
		return $output->toString();
	}

	function makeImportant(){
		return new Less_Tree_Rule($this->name, $this->value, '!important', $this->merge, $this->index, $this->currentFileInfo, $this->inline);
	}

}
 

/**
 * Ruleset
 *
 * @package Less
 * @subpackage tree
 */
class Less_Tree_Ruleset extends Less_Tree{

	protected $lookups;
	public $_variables;
	public $_rulesets;

	public $strictImports;

	public $selectors;
	public $rules;
	public $root;
	public $allowImports;
	public $paths;
	public $firstRoot;
	public $type = 'Ruleset';
	public $multiMedia;
	public $allExtends;
	public $extendOnEveryPath;

	var $ruleset_id;
	var $originalRuleset;

	var $first_oelements;

	public function SetRulesetIndex(){
		$this->ruleset_id = Less_Parser::$next_id++;
		$this->originalRuleset = $this->ruleset_id;

		if( $this->selectors ){
			foreach($this->selectors as $sel){
				if( $sel->_oelements ){
					$this->first_oelements[$sel->_oelements[0]] = true;
				}
			}
		}
	}

	public function __construct($selectors, $rules, $strictImports = null){
		$this->selectors = $selectors;
		$this->rules = $rules;
		$this->lookups = array();
		$this->strictImports = $strictImports;
		$this->SetRulesetIndex();
	}

	function accept( $visitor ){
		if( $this->paths ){
			$paths_len = count($this->paths);
			for($i = 0,$paths_len; $i < $paths_len; $i++ ){
				$this->paths[$i] = $visitor->visitArray($this->paths[$i]);
			}
		}elseif( $this->selectors ){
			$this->selectors = $visitor->visitArray($this->selectors);
		}

		if( $this->rules ){
			$this->rules = $visitor->visitArray($this->rules);
		}
	}

	public function compile($env){

		$ruleset = $this->PrepareRuleset($env);


		// Store the frames around mixin definitions,
		// so they can be evaluated like closures when the time comes.
		$rsRuleCnt = count($ruleset->rules);
		for( $i = 0; $i < $rsRuleCnt; $i++ ){
			if( $ruleset->rules[$i] instanceof Less_Tree_Mixin_Definition || $ruleset->rules[$i] instanceof Less_Tree_DetachedRuleset ){
				$ruleset->rules[$i] = $ruleset->rules[$i]->compile($env);
			}
		}

		$mediaBlockCount = 0;
		if( $env instanceof Less_Environment ){
			$mediaBlockCount = count($env->mediaBlocks);
		}

		// Evaluate mixin calls.
		$this->EvalMixinCalls( $ruleset, $env, $rsRuleCnt );


		// Evaluate everything else
		for( $i=0; $i<$rsRuleCnt; $i++ ){
			if(! ($ruleset->rules[$i] instanceof Less_Tree_Mixin_Definition || $ruleset->rules[$i] instanceof Less_Tree_DetachedRuleset) ){
				$ruleset->rules[$i] = $ruleset->rules[$i]->compile($env);
			}
		}

        // Evaluate everything else
		for( $i=0; $i<$rsRuleCnt; $i++ ){
			$rule = $ruleset->rules[$i];

            // for rulesets, check if it is a css guard and can be removed
			if( $rule instanceof Less_Tree_Ruleset && $rule->selectors && count($rule->selectors) === 1 ){

                // check if it can be folded in (e.g. & where)
				if( $rule->selectors[0]->isJustParentSelector() ){
					array_splice($ruleset->rules,$i--,1);
					$rsRuleCnt--;

					for($j = 0; $j < count($rule->rules); $j++ ){
						$subRule = $rule->rules[$j];
						if( !($subRule instanceof Less_Tree_Rule) || !$subRule->variable ){
							array_splice($ruleset->rules, ++$i, 0, array($subRule));
							$rsRuleCnt++;
						}
					}

                }
            }
        }


		// Pop the stack
		$env->shiftFrame();

		if ($mediaBlockCount) {
			$len = count($env->mediaBlocks);
			for($i = $mediaBlockCount; $i < $len; $i++ ){
				$env->mediaBlocks[$i]->bubbleSelectors($ruleset->selectors);
			}
		}

		return $ruleset;
	}

	/**
	 * Compile Less_Tree_Mixin_Call objects
	 *
	 * @param Less_Tree_Ruleset $ruleset
	 * @param integer $rsRuleCnt
	 */
	private function EvalMixinCalls( $ruleset, $env, &$rsRuleCnt ){
		for($i=0; $i < $rsRuleCnt; $i++){
			$rule = $ruleset->rules[$i];

			if( $rule instanceof Less_Tree_Mixin_Call ){
				$rule = $rule->compile($env);

				$temp = array();
				foreach($rule as $r){
					if( ($r instanceof Less_Tree_Rule) && $r->variable ){
						// do not pollute the scope if the variable is
						// already there. consider returning false here
						// but we need a way to "return" variable from mixins
						if( !$ruleset->variable($r->name) ){
							$temp[] = $r;
						}
					}else{
						$temp[] = $r;
					}
				}
				$temp_count = count($temp)-1;
				array_splice($ruleset->rules, $i, 1, $temp);
				$rsRuleCnt += $temp_count;
				$i += $temp_count;
				$ruleset->resetCache();

			}elseif( $rule instanceof Less_Tree_RulesetCall ){

				$rule = $rule->compile($env);
				$rules = array();
				foreach($rule->rules as $r){
					if( ($r instanceof Less_Tree_Rule) && $r->variable ){
						continue;
					}
					$rules[] = $r;
				}

				array_splice($ruleset->rules, $i, 1, $rules);
				$temp_count = count($rules);
				$rsRuleCnt += $temp_count - 1;
				$i += $temp_count-1;
				$ruleset->resetCache();
			}

		}
	}


	/**
	 * Compile the selectors and create a new ruleset object for the compile() method
	 *
	 */
	private function PrepareRuleset($env){

		$hasOnePassingSelector = false;
		$selectors = array();
		if( $this->selectors ){
			Less_Tree_DefaultFunc::error("it is currently only allowed in parametric mixin guards,");

			foreach($this->selectors as $s){
				$selector = $s->compile($env);
				$selectors[] = $selector;
				if( $selector->evaldCondition ){
					$hasOnePassingSelector = true;
				}
			}

			Less_Tree_DefaultFunc::reset();
		} else {
			$hasOnePassingSelector = true;
		}

		if( $this->rules && $hasOnePassingSelector ){
			$rules = $this->rules;
		}else{
			$rules = array();
		}

		$ruleset = new Less_Tree_Ruleset($selectors, $rules, $this->strictImports);

		$ruleset->originalRuleset = $this->ruleset_id;

		$ruleset->root = $this->root;
		$ruleset->firstRoot = $this->firstRoot;
		$ruleset->allowImports = $this->allowImports;


		// push the current ruleset to the frames stack
		$env->unshiftFrame($ruleset);


		// Evaluate imports
		if( $ruleset->root || $ruleset->allowImports || !$ruleset->strictImports ){
			$ruleset->evalImports($env);
		}

		return $ruleset;
	}

	function evalImports($env) {

		$rules_len = count($this->rules);
		for($i=0; $i < $rules_len; $i++){
			$rule = $this->rules[$i];

			if( $rule instanceof Less_Tree_Import ){
				$rules = $rule->compile($env);
				if( is_array($rules) ){
					array_splice($this->rules, $i, 1, $rules);
					$temp_count = count($rules)-1;
					$i += $temp_count;
					$rules_len += $temp_count;
				}else{
					array_splice($this->rules, $i, 1, array($rules));
				}

				$this->resetCache();
			}
		}
	}

	function makeImportant(){

		$important_rules = array();
		foreach($this->rules as $rule){
			if( $rule instanceof Less_Tree_Rule || $rule instanceof Less_Tree_Ruleset ){
				$important_rules[] = $rule->makeImportant();
			}else{
				$important_rules[] = $rule;
			}
		}

		return new Less_Tree_Ruleset($this->selectors, $important_rules, $this->strictImports );
	}

	public function matchArgs($args){
		return !$args;
	}

	// lets you call a css selector with a guard
	public function matchCondition( $args, $env ){
		$lastSelector = end($this->selectors);

		if( !$lastSelector->evaldCondition ){
			return false;
		}
		if( $lastSelector->condition && !$lastSelector->condition->compile( $env->copyEvalEnv( $env->frames ) ) ){
			return false;
		}
		return true;
	}

	function resetCache(){
		$this->_rulesets = null;
		$this->_variables = null;
		$this->lookups = array();
	}

	public function variables(){
		$this->_variables = array();
		foreach( $this->rules as $r){
			if ($r instanceof Less_Tree_Rule && $r->variable === true) {
				$this->_variables[$r->name] = $r;
			}
		}
	}

	public function variable($name){

		if( is_null($this->_variables) ){
			$this->variables();
		}
		return isset($this->_variables[$name]) ? $this->_variables[$name] : null;
	}

	public function find( $selector, $self = null ){

		$key = implode(' ',$selector->_oelements);

		if( !isset($this->lookups[$key]) ){

			if( !$self ){
				$self = $this->ruleset_id;
			}

			$this->lookups[$key] = array();

			$first_oelement = $selector->_oelements[0];

			foreach($this->rules as $rule){
				if( $rule instanceof Less_Tree_Ruleset && $rule->ruleset_id != $self ){

					if( isset($rule->first_oelements[$first_oelement]) ){

						foreach( $rule->selectors as $ruleSelector ){
							$match = $selector->match($ruleSelector);
							if( $match ){
								if( $selector->elements_len > $match ){
									$this->lookups[$key] = array_merge($this->lookups[$key], $rule->find( new Less_Tree_Selector(array_slice($selector->elements, $match)), $self));
								} else {
									$this->lookups[$key][] = $rule;
								}
								break;
							}
						}
					}
				}
			}
		}

		return $this->lookups[$key];
	}


	/**
	 * @see Less_Tree::genCSS
	 */
	public function genCSS( $output ){

		if( !$this->root ){
			Less_Environment::$tabLevel++;
		}

		$tabRuleStr = $tabSetStr = '';
		if( !Less_Parser::$options['compress'] ){
			if( Less_Environment::$tabLevel ){
				$tabRuleStr = "\n".str_repeat( '  ' , Less_Environment::$tabLevel );
				$tabSetStr = "\n".str_repeat( '  ' , Less_Environment::$tabLevel-1 );
			}else{
				$tabSetStr = $tabRuleStr = "\n";
			}
		}


		$ruleNodes = array();
		$rulesetNodes = array();
		foreach($this->rules as $rule){

			$class = get_class($rule);
			if( ($class === 'Less_Tree_Media') || ($class === 'Less_Tree_Directive') || ($this->root && $class === 'Less_Tree_Comment') || ($class === 'Less_Tree_Ruleset' && $rule->rules) ){
				$rulesetNodes[] = $rule;
			}else{
				$ruleNodes[] = $rule;
			}
		}

		// If this is the root node, we don't render
		// a selector, or {}.
		if( !$this->root ){

			/*
			debugInfo = tree.debugInfo(env, this, tabSetStr);

			if (debugInfo) {
				output.add(debugInfo);
				output.add(tabSetStr);
			}
			*/

			$paths_len = count($this->paths);
			for( $i = 0; $i < $paths_len; $i++ ){
				$path = $this->paths[$i];
				$firstSelector = true;

				foreach($path as $p){
					$p->genCSS( $output, $firstSelector );
					$firstSelector = false;
				}

				if( $i + 1 < $paths_len ){
					$output->add( ',' . $tabSetStr );
				}
			}

			$output->add( (Less_Parser::$options['compress'] ? '{' : " {") . $tabRuleStr );
		}

		// Compile rules and rulesets
		$ruleNodes_len = count($ruleNodes);
		$rulesetNodes_len = count($rulesetNodes);
		for( $i = 0; $i < $ruleNodes_len; $i++ ){
			$rule = $ruleNodes[$i];

			// @page{ directive ends up with root elements inside it, a mix of rules and rulesets
			// In this instance we do not know whether it is the last property
			if( $i + 1 === $ruleNodes_len && (!$this->root || $rulesetNodes_len === 0 || $this->firstRoot ) ){
				Less_Environment::$lastRule = true;
			}

			$rule->genCSS( $output );

			if( !Less_Environment::$lastRule ){
				$output->add( $tabRuleStr );
			}else{
				Less_Environment::$lastRule = false;
			}
		}

		if( !$this->root ){
			$output->add( $tabSetStr . '}' );
			Less_Environment::$tabLevel--;
		}

		$firstRuleset = true;
		$space = ($this->root ? $tabRuleStr : $tabSetStr);
		for( $i = 0; $i < $rulesetNodes_len; $i++ ){

			if( $ruleNodes_len && $firstRuleset ){
				$output->add( $space );
			}elseif( !$firstRuleset ){
				$output->add( $space );
			}
			$firstRuleset = false;
			$rulesetNodes[$i]->genCSS( $output);
		}

		if( !Less_Parser::$options['compress'] && $this->firstRoot ){
			$output->add( "\n" );
		}

	}


	function markReferenced(){
		if( !$this->selectors ){
			return;
		}
		foreach($this->selectors as $selector){
			$selector->markReferenced();
		}
	}

	public function joinSelectors( $context, $selectors ){
		$paths = array();
		if( is_array($selectors) ){
			foreach($selectors as $selector) {
				$this->joinSelector( $paths, $context, $selector);
			}
		}
		return $paths;
	}

	public function joinSelector( &$paths, $context, $selector){

		$hasParentSelector = false;

		foreach($selector->elements as $el) {
			if( $el->value === '&') {
				$hasParentSelector = true;
			}
		}

		if( !$hasParentSelector ){
			if( $context ){
				foreach($context as $context_el){
					$paths[] = array_merge($context_el, array($selector) );
				}
			}else {
				$paths[] = array($selector);
			}
			return;
		}


		// The paths are [[Selector]]
		// The first list is a list of comma seperated selectors
		// The inner list is a list of inheritance seperated selectors
		// e.g.
		// .a, .b {
		//   .c {
		//   }
		// }
		// == [[.a] [.c]] [[.b] [.c]]
		//

		// the elements from the current selector so far
		$currentElements = array();
		// the current list of new selectors to add to the path.
		// We will build it up. We initiate it with one empty selector as we "multiply" the new selectors
		// by the parents
		$newSelectors = array(array());


		foreach( $selector->elements as $el){

			// non parent reference elements just get added
			if( $el->value !== '&' ){
				$currentElements[] = $el;
			} else {
				// the new list of selectors to add
				$selectorsMultiplied = array();

				// merge the current list of non parent selector elements
				// on to the current list of selectors to add
				if( $currentElements ){
					$this->mergeElementsOnToSelectors( $currentElements, $newSelectors);
				}

				// loop through our current selectors
				foreach($newSelectors as $sel){

					// if we don't have any parent paths, the & might be in a mixin so that it can be used
					// whether there are parents or not
					if( !$context ){
						// the combinator used on el should now be applied to the next element instead so that
						// it is not lost
						if( $sel ){
							$sel[0]->elements = array_slice($sel[0]->elements,0);
							$sel[0]->elements[] = new Less_Tree_Element($el->combinator, '', $el->index, $el->currentFileInfo );
						}
						$selectorsMultiplied[] = $sel;
					}else {

						// and the parent selectors
						foreach($context as $parentSel){
							// We need to put the current selectors
							// then join the last selector's elements on to the parents selectors

							// our new selector path
							$newSelectorPath = array();
							// selectors from the parent after the join
							$afterParentJoin = array();
							$newJoinedSelectorEmpty = true;

							//construct the joined selector - if & is the first thing this will be empty,
							// if not newJoinedSelector will be the last set of elements in the selector
							if( $sel ){
								$newSelectorPath = $sel;
								$lastSelector = array_pop($newSelectorPath);
								$newJoinedSelector = $selector->createDerived( array_slice($lastSelector->elements,0) );
								$newJoinedSelectorEmpty = false;
							}
							else {
								$newJoinedSelector = $selector->createDerived(array());
							}

							//put together the parent selectors after the join
							if ( count($parentSel) > 1) {
								$afterParentJoin = array_merge($afterParentJoin, array_slice($parentSel,1) );
							}

							if ( $parentSel ){
								$newJoinedSelectorEmpty = false;

								// join the elements so far with the first part of the parent
								$newJoinedSelector->elements[] = new Less_Tree_Element( $el->combinator, $parentSel[0]->elements[0]->value, $el->index, $el->currentFileInfo);

								$newJoinedSelector->elements = array_merge( $newJoinedSelector->elements, array_slice($parentSel[0]->elements, 1) );
							}

							if (!$newJoinedSelectorEmpty) {
								// now add the joined selector
								$newSelectorPath[] = $newJoinedSelector;
							}

							// and the rest of the parent
							$newSelectorPath = array_merge($newSelectorPath, $afterParentJoin);

							// add that to our new set of selectors
							$selectorsMultiplied[] = $newSelectorPath;
						}
					}
				}

				// our new selectors has been multiplied, so reset the state
				$newSelectors = $selectorsMultiplied;
				$currentElements = array();
			}
		}

		// if we have any elements left over (e.g. .a& .b == .b)
		// add them on to all the current selectors
		if( $currentElements ){
			$this->mergeElementsOnToSelectors($currentElements, $newSelectors);
		}
		foreach( $newSelectors as $new_sel){
			if( $new_sel ){
				$paths[] = $new_sel;
			}
		}
	}

	function mergeElementsOnToSelectors( $elements, &$selectors){

		if( !$selectors ){
			$selectors[] = array( new Less_Tree_Selector($elements) );
			return;
		}


		foreach( $selectors as &$sel){

			// if the previous thing in sel is a parent this needs to join on to it
			if( $sel ){
				$last = count($sel)-1;
				$sel[$last] = $sel[$last]->createDerived( array_merge($sel[$last]->elements, $elements) );
			}else{
				$sel[] = new Less_Tree_Selector( $elements );
			}
		}
	}
}
 

/**
 * RulesetCall
 *
 * @package Less
 * @subpackage tree
 */
class Less_Tree_RulesetCall extends Less_Tree{

	public $variable;
	public $type = "RulesetCall";

	function __construct($variable){
		$this->variable = $variable;
	}

	function accept($visitor) {}

	function compile( $env ){
		$variable = new Less_Tree_Variable($this->variable);
		$detachedRuleset = $variable->compile($env);
		return $detachedRuleset->callEval($env);
	}
}

 

/**
 * Selector
 *
 * @package Less
 * @subpackage tree
 */
class Less_Tree_Selector extends Less_Tree{

	public $elements;
	public $condition;
	public $extendList = array();
	public $_css;
	public $index;
	public $evaldCondition = false;
	public $type = 'Selector';
	public $currentFileInfo = array();
	public $isReferenced;
	public $mediaEmpty;

	public $elements_len = 0;

	public $_oelements;
	public $_oelements_len;
	public $cacheable = true;

	/**
	 * @param boolean $isReferenced
	 */
	public function __construct( $elements, $extendList = array() , $condition = null, $index=null, $currentFileInfo=null, $isReferenced=null ){

		$this->elements = $elements;
		$this->elements_len = count($elements);
		$this->extendList = $extendList;
		$this->condition = $condition;
		if( $currentFileInfo ){
			$this->currentFileInfo = $currentFileInfo;
		}
		$this->isReferenced = $isReferenced;
		if( !$condition ){
			$this->evaldCondition = true;
		}

		$this->CacheElements();
	}

	function accept($visitor) {
		$this->elements = $visitor->visitArray($this->elements);
		$this->extendList = $visitor->visitArray($this->extendList);
		if( $this->condition ){
			$this->condition = $visitor->visitObj($this->condition);
		}

		if( $visitor instanceof Less_Visitor_extendFinder ){
			$this->CacheElements();
		}
	}

	function createDerived( $elements, $extendList = null, $evaldCondition = null ){
		$newSelector = new Less_Tree_Selector( $elements, ($extendList ? $extendList : $this->extendList), null, $this->index, $this->currentFileInfo, $this->isReferenced);
		$newSelector->evaldCondition = $evaldCondition ? $evaldCondition : $this->evaldCondition;
		return $newSelector;
	}


	public function match( $other ){

		if( !$other->_oelements || ($this->elements_len < $other->_oelements_len) ){
			return 0;
		}

		for( $i = 0; $i < $other->_oelements_len; $i++ ){
			if( $this->elements[$i]->value !== $other->_oelements[$i]) {
				return 0;
			}
		}

		return $other->_oelements_len; // return number of matched elements
	}


	public function CacheElements(){

		$this->_oelements = array();
		$css = '';

		foreach($this->elements as $v){

			$css .= $v->combinator;
			if( !$v->value_is_object ){
				$css .= $v->value;
				continue;
			}

			if( !property_exists($v->value,'value') || !is_string($v->value->value) ){
				$this->cacheable = false;
				return;
			}
			$css .= $v->value->value;
		}

		$this->_oelements_len = preg_match_all('/[,&#\.\w-](?:[\w-]|(?:\\\\.))*/', $css, $matches);
		if( $this->_oelements_len ){
			$this->_oelements = $matches[0];

			if( $this->_oelements[0] === '&' ){
				array_shift($this->_oelements);
				$this->_oelements_len--;
			}
		}
	}

	public function isJustParentSelector(){
		return !$this->mediaEmpty &&
			count($this->elements) === 1 &&
			$this->elements[0]->value === '&' &&
			($this->elements[0]->combinator === ' ' || $this->elements[0]->combinator === '');
	}

	public function compile($env) {

		$elements = array();
		foreach($this->elements as $el){
			$elements[] = $el->compile($env);
		}

		$extendList = array();
		foreach($this->extendList as $el){
			$extendList[] = $el->compile($el);
		}

		$evaldCondition = false;
		if( $this->condition ){
			$evaldCondition = $this->condition->compile($env);
		}

		return $this->createDerived( $elements, $extendList, $evaldCondition );
	}


	/**
	 * @see Less_Tree::genCSS
	 */
	function genCSS( $output, $firstSelector = true ){

		if( !$firstSelector && $this->elements[0]->combinator === "" ){
			$output->add(' ', $this->currentFileInfo, $this->index);
		}

		foreach($this->elements as $element){
			$element->genCSS( $output );
		}
	}

	function markReferenced(){
		$this->isReferenced = true;
	}

	function getIsReferenced(){
		return !isset($this->currentFileInfo['reference']) || !$this->currentFileInfo['reference'] || $this->isReferenced;
	}

	function getIsOutput(){
		return $this->evaldCondition;
	}

}
 

/**
 * UnicodeDescriptor
 *
 * @package Less
 * @subpackage tree
 */
class Less_Tree_UnicodeDescriptor extends Less_Tree{

	public $value;
	public $type = 'UnicodeDescriptor';

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

    /**
     * @see Less_Tree::genCSS
     */
	public function genCSS( $output ){
		$output->add( $this->value );
	}

	public function compile(){
		return $this;
	}
}

 

/**
 * Unit
 *
 * @package Less
 * @subpackage tree
 */
class Less_Tree_Unit extends Less_Tree{

	var $numerator = array();
	var $denominator = array();
	public $backupUnit;
	public $type = 'Unit';

	function __construct($numerator = array(), $denominator = array(), $backupUnit = null ){
		$this->numerator = $numerator;
		$this->denominator = $denominator;
		$this->backupUnit = $backupUnit;
	}

	function __clone(){
	}

    /**
     * @see Less_Tree::genCSS
     */
	function genCSS( $output ){

		if( $this->numerator ){
			$output->add( $this->numerator[0] );
		}elseif( $this->denominator ){
			$output->add( $this->denominator[0] );
		}elseif( !Less_Parser::$options['strictUnits'] && $this->backupUnit ){
			$output->add( $this->backupUnit );
			return ;
		}
	}

	function toString(){
		$returnStr = implode('*',$this->numerator);
		foreach($this->denominator as $d){
			$returnStr .= '/'.$d;
		}
		return $returnStr;
	}

	function __toString(){
		return $this->toString();
	}


	/**
	 * @param Less_Tree_Unit $other
	 */
	function compare($other) {
		return $this->is( $other->toString() ) ? 0 : -1;
	}

	function is($unitString){
		return $this->toString() === $unitString;
	}

	function isLength(){
		$css = $this->toCSS();
		return !!preg_match('/px|em|%|in|cm|mm|pc|pt|ex/',$css);
	}

	function isAngle() {
		return isset( Less_Tree_UnitConversions::$angle[$this->toCSS()] );
	}

	function isEmpty(){
		return !$this->numerator && !$this->denominator;
	}

	function isSingular() {
		return count($this->numerator) <= 1 && !$this->denominator;
	}


	function usedUnits(){
		$result = array();

		foreach(Less_Tree_UnitConversions::$groups as $groupName){
			$group = Less_Tree_UnitConversions::${$groupName};

			foreach($this->numerator as $atomicUnit){
				if( isset($group[$atomicUnit]) && !isset($result[$groupName]) ){
					$result[$groupName] = $atomicUnit;
				}
			}

			foreach($this->denominator as $atomicUnit){
				if( isset($group[$atomicUnit]) && !isset($result[$groupName]) ){
					$result[$groupName] = $atomicUnit;
				}
			}
		}

		return $result;
	}

	function cancel(){
		$counter = array();
		$backup = null;

		foreach($this->numerator as $atomicUnit){
			if( !$backup ){
				$backup = $atomicUnit;
			}
			$counter[$atomicUnit] = ( isset($counter[$atomicUnit]) ? $counter[$atomicUnit] : 0) + 1;
		}

		foreach($this->denominator as $atomicUnit){
			if( !$backup ){
				$backup = $atomicUnit;
			}
			$counter[$atomicUnit] = ( isset($counter[$atomicUnit]) ? $counter[$atomicUnit] : 0) - 1;
		}

		$this->numerator = array();
		$this->denominator = array();

		foreach($counter as $atomicUnit => $count){
			if( $count > 0 ){
				for( $i = 0; $i < $count; $i++ ){
					$this->numerator[] = $atomicUnit;
				}
			}elseif( $count < 0 ){
				for( $i = 0; $i < -$count; $i++ ){
					$this->denominator[] = $atomicUnit;
				}
			}
		}

		if( !$this->numerator && !$this->denominator && $backup ){
			$this->backupUnit = $backup;
		}

		sort($this->numerator);
		sort($this->denominator);
	}


}

 

/**
 * UnitConversions
 *
 * @package Less
 * @subpackage tree
 */
class Less_Tree_UnitConversions{

	public static $groups = array('length','duration','angle');

	public static $length = array(
		'm'=> 1,
		'cm'=> 0.01,
		'mm'=> 0.001,
		'in'=> 0.0254,
		'px'=> 0.000264583, // 0.0254 / 96,
		'pt'=> 0.000352778, // 0.0254 / 72,
		'pc'=> 0.004233333, // 0.0254 / 72 * 12
		);

	public static $duration = array(
		's'=> 1,
		'ms'=> 0.001
		);

	public static $angle = array(
		'rad' => 0.1591549430919,	// 1/(2*M_PI),
		'deg' => 0.002777778, 		// 1/360,
		'grad'=> 0.0025,			// 1/400,
		'turn'=> 1
		);

} 

/**
 * Url
 *
 * @package Less
 * @subpackage tree
 */
class Less_Tree_Url extends Less_Tree{

	public $attrs;
	public $value;
	public $currentFileInfo;
	public $isEvald;
	public $type = 'Url';

	public function __construct($value, $currentFileInfo = null, $isEvald = null){
		$this->value = $value;
		$this->currentFileInfo = $currentFileInfo;
		$this->isEvald = $isEvald;
	}

	function accept( $visitor ){
		$this->value = $visitor->visitObj($this->value);
	}

    /**
     * @see Less_Tree::genCSS
     */
	function genCSS( $output ){
		$output->add( 'url(' );
		$this->value->genCSS( $output );
		$output->add( ')' );
	}

	/**
	 * @param Less_Functions $ctx
	 */
	public function compile($ctx){
		$val = $this->value->compile($ctx);

		if( !$this->isEvald ){
			// Add the base path if the URL is relative
			if( Less_Parser::$options['relativeUrls']
				&& $this->currentFileInfo
				&& is_string($val->value)
				&& Less_Environment::isPathRelative($val->value)
			){
				$rootpath = $this->currentFileInfo['uri_root'];
				if ( !$val->quote ){
					$rootpath = preg_replace('/[\(\)\'"\s]/', '\\$1', $rootpath );
				}
				$val->value = $rootpath . $val->value;
			}

			$val->value = Less_Environment::normalizePath( $val->value);
		}

		// Add cache buster if enabled
		if( Less_Parser::$options['urlArgs'] ){
			if( !preg_match('/^\s*data:/',$val->value) ){
				$delimiter = strpos($val->value,'?') === false ? '?' : '&';
				$urlArgs = $delimiter . Less_Parser::$options['urlArgs'];
				$hash_pos = strpos($val->value,'#');
				if( $hash_pos !== false ){
					$val->value = substr_replace($val->value,$urlArgs, $hash_pos, 0);
				} else {
					$val->value .= $urlArgs;
				}
			}
		}

		return new Less_Tree_URL($val, $this->currentFileInfo, true);
	}

}
 

/**
 * Value
 *
 * @package Less
 * @subpackage tree
 */
class Less_Tree_Value extends Less_Tree{

	public $type = 'Value';
	public $value;

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

	function accept($visitor) {
		$this->value = $visitor->visitArray($this->value);
	}

	public function compile($env){

		$ret = array();
		$i = 0;
		foreach($this->value as $i => $v){
			$ret[] = $v->compile($env);
		}
		if( $i > 0 ){
			return new Less_Tree_Value($ret);
		}
		return $ret[0];
	}

    /**
     * @see Less_Tree::genCSS
     */
	function genCSS( $output ){
		$len = count($this->value);
		for($i = 0; $i < $len; $i++ ){
			$this->value[$i]->genCSS( $output );
			if( $i+1 < $len ){
				$output->add( Less_Environment::$_outputMap[','] );
			}
		}
	}

}
 

/**
 * Variable
 *
 * @package Less
 * @subpackage tree
 */
class Less_Tree_Variable extends Less_Tree{

	public $name;
	public $index;
	public $currentFileInfo;
	public $evaluating = false;
	public $type = 'Variable';
	public $parensInOp ;

    /**
     * @param string $name
     */
    public function __construct($name, $index = null, $currentFileInfo = null) {
        $this->name = $name;
        $this->index = $index;
		$this->currentFileInfo = $currentFileInfo;
    }

	public function compile($env) {

		if( $this->name[1] === '@' ){
			$v = new Less_Tree_Variable(substr($this->name, 1), $this->index + 1);
			$name = '@' . $v->compile($env)->value;
		}else{
			$name = $this->name;
		}

		if ($this->evaluating) {
			throw new Less_Exception_Compiler("Recursive variable definition for " . $name, null, $this->index, $this->currentFileInfo);
		}

		$this->evaluating = true;

		foreach($env->frames as $frame){
			if( $v = $frame->variable($name) ){
				$this->evaluating = false;
				return $v->value->compile($env);
			}
		}

		throw new Less_Exception_Compiler("variable " . $name . " is undefined", null, $this->index );
	}

}
 


class Less_Tree_Mixin_Call extends Less_Tree{

	public $selector;
	public $arguments;
	public $index;
	public $currentFileInfo;

	public $important;
	public $type = 'MixinCall';

	/**
	 * less.js: tree.mixin.Call
	 *
	 */
	public function __construct($elements, $args, $index, $currentFileInfo, $important = false){
		$this->selector = new Less_Tree_Selector($elements);
		$this->arguments = $args;
		$this->index = $index;
		$this->currentFileInfo = $currentFileInfo;
		$this->important = $important;
	}

	//function accept($visitor){
	//	$this->selector = $visitor->visit($this->selector);
	//	$this->arguments = $visitor->visit($this->arguments);
	//}


	public function compile($env){

		$rules = array();
		$match = false;
		$isOneFound = false;
		$candidates = array();
		$defaultUsed = false;
		$conditionResult = array();

		$args = array();
		foreach($this->arguments as $a){
			$args[] = array('name'=> $a['name'], 'value' => $a['value']->compile($env) );
		}

		foreach($env->frames as $frame){

			$mixins = $frame->find($this->selector);

			if( !$mixins ){
				continue;
			}

			$isOneFound = true;
			$defNone = 0;
			$defTrue = 1;
			$defFalse = 2;

			// To make `default()` function independent of definition order we have two "subpasses" here.
			// At first we evaluate each guard *twice* (with `default() == true` and `default() == false`),
			// and build candidate list with corresponding flags. Then, when we know all possible matches,
			// we make a final decision.

			$mixins_len = count($mixins);
			for( $m = 0; $m < $mixins_len; $m++ ){
				$mixin = $mixins[$m];

				if( $this->IsRecursive( $env, $mixin ) ){
					continue;
				}

				if( $mixin->matchArgs($args, $env) ){

					$candidate = array('mixin' => $mixin, 'group' => $defNone);

					if( $mixin instanceof Less_Tree_Ruleset ){

						for( $f = 0; $f < 2; $f++ ){
							Less_Tree_DefaultFunc::value($f);
							$conditionResult[$f] = $mixin->matchCondition( $args, $env);
						}
						if( $conditionResult[0] || $conditionResult[1] ){
							if( $conditionResult[0] != $conditionResult[1] ){
								$candidate['group'] = $conditionResult[1] ? $defTrue : $defFalse;
							}

							$candidates[] = $candidate;
						}
					}else{
						$candidates[] = $candidate;
					}

					$match = true;
				}
			}

			Less_Tree_DefaultFunc::reset();


			$count = array(0, 0, 0);
			for( $m = 0; $m < count($candidates); $m++ ){
				$count[ $candidates[$m]['group'] ]++;
			}

			if( $count[$defNone] > 0 ){
				$defaultResult = $defFalse;
			} else {
				$defaultResult = $defTrue;
				if( ($count[$defTrue] + $count[$defFalse]) > 1 ){
					throw Exception( 'Ambiguous use of `default()` found when matching for `'. $this->format($args) + '`' );
				}
			}


			$candidates_length = count($candidates);
			$length_1 = ($candidates_length == 1);

			for( $m = 0; $m < $candidates_length; $m++){
				$candidate = $candidates[$m]['group'];
				if( ($candidate === $defNone) || ($candidate === $defaultResult) ){
					try{
						$mixin = $candidates[$m]['mixin'];
						if( !($mixin instanceof Less_Tree_Mixin_Definition) ){
							$mixin = new Less_Tree_Mixin_Definition('', array(), $mixin->rules, null, false);
							$mixin->originalRuleset = $mixins[$m]->originalRuleset;
						}
						$rules = array_merge($rules, $mixin->evalCall($env, $args, $this->important)->rules);
					} catch (Exception $e) {
						//throw new Less_Exception_Compiler($e->getMessage(), $e->index, null, $this->currentFileInfo['filename']);
						throw new Less_Exception_Compiler($e->getMessage(), null, null, $this->currentFileInfo);
					}
				}
			}

			if( $match ){
				if( !$this->currentFileInfo || !isset($this->currentFileInfo['reference']) || !$this->currentFileInfo['reference'] ){
					Less_Tree::ReferencedArray($rules);
				}

				return $rules;
			}
		}

		if( $isOneFound ){
			throw new Less_Exception_Compiler('No matching definition was found for `'.$this->Format( $args ).'`', null, $this->index, $this->currentFileInfo);

		}else{
			throw new Less_Exception_Compiler(trim($this->selector->toCSS()) . " is undefined", null, $this->index);
		}

	}

	/**
	 * Format the args for use in exception messages
	 *
	 */
	private function Format($args){
		$message = array();
		if( $args ){
			foreach($args as $a){
				$argValue = '';
				if( $a['name'] ){
					$argValue += $a['name']+':';
				}
				if( is_object($a['value']) ){
					$argValue += $a['value']->toCSS();
				}else{
					$argValue += '???';
				}
				$message[] = $argValue;
			}
		}
		return implode(', ',$message);
	}


	/**
	 * Are we in a recursive mixin call?
	 *
	 * @return bool
	 */
	private function IsRecursive( $env, $mixin ){

		foreach($env->frames as $recur_frame){
			if( !($mixin instanceof Less_Tree_Mixin_Definition) ){

				if( $mixin === $recur_frame ){
					return true;
				}

				if( isset($recur_frame->originalRuleset) && $mixin->ruleset_id === $recur_frame->originalRuleset ){
					return true;
				}
			}
		}

		return false;
	}

}


 

class Less_Tree_Mixin_Definition extends Less_Tree_Ruleset{
	public $name;
	public $selectors;
	public $params;
	public $arity		= 0;
	public $rules;
	public $lookups		= array();
	public $required	= 0;
	public $frames		= array();
	public $condition;
	public $variadic;
	public $type		= 'MixinDefinition';


	// less.js : /lib/less/tree/mixin.js : tree.mixin.Definition
	public function __construct($name, $params, $rules, $condition, $variadic = false, $frames = null ){
		$this->name = $name;
		$this->selectors = array(new Less_Tree_Selector(array( new Less_Tree_Element(null, $name))));

		$this->params = $params;
		$this->condition = $condition;
		$this->variadic = $variadic;
		$this->rules = $rules;

		if( $params ){
			$this->arity = count($params);
			foreach( $params as $p ){
				if (! isset($p['name']) || ($p['name'] && !isset($p['value']))) {
					$this->required++;
				}
			}
		}

		$this->frames = $frames;
		$this->SetRulesetIndex();
	}



	//function accept( $visitor ){
	//	$this->params = $visitor->visit($this->params);
	//	$this->rules = $visitor->visit($this->rules);
	//	$this->condition = $visitor->visit($this->condition);
	//}


	public function toCSS(){
		return '';
	}

	// less.js : /lib/less/tree/mixin.js : tree.mixin.Definition.evalParams
	public function compileParams($env, $mixinFrames, $args = array() , &$evaldArguments = array() ){
		$frame = new Less_Tree_Ruleset(null, array());
		$params = $this->params;
		$mixinEnv = null;
		$argsLength = 0;

		if( $args ){
			$argsLength = count($args);
			for($i = 0; $i < $argsLength; $i++ ){
				$arg = $args[$i];

				if( $arg && $arg['name'] ){
					$isNamedFound = false;

					foreach($params as $j => $param){
						if( !isset($evaldArguments[$j]) && $arg['name'] === $params[$j]['name']) {
							$evaldArguments[$j] = $arg['value']->compile($env);
							array_unshift($frame->rules, new Less_Tree_Rule( $arg['name'], $arg['value']->compile($env) ) );
							$isNamedFound = true;
							break;
						}
					}
					if ($isNamedFound) {
						array_splice($args, $i, 1);
						$i--;
						$argsLength--;
						continue;
					} else {
						throw new Less_Exception_Compiler("Named argument for " . $this->name .' '.$args[$i]['name'] . ' not found');
					}
				}
			}
		}

		$argIndex = 0;
		foreach($params as $i => $param){

			if ( isset($evaldArguments[$i]) ){ continue; }

			$arg = null;
			if( isset($args[$argIndex]) ){
				$arg = $args[$argIndex];
			}

			if (isset($param['name']) && $param['name']) {

				if( isset($param['variadic']) ){
					$varargs = array();
					for ($j = $argIndex; $j < $argsLength; $j++) {
						$varargs[] = $args[$j]['value']->compile($env);
					}
					$expression = new Less_Tree_Expression($varargs);
					array_unshift($frame->rules, new Less_Tree_Rule($param['name'], $expression->compile($env)));
				}else{
					$val = ($arg && $arg['value']) ? $arg['value'] : false;

					if ($val) {
						$val = $val->compile($env);
					} else if ( isset($param['value']) ) {

						if( !$mixinEnv ){
							$mixinEnv = new Less_Environment();
							$mixinEnv->frames = array_merge( array($frame), $mixinFrames);
						}

						$val = $param['value']->compile($mixinEnv);
						$frame->resetCache();
					} else {
						throw new Less_Exception_Compiler("Wrong number of arguments for " . $this->name . " (" . $argsLength . ' for ' . $this->arity . ")");
					}

					array_unshift($frame->rules, new Less_Tree_Rule($param['name'], $val));
					$evaldArguments[$i] = $val;
				}
			}

			if ( isset($param['variadic']) && $args) {
				for ($j = $argIndex; $j < $argsLength; $j++) {
					$evaldArguments[$j] = $args[$j]['value']->compile($env);
				}
			}
			$argIndex++;
		}

		ksort($evaldArguments);
		$evaldArguments = array_values($evaldArguments);

		return $frame;
	}

	public function compile($env) {
		if( $this->frames ){
			return new Less_Tree_Mixin_Definition($this->name, $this->params, $this->rules, $this->condition, $this->variadic, $this->frames );
		}
		return new Less_Tree_Mixin_Definition($this->name, $this->params, $this->rules, $this->condition, $this->variadic, $env->frames );
	}

	public function evalCall($env, $args = NULL, $important = NULL) {

		Less_Environment::$mixin_stack++;

		$_arguments = array();

		if( $this->frames ){
			$mixinFrames = array_merge($this->frames, $env->frames);
		}else{
			$mixinFrames = $env->frames;
		}

		$frame = $this->compileParams($env, $mixinFrames, $args, $_arguments);

		$ex = new Less_Tree_Expression($_arguments);
		array_unshift($frame->rules, new Less_Tree_Rule('@arguments', $ex->compile($env)));


		$ruleset = new Less_Tree_Ruleset(null, $this->rules);
		$ruleset->originalRuleset = $this->ruleset_id;


		$ruleSetEnv = new Less_Environment();
		$ruleSetEnv->frames = array_merge( array($this, $frame), $mixinFrames );
		$ruleset = $ruleset->compile( $ruleSetEnv );

		if( $important ){
			$ruleset = $ruleset->makeImportant();
		}

		Less_Environment::$mixin_stack--;

		return $ruleset;
	}


	public function matchCondition($args, $env) {

		if( !$this->condition ){
			return true;
		}

		$frame = $this->compileParams($env, array_merge($this->frames,$env->frames), $args );

		$compile_env = new Less_Environment();
		$compile_env->frames = array_merge(
				array($frame)		// the parameter variables
				, $this->frames		// the parent namespace/mixin frames
				, $env->frames		// the current environment frames
			);

		return (bool)$this->condition->compile($compile_env);
	}

	public function matchArgs($args, $env = NULL){
		$argsLength = count($args);

		if( !$this->variadic ){
			if( $argsLength < $this->required ){
				return false;
			}
			if( $argsLength > count($this->params) ){
				return false;
			}
		}else{
			if( $argsLength < ($this->required - 1)){
				return false;
			}
		}

		$len = min($argsLength, $this->arity);

		for( $i = 0; $i < $len; $i++ ){
			if( !isset($this->params[$i]['name']) && !isset($this->params[$i]['variadic']) ){
				if( $args[$i]['value']->compile($env)->toCSS() != $this->params[$i]['value']->compile($env)->toCSS() ){
					return false;
				}
			}
		}

		return true;
	}

}
 

/**
 * Extend Finder Visitor
 *
 * @package Less
 * @subpackage visitor
 */
class Less_Visitor_extendFinder extends Less_Visitor{

	public $contexts = array();
	public $allExtendsStack;
	public $foundExtends;

	function __construct(){
		$this->contexts = array();
		$this->allExtendsStack = array(array());
		parent::__construct();
	}

	/**
	 * @param Less_Tree_Ruleset $root
	 */
	function run($root){
		$root = $this->visitObj($root);
		$root->allExtends =& $this->allExtendsStack[0];
		return $root;
	}

	function visitRule($ruleNode, &$visitDeeper ){
		$visitDeeper = false;
	}

	function visitMixinDefinition( $mixinDefinitionNode, &$visitDeeper ){
		$visitDeeper = false;
	}

	function visitRuleset($rulesetNode){

		if( $rulesetNode->root ){
			return;
		}

		$allSelectorsExtendList = array();

		// get &:extend(.a); rules which apply to all selectors in this ruleset
		if( $rulesetNode->rules ){
			foreach($rulesetNode->rules as $rule){
				if( $rule instanceof Less_Tree_Extend ){
					$allSelectorsExtendList[] = $rule;
					$rulesetNode->extendOnEveryPath = true;
				}
			}
		}


		// now find every selector and apply the extends that apply to all extends
		// and the ones which apply to an individual extend
		foreach($rulesetNode->paths as $selectorPath){
			$selector = end($selectorPath); //$selectorPath[ count($selectorPath)-1];

			$j = 0;
			foreach($selector->extendList as $extend){
				$this->allExtendsStackPush($rulesetNode, $selectorPath, $extend, $j);
			}
			foreach($allSelectorsExtendList as $extend){
				$this->allExtendsStackPush($rulesetNode, $selectorPath, $extend, $j);
			}
		}

		$this->contexts[] = $rulesetNode->selectors;
	}

	function allExtendsStackPush($rulesetNode, $selectorPath, $extend, &$j){
		$this->foundExtends = true;
		$extend = clone $extend;
		$extend->findSelfSelectors( $selectorPath );
		$extend->ruleset = $rulesetNode;
		if( $j === 0 ){
			$extend->firstExtendOnThisSelectorPath = true;
		}

		$end_key = count($this->allExtendsStack)-1;
		$this->allExtendsStack[$end_key][] = $extend;
		$j++;
	}


	function visitRulesetOut( $rulesetNode ){
		if( !is_object($rulesetNode) || !$rulesetNode->root ){
			array_pop($this->contexts);
		}
	}

	function visitMedia( $mediaNode ){
		$mediaNode->allExtends = array();
		$this->allExtendsStack[] =& $mediaNode->allExtends;
	}

	function visitMediaOut(){
		array_pop($this->allExtendsStack);
	}

	function visitDirective( $directiveNode ){
		$directiveNode->allExtends = array();
		$this->allExtendsStack[] =& $directiveNode->allExtends;
	}

	function visitDirectiveOut(){
		array_pop($this->allExtendsStack);
	}
}


 

/*
class Less_Visitor_import extends Less_VisitorReplacing{

	public $_visitor;
	public $_importer;
	public $importCount;

	function __construct( $evalEnv ){
		$this->env = $evalEnv;
		$this->importCount = 0;
		parent::__construct();
	}


	function run( $root ){
		$root = $this->visitObj($root);
		$this->isFinished = true;

		//if( $this->importCount === 0) {
		//	$this->_finish();
		//}
	}

	function visitImport($importNode, &$visitDeeper ){
		$importVisitor = $this;
		$inlineCSS = $importNode->options['inline'];

		if( !$importNode->css || $inlineCSS ){
			$evaldImportNode = $importNode->compileForImport($this->env);

			if( $evaldImportNode && (!$evaldImportNode->css || $inlineCSS) ){
				$importNode = $evaldImportNode;
				$this->importCount++;
				$env = clone $this->env;

				if( (isset($importNode->options['multiple']) && $importNode->options['multiple']) ){
					$env->importMultiple = true;
				}

				//get path & uri
				$path_and_uri = null;
				if( is_callable(Less_Parser::$options['import_callback']) ){
					$path_and_uri = call_user_func(Less_Parser::$options['import_callback'],$importNode);
				}

				if( !$path_and_uri ){
					$path_and_uri = $importNode->PathAndUri();
				}

				if( $path_and_uri ){
					list($full_path, $uri) = $path_and_uri;
				}else{
					$full_path = $uri = $importNode->getPath();
				}


				//import once
				if( $importNode->skip( $full_path, $env) ){
					return array();
				}

				if( $importNode->options['inline'] ){
					//todo needs to reference css file not import
					//$contents = new Less_Tree_Anonymous($importNode->root, 0, array('filename'=>$importNode->importedFilename), true );

					Less_Parser::AddParsedFile($full_path);
					$contents = new Less_Tree_Anonymous( file_get_contents($full_path), 0, array(), true );

					if( $importNode->features ){
						return new Less_Tree_Media( array($contents), $importNode->features->value );
					}

					return array( $contents );
				}


				// css ?
				if( $importNode->css ){
					$features = ( $importNode->features ? $importNode->features->compile($env) : null );
					return new Less_Tree_Import( $importNode->compilePath( $env), $features, $importNode->options, $this->index);
				}

				return $importNode->ParseImport( $full_path, $uri, $env );
			}

		}

		$visitDeeper = false;
		return $importNode;
	}


	function visitRule( $ruleNode, &$visitDeeper ){
		$visitDeeper = false;
		return $ruleNode;
	}

	function visitDirective($directiveNode, $visitArgs){
		array_unshift($this->env->frames,$directiveNode);
		return $directiveNode;
	}

	function visitDirectiveOut($directiveNode) {
		array_shift($this->env->frames);
	}

	function visitMixinDefinition($mixinDefinitionNode, $visitArgs) {
		array_unshift($this->env->frames,$mixinDefinitionNode);
		return $mixinDefinitionNode;
	}

	function visitMixinDefinitionOut($mixinDefinitionNode) {
		array_shift($this->env->frames);
	}

	function visitRuleset($rulesetNode, $visitArgs) {
		array_unshift($this->env->frames,$rulesetNode);
		return $rulesetNode;
	}

	function visitRulesetOut($rulesetNode) {
		array_shift($this->env->frames);
	}

	function visitMedia($mediaNode, $visitArgs) {
		array_unshift($this->env->frames, $mediaNode->ruleset);
		return $mediaNode;
	}

	function visitMediaOut($mediaNode) {
		array_shift($this->env->frames);
	}

}
*/


 

/**
 * Join Selector Visitor
 *
 * @package Less
 * @subpackage visitor
 */
class Less_Visitor_joinSelector extends Less_Visitor{

	public $contexts = array( array() );

	/**
	 * @param Less_Tree_Ruleset $root
	 */
	function run( $root ){
		return $this->visitObj($root);
	}

	function visitRule( $ruleNode, &$visitDeeper ){
		$visitDeeper = false;
	}

	function visitMixinDefinition( $mixinDefinitionNode, &$visitDeeper ){
		$visitDeeper = false;
	}

	function visitRuleset( $rulesetNode ){

		$paths = array();

		if( !$rulesetNode->root ){
			$selectors = array();

			if( $rulesetNode->selectors && $rulesetNode->selectors ){
				foreach($rulesetNode->selectors as $selector){
					if( $selector->getIsOutput() ){
						$selectors[] = $selector;
					}
				}
			}

			if( !$selectors ){
				$rulesetNode->selectors = null;
				$rulesetNode->rules = null;
			}else{
				$context = end($this->contexts); //$context = $this->contexts[ count($this->contexts) - 1];
				$paths = $rulesetNode->joinSelectors( $context, $selectors);
			}

			$rulesetNode->paths = $paths;
		}

		$this->contexts[] = $paths; //different from less.js. Placed after joinSelectors() so that $this->contexts will get correct $paths
	}

	function visitRulesetOut(){
		array_pop($this->contexts);
	}

	function visitMedia($mediaNode) {
		$context = end($this->contexts); //$context = $this->contexts[ count($this->contexts) - 1];

		if( !count($context) || (is_object($context[0]) && $context[0]->multiMedia) ){
			$mediaNode->rules[0]->root = true;
		}
	}

}

 

/**
 * Process Extends Visitor
 *
 * @package Less
 * @subpackage visitor
 */
class Less_Visitor_processExtends extends Less_Visitor{

	public $allExtendsStack;

	/**
	 * @param Less_Tree_Ruleset $root
	 */
	public function run( $root ){
		$extendFinder = new Less_Visitor_extendFinder();
		$extendFinder->run( $root );
		if( !$extendFinder->foundExtends){
			return $root;
		}

		$root->allExtends = $this->doExtendChaining( $root->allExtends, $root->allExtends);

		$this->allExtendsStack = array();
		$this->allExtendsStack[] = &$root->allExtends;

		return $this->visitObj( $root );
	}

	private function doExtendChaining( $extendsList, $extendsListTarget, $iterationCount = 0){
		//
		// chaining is different from normal extension.. if we extend an extend then we are not just copying, altering and pasting
		// the selector we would do normally, but we are also adding an extend with the same target selector
		// this means this new extend can then go and alter other extends
		//
		// this method deals with all the chaining work - without it, extend is flat and doesn't work on other extend selectors
		// this is also the most expensive.. and a match on one selector can cause an extension of a selector we had already processed if
		// we look at each selector at a time, as is done in visitRuleset

		$extendsToAdd = array();


		//loop through comparing every extend with every target extend.
		// a target extend is the one on the ruleset we are looking at copy/edit/pasting in place
		// e.g. .a:extend(.b) {} and .b:extend(.c) {} then the first extend extends the second one
		// and the second is the target.
		// the seperation into two lists allows us to process a subset of chains with a bigger set, as is the
		// case when processing media queries
		for( $extendIndex = 0, $extendsList_len = count($extendsList); $extendIndex < $extendsList_len; $extendIndex++ ){
			for( $targetExtendIndex = 0; $targetExtendIndex < count($extendsListTarget); $targetExtendIndex++ ){

				$extend = $extendsList[$extendIndex];
				$targetExtend = $extendsListTarget[$targetExtendIndex];

				// look for circular references
				if( in_array($targetExtend->object_id, $extend->parent_ids,true) ){
					continue;
				}

				// find a match in the target extends self selector (the bit before :extend)
				$selectorPath = array( $targetExtend->selfSelectors[0] );
				$matches = $this->findMatch( $extend, $selectorPath);


				if( $matches ){

					// we found a match, so for each self selector..
					foreach($extend->selfSelectors as $selfSelector ){


						// process the extend as usual
						$newSelector = $this->extendSelector( $matches, $selectorPath, $selfSelector);

						// but now we create a new extend from it
						$newExtend = new Less_Tree_Extend( $targetExtend->selector, $targetExtend->option, 0);
						$newExtend->selfSelectors = $newSelector;

						// add the extend onto the list of extends for that selector
						end($newSelector)->extendList = array($newExtend);
						//$newSelector[ count($newSelector)-1]->extendList = array($newExtend);

						// record that we need to add it.
						$extendsToAdd[] = $newExtend;
						$newExtend->ruleset = $targetExtend->ruleset;

						//remember its parents for circular references
						$newExtend->parent_ids = array_merge($newExtend->parent_ids,$targetExtend->parent_ids,$extend->parent_ids);

						// only process the selector once.. if we have :extend(.a,.b) then multiple
						// extends will look at the same selector path, so when extending
						// we know that any others will be duplicates in terms of what is added to the css
						if( $targetExtend->firstExtendOnThisSelectorPath ){
							$newExtend->firstExtendOnThisSelectorPath = true;
							$targetExtend->ruleset->paths[] = $newSelector;
						}
					}
				}
			}
		}

		if( $extendsToAdd ){
			// try to detect circular references to stop a stack overflow.
			// may no longer be needed.			$this->extendChainCount++;
			if( $iterationCount > 100) {

				try{
					$selectorOne = $extendsToAdd[0]->selfSelectors[0]->toCSS();
					$selectorTwo = $extendsToAdd[0]->selector->toCSS();
				}catch(Exception $e){
					$selectorOne = "{unable to calculate}";
					$selectorTwo = "{unable to calculate}";
				}

				throw new Less_Exception_Parser("extend circular reference detected. One of the circular extends is currently:"+$selectorOne+":extend(" + $selectorTwo+")");
			}

			// now process the new extends on the existing rules so that we can handle a extending b extending c ectending d extending e...
			$extendsToAdd = $this->doExtendChaining( $extendsToAdd, $extendsListTarget, $iterationCount+1);
		}

		return array_merge($extendsList, $extendsToAdd);
	}


	protected function visitRule( $ruleNode, &$visitDeeper ){
		$visitDeeper = false;
	}

	protected function visitMixinDefinition( $mixinDefinitionNode, &$visitDeeper ){
		$visitDeeper = false;
	}

	protected function visitSelector( $selectorNode, &$visitDeeper ){
		$visitDeeper = false;
	}

	protected function visitRuleset($rulesetNode){


		if( $rulesetNode->root ){
			return;
		}

		$allExtends	= end($this->allExtendsStack);
		$paths_len = count($rulesetNode->paths);

		// look at each selector path in the ruleset, find any extend matches and then copy, find and replace
		foreach($allExtends as $allExtend){
			for($pathIndex = 0; $pathIndex < $paths_len; $pathIndex++ ){

				// extending extends happens initially, before the main pass
				if( isset($rulesetNode->extendOnEveryPath) && $rulesetNode->extendOnEveryPath ){
					continue;
				}

				$selectorPath = $rulesetNode->paths[$pathIndex];

				if( end($selectorPath)->extendList ){
					continue;
				}

				$this->ExtendMatch( $rulesetNode, $allExtend, $selectorPath);

			}
		}
	}


	private function ExtendMatch( $rulesetNode, $extend, $selectorPath ){
		$matches = $this->findMatch($extend, $selectorPath);

		if( $matches ){
			foreach($extend->selfSelectors as $selfSelector ){
				$rulesetNode->paths[] = $this->extendSelector($matches, $selectorPath, $selfSelector);
			}
		}
	}



	private function findMatch($extend, $haystackSelectorPath ){


		if( !$this->HasMatches($extend, $haystackSelectorPath) ){
			return false;
		}


		//
		// look through the haystack selector path to try and find the needle - extend.selector
		// returns an array of selector matches that can then be replaced
		//
		$needleElements = $extend->selector->elements;
		$potentialMatches = array();
		$potentialMatches_len = 0;
		$potentialMatch = null;
		$matches = array();



		// loop through the haystack elements
		$haystack_path_len = count($haystackSelectorPath);
		for($haystackSelectorIndex = 0; $haystackSelectorIndex < $haystack_path_len; $haystackSelectorIndex++ ){
			$hackstackSelector = $haystackSelectorPath[$haystackSelectorIndex];

			$haystack_elements_len = count($hackstackSelector->elements);
			for($hackstackElementIndex = 0; $hackstackElementIndex < $haystack_elements_len; $hackstackElementIndex++ ){

				$haystackElement = $hackstackSelector->elements[$hackstackElementIndex];

				// if we allow elements before our match we can add a potential match every time. otherwise only at the first element.
				if( $extend->allowBefore || ($haystackSelectorIndex === 0 && $hackstackElementIndex === 0) ){
					$potentialMatches[] = array('pathIndex'=> $haystackSelectorIndex, 'index'=> $hackstackElementIndex, 'matched'=> 0, 'initialCombinator'=> $haystackElement->combinator);
					$potentialMatches_len++;
				}

				for($i = 0; $i < $potentialMatches_len; $i++ ){

					$potentialMatch = &$potentialMatches[$i];
					$potentialMatch = $this->PotentialMatch( $potentialMatch, $needleElements, $haystackElement, $hackstackElementIndex );


					// if we are still valid and have finished, test whether we have elements after and whether these are allowed
					if( $potentialMatch && $potentialMatch['matched'] === $extend->selector->elements_len ){
						$potentialMatch['finished'] = true;

						if( !$extend->allowAfter && ($hackstackElementIndex+1 < $haystack_elements_len || $haystackSelectorIndex+1 < $haystack_path_len) ){
							$potentialMatch = null;
						}
					}

					// if null we remove, if not, we are still valid, so either push as a valid match or continue
					if( $potentialMatch ){
						if( $potentialMatch['finished'] ){
							$potentialMatch['length'] = $extend->selector->elements_len;
							$potentialMatch['endPathIndex'] = $haystackSelectorIndex;
							$potentialMatch['endPathElementIndex'] = $hackstackElementIndex + 1; // index after end of match
							$potentialMatches = array(); // we don't allow matches to overlap, so start matching again
							$potentialMatches_len = 0;
							$matches[] = $potentialMatch;
						}
						continue;
					}

					array_splice($potentialMatches, $i, 1);
					$potentialMatches_len--;
					$i--;
				}
			}
		}

		return $matches;
	}


	// Before going through all the nested loops, lets check to see if a match is possible
	// Reduces Bootstrap 3.1 compile time from ~6.5s to ~5.6s
	private function HasMatches($extend, $haystackSelectorPath){

		if( !$extend->selector->cacheable ){
			return true;
		}

		$first_el = $extend->selector->_oelements[0];

		foreach($haystackSelectorPath as $hackstackSelector){
			if( !$hackstackSelector->cacheable ){
				return true;
			}

			if( in_array($first_el, $hackstackSelector->_oelements) ){
				return true;
			}
		}

		return false;
	}


	/**
	 * @param integer $hackstackElementIndex
	 */
	private function PotentialMatch( $potentialMatch, $needleElements, $haystackElement, $hackstackElementIndex ){


		if( $potentialMatch['matched'] > 0 ){

			// selectors add " " onto the first element. When we use & it joins the selectors together, but if we don't
			// then each selector in haystackSelectorPath has a space before it added in the toCSS phase. so we need to work out
			// what the resulting combinator will be
			$targetCombinator = $haystackElement->combinator;
			if( $targetCombinator === '' && $hackstackElementIndex === 0 ){
				$targetCombinator = ' ';
			}

			if( $needleElements[ $potentialMatch['matched'] ]->combinator !== $targetCombinator ){
				return null;
			}
		}

		// if we don't match, null our match to indicate failure
		if( !$this->isElementValuesEqual( $needleElements[$potentialMatch['matched'] ]->value, $haystackElement->value) ){
			return null;
		}

		$potentialMatch['finished'] = false;
		$potentialMatch['matched']++;

		return $potentialMatch;
	}


	private function isElementValuesEqual( $elementValue1, $elementValue2 ){

		if( $elementValue1 === $elementValue2 ){
			return true;
		}

		if( is_string($elementValue1) || is_string($elementValue2) ) {
			return false;
		}

		if( $elementValue1 instanceof Less_Tree_Attribute ){
			return $this->isAttributeValuesEqual( $elementValue1, $elementValue2 );
		}

		$elementValue1 = $elementValue1->value;
		if( $elementValue1 instanceof Less_Tree_Selector ){
			return $this->isSelectorValuesEqual( $elementValue1, $elementValue2 );
		}

		return false;
	}


	/**
	 * @param Less_Tree_Selector $elementValue1
	 */
	private function isSelectorValuesEqual( $elementValue1, $elementValue2 ){

		$elementValue2 = $elementValue2->value;
		if( !($elementValue2 instanceof Less_Tree_Selector) || $elementValue1->elements_len !== $elementValue2->elements_len ){
			return false;
		}

		for( $i = 0; $i < $elementValue1->elements_len; $i++ ){

			if( $elementValue1->elements[$i]->combinator !== $elementValue2->elements[$i]->combinator ){
				if( $i !== 0 || ($elementValue1->elements[$i]->combinator || ' ') !== ($elementValue2->elements[$i]->combinator || ' ') ){
					return false;
				}
			}

			if( !$this->isElementValuesEqual($elementValue1->elements[$i]->value, $elementValue2->elements[$i]->value) ){
				return false;
			}
		}

		return true;
	}


	/**
	 * @param Less_Tree_Attribute $elementValue1
	 */
	private function isAttributeValuesEqual( $elementValue1, $elementValue2 ){

		if( $elementValue1->op !== $elementValue2->op || $elementValue1->key !== $elementValue2->key ){
			return false;
		}

		if( !$elementValue1->value || !$elementValue2->value ){
			if( $elementValue1->value || $elementValue2->value ) {
				return false;
			}
			return true;
		}

		$elementValue1 = ($elementValue1->value->value ? $elementValue1->value->value : $elementValue1->value );
		$elementValue2 = ($elementValue2->value->value ? $elementValue2->value->value : $elementValue2->value );

		return $elementValue1 === $elementValue2;
	}


	private function extendSelector($matches, $selectorPath, $replacementSelector){

		//for a set of matches, replace each match with the replacement selector

		$currentSelectorPathIndex = 0;
		$currentSelectorPathElementIndex = 0;
		$path = array();
		$selectorPath_len = count($selectorPath);

		for($matchIndex = 0, $matches_len = count($matches); $matchIndex < $matches_len; $matchIndex++ ){


			$match = $matches[$matchIndex];
			$selector = $selectorPath[ $match['pathIndex'] ];

			$firstElement = new Less_Tree_Element(
				$match['initialCombinator'],
				$replacementSelector->elements[0]->value,
				$replacementSelector->elements[0]->index,
				$replacementSelector->elements[0]->currentFileInfo
			);

			if( $match['pathIndex'] > $currentSelectorPathIndex && $currentSelectorPathElementIndex > 0 ){
				$last_path = end($path);
				$last_path->elements = array_merge( $last_path->elements, array_slice( $selectorPath[$currentSelectorPathIndex]->elements, $currentSelectorPathElementIndex));
				$currentSelectorPathElementIndex = 0;
				$currentSelectorPathIndex++;
			}

			$newElements = array_merge(
				array_slice($selector->elements, $currentSelectorPathElementIndex, ($match['index'] - $currentSelectorPathElementIndex) ) // last parameter of array_slice is different than the last parameter of javascript's slice
				, array($firstElement)
				, array_slice($replacementSelector->elements,1)
				);

			if( $currentSelectorPathIndex === $match['pathIndex'] && $matchIndex > 0 ){
				$last_key = count($path)-1;
				$path[$last_key]->elements = array_merge($path[$last_key]->elements,$newElements);
			}else{
				$path = array_merge( $path, array_slice( $selectorPath, $currentSelectorPathIndex, $match['pathIndex'] ));
				$path[] = new Less_Tree_Selector( $newElements );
			}

			$currentSelectorPathIndex = $match['endPathIndex'];
			$currentSelectorPathElementIndex = $match['endPathElementIndex'];
			if( $currentSelectorPathElementIndex >= count($selectorPath[$currentSelectorPathIndex]->elements) ){
				$currentSelectorPathElementIndex = 0;
				$currentSelectorPathIndex++;
			}
		}

		if( $currentSelectorPathIndex < $selectorPath_len && $currentSelectorPathElementIndex > 0 ){
			$last_path = end($path);
			$last_path->elements = array_merge( $last_path->elements, array_slice($selectorPath[$currentSelectorPathIndex]->elements, $currentSelectorPathElementIndex));
			$currentSelectorPathIndex++;
		}

		$slice_len = $selectorPath_len - $currentSelectorPathIndex;
		$path = array_merge($path, array_slice($selectorPath, $currentSelectorPathIndex, $slice_len));

		return $path;
	}


	protected function visitMedia( $mediaNode ){
		$newAllExtends = array_merge( $mediaNode->allExtends, end($this->allExtendsStack) );
		$this->allExtendsStack[] = $this->doExtendChaining($newAllExtends, $mediaNode->allExtends);
	}

	protected function visitMediaOut(){
		array_pop( $this->allExtendsStack );
	}

	protected function visitDirective( $directiveNode ){
		$newAllExtends = array_merge( $directiveNode->allExtends, end($this->allExtendsStack) );
		$this->allExtendsStack[] = $this->doExtendChaining($newAllExtends, $directiveNode->allExtends);
	}

	protected function visitDirectiveOut(){
		array_pop($this->allExtendsStack);
	}

} 

/**
 * toCSS Visitor
 *
 * @package Less
 * @subpackage visitor
 */
class Less_Visitor_toCSS extends Less_VisitorReplacing{

	private $charset;

	function __construct(){
		parent::__construct();
	}

	/**
	 * @param Less_Tree_Ruleset $root
	 */
	function run( $root ){
		return $this->visitObj($root);
	}

	function visitRule( $ruleNode ){
		if( $ruleNode->variable ){
			return array();
		}
		return $ruleNode;
	}

	function visitMixinDefinition($mixinNode){
		// mixin definitions do not get eval'd - this means they keep state
		// so we have to clear that state here so it isn't used if toCSS is called twice
		$mixinNode->frames = array();
		return array();
	}

	function visitExtend(){
		return array();
	}

	function visitComment( $commentNode ){
		if( $commentNode->isSilent() ){
			return array();
		}
		return $commentNode;
	}

	function visitMedia( $mediaNode, &$visitDeeper ){
		$mediaNode->accept($this);
		$visitDeeper = false;

		if( !$mediaNode->rules ){
			return array();
		}
		return $mediaNode;
	}

	function visitDirective( $directiveNode ){
		if( isset($directiveNode->currentFileInfo['reference']) && (!property_exists($directiveNode,'isReferenced') || !$directiveNode->isReferenced) ){
			return array();
		}
		if( $directiveNode->name === '@charset' ){
			// Only output the debug info together with subsequent @charset definitions
			// a comment (or @media statement) before the actual @charset directive would
			// be considered illegal css as it has to be on the first line
			if( isset($this->charset) && $this->charset ){

				//if( $directiveNode->debugInfo ){
				//	$comment = new Less_Tree_Comment('/* ' . str_replace("\n",'',$directiveNode->toCSS())." */\n");
				//	$comment->debugInfo = $directiveNode->debugInfo;
				//	return $this->visit($comment);
				//}


				return array();
			}
			$this->charset = true;
		}
		return $directiveNode;
	}

	function checkPropertiesInRoot( $rulesetNode ){

		if( !$rulesetNode->firstRoot ){
			return;
		}

		foreach($rulesetNode->rules as $ruleNode){
			if( $ruleNode instanceof Less_Tree_Rule && !$ruleNode->variable ){
				$msg = "properties must be inside selector blocks, they cannot be in the root. Index ".$ruleNode->index.($ruleNode->currentFileInfo ? (' Filename: '.$ruleNode->currentFileInfo['filename']) : null);
				throw new Less_Exception_Compiler($msg);
			}
		}
	}


	function visitRuleset( $rulesetNode, &$visitDeeper ){

		$visitDeeper = false;

		$this->checkPropertiesInRoot( $rulesetNode );

		if( $rulesetNode->root ){
			return $this->visitRulesetRoot( $rulesetNode );
		}

		$rulesets = array();
		$rulesetNode->paths = $this->visitRulesetPaths($rulesetNode);

		// by pass error; debug later - KHANH
		if (!$rulesetNode->rules) return $rulesets;
		//;

		// Compile rules and rulesets
		$nodeRuleCnt = count($rulesetNode->rules);
		for( $i = 0; $i < $nodeRuleCnt; ){
			$rule = $rulesetNode->rules[$i];

			if( property_exists($rule,'rules') ){
				// visit because we are moving them out from being a child
				$rulesets[] = $this->visitObj($rule);
				array_splice($rulesetNode->rules,$i,1);
				$nodeRuleCnt--;
				continue;
			}
			$i++;
		}


		// accept the visitor to remove rules and refactor itself
		// then we can decide now whether we want it or not
		if( $nodeRuleCnt > 0 ){
			$rulesetNode->accept($this);

			if( $rulesetNode->rules ){

				if( count($rulesetNode->rules) >  1 ){
					$this->_mergeRules( $rulesetNode->rules );
					$this->_removeDuplicateRules( $rulesetNode->rules );
				}

				// now decide whether we keep the ruleset
				if( $rulesetNode->paths ){
					//array_unshift($rulesets, $rulesetNode);
					array_splice($rulesets,0,0,array($rulesetNode));
				}
			}

		}


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


	/**
	 * Helper function for visitiRuleset
	 *
	 * return array|Less_Tree_Ruleset
	 */
	private function visitRulesetRoot( $rulesetNode ){
		$rulesetNode->accept( $this );
		if( $rulesetNode->firstRoot || $rulesetNode->rules ){
			return $rulesetNode;
		}
		return array();
	}


	/**
	 * Helper function for visitRuleset()
	 *
	 * @return array
	 */
	private function visitRulesetPaths($rulesetNode){

		$paths = array();
		foreach($rulesetNode->paths as $p){
			if( $p[0]->elements[0]->combinator === ' ' ){
				$p[0]->elements[0]->combinator = '';
			}

			foreach($p as $pi){
				if( $pi->getIsReferenced() && $pi->getIsOutput() ){
					$paths[] = $p;
					break;
				}
			}
		}

		return $paths;
	}

	function _removeDuplicateRules( &$rules ){
		// remove duplicates
		$ruleCache = array();
		for( $i = count($rules)-1; $i >= 0 ; $i-- ){
			$rule = $rules[$i];
			if( $rule instanceof Less_Tree_Rule || $rule instanceof Less_Tree_NameValue ){

				if( !isset($ruleCache[$rule->name]) ){
					$ruleCache[$rule->name] = $rule;
				}else{
					$ruleList =& $ruleCache[$rule->name];

					if( $ruleList instanceof Less_Tree_Rule || $ruleList instanceof Less_Tree_NameValue ){
						$ruleList = $ruleCache[$rule->name] = array( $ruleCache[$rule->name]->toCSS() );
					}

					$ruleCSS = $rule->toCSS();
					if( array_search($ruleCSS,$ruleList) !== false ){
						array_splice($rules,$i,1);
					}else{
						$ruleList[] = $ruleCSS;
					}
				}
			}
		}
	}

	function _mergeRules( &$rules ){
		$groups = array();

		//obj($rules);

		$rules_len = count($rules);
		for( $i = 0; $i < $rules_len; $i++ ){
			$rule = $rules[$i];

			if( ($rule instanceof Less_Tree_Rule) && $rule->merge ){

				$key = $rule->name;
				if( $rule->important ){
					$key .= ',!';
				}

				if( !isset($groups[$key]) ){
					$groups[$key] = array();
				}else{
					array_splice($rules, $i--, 1);
					$rules_len--;
				}

				$groups[$key][] = $rule;
			}
		}


		foreach($groups as $parts){

			if( count($parts) > 1 ){
				$rule = $parts[0];
				$spacedGroups = array();
				$lastSpacedGroup = array();
				$parts_mapped = array();
				foreach($parts as $p){
					if( $p->merge === '+' ){
						if( $lastSpacedGroup ){
							$spacedGroups[] = self::toExpression($lastSpacedGroup);
						}
						$lastSpacedGroup = array();
					}
					$lastSpacedGroup[] = $p;
				}

				$spacedGroups[] = self::toExpression($lastSpacedGroup);
				$rule->value = self::toValue($spacedGroups);
			}
		}

	}

	static function toExpression($values){
		$mapped = array();
		foreach($values as $p){
			$mapped[] = $p->value;
		}
		return new Less_Tree_Expression( $mapped );
	}

	static function toValue($values){
		//return new Less_Tree_Value($values); ??

		$mapped = array();
		foreach($values as $p){
			$mapped[] = $p;
		}
		return new Less_Tree_Value($mapped);
	}
}

 

/**
 * Parser Exception
 *
 * @package Less
 * @subpackage exception
 */
class Less_Exception_Parser extends Exception{

	/**
	 * The current file
	 *
	 * @var Less_ImportedFile
	 */
	public $currentFile;

	/**
	 * The current parser index
	 *
	 * @var integer
	 */
	public $index;

	protected $input;

	protected $details = array();


	/**
	 * Constructor
	 *
	 * @param string $message
	 * @param Exception $previous Previous exception
	 * @param integer $index The current parser index
	 * @param Less_FileInfo|string $currentFile The file
	 * @param integer $code The exception code
	 */
	public function __construct($message = null, Exception $previous = null, $index = null, $currentFile = null, $code = 0){

		if (PHP_VERSION_ID < 50300) {
			$this->previous = $previous;
			parent::__construct($message, $code);
		} else {
			parent::__construct($message, $code, $previous);
		}

		$this->currentFile = $currentFile;
		$this->index = $index;

		$this->genMessage();
	}


	protected function getInput(){

		if( !$this->input && $this->currentFile && $this->currentFile['filename'] ){
			$this->input = file_get_contents( $this->currentFile['filename'] );
		}
	}



	/**
	 * Converts the exception to string
	 *
	 * @return string
	 */
	public function genMessage(){

		if( $this->currentFile && $this->currentFile['filename'] ){
			$this->message .= ' in '.basename($this->currentFile['filename']);
		}

		if( $this->index !== null ){
			$this->getInput();
			if( $this->input ){
				$line = self::getLineNumber();
				$this->message .= ' on line '.$line.', column '.self::getColumn();

				$lines = explode("\n",$this->input);

				$count = count($lines);
				$start_line = max(0, $line-3);
				$last_line = min($count, $start_line+6);
				$num_len = strlen($last_line);
				for( $i = $start_line; $i < $last_line; $i++ ){
					$this->message .= "\n".str_pad($i+1,$num_len,'0',STR_PAD_LEFT).'| '.$lines[$i];
				}
			}
		}

	}

	/**
	 * Returns the line number the error was encountered
	 *
	 * @return integer
	 */
	public function getLineNumber(){
		if( $this->index ){
			return substr_count($this->input, "\n", 0, $this->index) + 1;
		}
		return 1;
	}


	/**
	 * Returns the column the error was encountered
	 *
	 * @return integer
	 */
	public function getColumn(){

		$part = substr($this->input, 0, $this->index);
		$pos = strrpos($part,"\n");
		return $this->index - $pos;
	}

}
 

/**
 * Chunk Exception
 *
 * @package Less
 * @subpackage exception
 */
class Less_Exception_Chunk extends Less_Exception_Parser{


	protected $parserCurrentIndex = 0;

	protected $emitFrom = 0;

	protected $input_len;


	/**
	 * Constructor
	 *
	 * @param string $input
	 * @param Exception $previous Previous exception
	 * @param integer $index The current parser index
	 * @param Less_FileInfo|string $currentFile The file
	 * @param integer $code The exception code
	 */
	public function __construct($input, Exception $previous = null, $index = null, $currentFile = null, $code = 0){

		$this->message = 'ParseError: Unexpected input'; //default message

		$this->index = $index;

		$this->currentFile = $currentFile;

		$this->input = $input;
		$this->input_len = strlen($input);

		$this->Chunks();
		$this->genMessage();
	}


	/**
	 * See less.js chunks()
	 * We don't actually need the chunks
	 *
	 */
	function Chunks(){
		$level = 0;
		$parenLevel = 0;
		$lastMultiCommentEndBrace = null;
		$lastOpening = null;
		$lastMultiComment = null;
		$lastParen = null;

		for( $this->parserCurrentIndex = 0; $this->parserCurrentIndex < $this->input_len; $this->parserCurrentIndex++ ){
			$cc = $this->CharCode($this->parserCurrentIndex);
			if ((($cc >= 97) && ($cc <= 122)) || ($cc < 34)) {
				// a-z or whitespace
				continue;
			}

			switch ($cc) {

				// (
				case 40:
					$parenLevel++;
					$lastParen = $this->parserCurrentIndex;
					continue 2;

				// )
				case 41:
					$parenLevel--;
					if( $parenLevel < 0 ){
						return $this->fail("missing opening `(`");
					}
					continue 2;

				// ;
				case 59:
					//if (!$parenLevel) { $this->emitChunk();	}
					continue 2;

				// {
				case 123:
					$level++;
					$lastOpening = $this->parserCurrentIndex;
					continue 2;

				// }
				case 125:
					$level--;
					if( $level < 0 ){
						return $this->fail("missing opening `{`");

					}
					//if (!$level && !$parenLevel) { $this->emitChunk(); }
					continue 2;
				// \
				case 92:
					if ($this->parserCurrentIndex < $this->input_len - 1) { $this->parserCurrentIndex++; continue 2; }
					return $this->fail("unescaped `\\`");

				// ", ' and `
				case 34:
				case 39:
				case 96:
					$matched = 0;
					$currentChunkStartIndex = $this->parserCurrentIndex;
					for ($this->parserCurrentIndex = $this->parserCurrentIndex + 1; $this->parserCurrentIndex < $this->input_len; $this->parserCurrentIndex++) {
						$cc2 = $this->CharCode($this->parserCurrentIndex);
						if ($cc2 > 96) { continue; }
						if ($cc2 == $cc) { $matched = 1; break; }
						if ($cc2 == 92) {        // \
							if ($this->parserCurrentIndex == $this->input_len - 1) {
								return $this->fail("unescaped `\\`");
							}
							$this->parserCurrentIndex++;
						}
					}
					if ($matched) { continue 2; }
					return $this->fail("unmatched `" + chr($cc) + "`", $currentChunkStartIndex);

				// /, check for comment
				case 47:
					if ($parenLevel || ($this->parserCurrentIndex == $this->input_len - 1)) { continue 2; }
					$cc2 = $this->CharCode($this->parserCurrentIndex+1);
					if ($cc2 == 47) {
						// //, find lnfeed
						for ($this->parserCurrentIndex = $this->parserCurrentIndex + 2; $this->parserCurrentIndex < $this->input_len; $this->parserCurrentIndex++) {
							$cc2 = $this->CharCode($this->parserCurrentIndex);
							if (($cc2 <= 13) && (($cc2 == 10) || ($cc2 == 13))) { break; }
						}
					} else if ($cc2 == 42) {
						// /*, find */
						$lastMultiComment = $currentChunkStartIndex = $this->parserCurrentIndex;
						for ($this->parserCurrentIndex = $this->parserCurrentIndex + 2; $this->parserCurrentIndex < $this->input_len - 1; $this->parserCurrentIndex++) {
							$cc2 = $this->CharCode($this->parserCurrentIndex);
							if ($cc2 == 125) { $lastMultiCommentEndBrace = $this->parserCurrentIndex; }
							if ($cc2 != 42) { continue; }
							if ($this->CharCode($this->parserCurrentIndex+1) == 47) { break; }
						}
						if ($this->parserCurrentIndex == $this->input_len - 1) {
							return $this->fail("missing closing `*/`", $currentChunkStartIndex);
						}
					}
					continue 2;

				// *, check for unmatched */
				case 42:
					if (($this->parserCurrentIndex < $this->input_len - 1) && ($this->CharCode($this->parserCurrentIndex+1) == 47)) {
						return $this->fail("unmatched `/*`");
					}
					continue 2;
			}
		}

		if( $level !== 0 ){
			if( ($lastMultiComment > $lastOpening) && ($lastMultiCommentEndBrace > $lastMultiComment) ){
				return $this->fail("missing closing `}` or `*/`", $lastOpening);
			} else {
				return $this->fail("missing closing `}`", $lastOpening);
			}
		} else if ( $parenLevel !== 0 ){
			return $this->fail("missing closing `)`", $lastParen);
		}


		//chunk didn't fail


		//$this->emitChunk(true);
	}

	function CharCode($pos){
		return ord($this->input[$pos]);
	}


	function fail( $msg, $index = null ){

		if( !$index ){
			$this->index = $this->parserCurrentIndex;
		}else{
			$this->index = $index;
		}
		$this->message = 'ParseError: '.$msg;
	}


	/*
	function emitChunk( $force = false ){
		$len = $this->parserCurrentIndex - $this->emitFrom;
		if ((($len < 512) && !$force) || !$len) {
			return;
		}
		$chunks[] = substr($this->input, $this->emitFrom, $this->parserCurrentIndex + 1 - $this->emitFrom );
		$this->emitFrom = $this->parserCurrentIndex + 1;
	}
	*/

}
 

/**
 * Compiler Exception
 *
 * @package Less
 * @subpackage exception
 */
class Less_Exception_Compiler extends Less_Exception_Parser{

} 

/**
 * Parser output with source map
 *
 * @package Less
 * @subpackage Output
 */
class Less_Output_Mapped extends Less_Output {

	/**
	 * The source map generator
	 *
	 * @var Less_SourceMap_Generator
	 */
	protected $generator;

	/**
	 * Current line
	 *
	 * @var integer
	 */
	protected $lineNumber = 0;

	/**
	 * Current column
	 *
	 * @var integer
	 */
	protected $column = 0;

	/**
	 * Array of contents map (file and its content)
	 *
	 * @var array
	 */
	protected $contentsMap = array();

	/**
	 * Constructor
	 *
	 * @param array $contentsMap Array of filename to contents map
	 * @param Less_SourceMap_Generator $generator
	 */
	public function __construct(array $contentsMap, $generator){
		$this->contentsMap = $contentsMap;
		$this->generator = $generator;
	}

	/**
	 * Adds a chunk to the stack
	 * The $index for less.php may be different from less.js since less.php does not chunkify inputs
	 *
	 * @param string $chunk
	 * @param string $fileInfo
	 * @param integer $index
	 * @param mixed $mapLines
	 */
	public function add($chunk, $fileInfo = null, $index = 0, $mapLines = null){

		//ignore adding empty strings
		if( $chunk === '' ){
			return;
		}


		$sourceLines = array();
		$sourceColumns = ' ';


		if( $fileInfo ){

			$url = $fileInfo['currentUri'];

			if( isset($this->contentsMap[$url]) ){
				$inputSource = substr($this->contentsMap[$url], 0, $index);
				$sourceLines = explode("\n", $inputSource);
				$sourceColumns = end($sourceLines);
			}else{
				throw new Exception('Filename '.$url.' not in contentsMap');
			}

		}

		$lines = explode("\n", $chunk);
		$columns = end($lines);

		if($fileInfo){

			if(!$mapLines){
				$this->generator->addMapping(
						$this->lineNumber + 1,					// generated_line
						$this->column,							// generated_column
						count($sourceLines),					// original_line
						strlen($sourceColumns),					// original_column
						$fileInfo['currentUri']
				);
			}else{
				for($i = 0, $count = count($lines); $i < $count; $i++){
					$this->generator->addMapping(
						$this->lineNumber + $i + 1,				// generated_line
						$i === 0 ? $this->column : 0,			// generated_column
						count($sourceLines) + $i,				// original_line
						$i === 0 ? strlen($sourceColumns) : 0, 	// original_column
						$fileInfo['currentUri']
					);
				}
			}
		}

		if(count($lines) === 1){
			$this->column += strlen($columns);
		}else{
			$this->lineNumber += count($lines) - 1;
			$this->column = strlen($columns);
		}

		// add only chunk
		parent::add($chunk);
	}

} 

/**
 * Encode / Decode Base64 VLQ.
 *
 * @package Less
 * @subpackage SourceMap
 */
class Less_SourceMap_Base64VLQ {

	/**
	 * Shift
	 *
	 * @var integer
	 */
	private $shift = 5;

	/**
	 * Mask
	 *
	 * @var integer
	 */
	private $mask = 0x1F; // == (1 << shift) == 0b00011111

	/**
	 * Continuation bit
	 *
	 * @var integer
	 */
	private $continuationBit = 0x20; // == (mask - 1 ) == 0b00100000

	/**
	 * Char to integer map
	 *
	 * @var array
	 */
	private $charToIntMap = array(
		'A' => 0, 'B' => 1, 'C' => 2, 'D' => 3, 'E' => 4, 'F' => 5, 'G' => 6,
		'H' => 7,'I' => 8, 'J' => 9, 'K' => 10, 'L' => 11, 'M' => 12, 'N' => 13,
		'O' => 14, 'P' => 15, 'Q' => 16, 'R' => 17, 'S' => 18, 'T' => 19, 'U' => 20,
		'V' => 21, 'W' => 22, 'X' => 23, 'Y' => 24, 'Z' => 25, 'a' => 26, 'b' => 27,
		'c' => 28, 'd' => 29, 'e' => 30, 'f' => 31, 'g' => 32, 'h' => 33, 'i' => 34,
		'j' => 35, 'k' => 36, 'l' => 37, 'm' => 38, 'n' => 39, 'o' => 40, 'p' => 41,
		'q' => 42, 'r' => 43, 's' => 44, 't' => 45, 'u' => 46, 'v' => 47, 'w' => 48,
		'x' => 49, 'y' => 50, 'z' => 51, 0 => 52, 1 => 53, 2 => 54, 3 => 55, 4 => 56,
		5 => 57,	6 => 58, 7 => 59, 8 => 60, 9 => 61, '+' => 62, '/' => 63,
	);

	/**
	 * Integer to char map
	 *
	 * @var array
	 */
	private $intToCharMap = array(
		0 => 'A', 1 => 'B', 2 => 'C', 3 => 'D', 4 => 'E', 5 => 'F', 6 => 'G',
		7 => 'H', 8 => 'I', 9 => 'J', 10 => 'K', 11 => 'L', 12 => 'M', 13 => 'N',
		14 => 'O', 15 => 'P', 16 => 'Q', 17 => 'R', 18 => 'S', 19 => 'T', 20 => 'U',
		21 => 'V', 22 => 'W', 23 => 'X', 24 => 'Y', 25 => 'Z', 26 => 'a', 27 => 'b',
		28 => 'c', 29 => 'd', 30 => 'e', 31 => 'f', 32 => 'g', 33 => 'h', 34 => 'i',
		35 => 'j', 36 => 'k', 37 => 'l', 38 => 'm', 39 => 'n', 40 => 'o', 41 => 'p',
		42 => 'q', 43 => 'r', 44 => 's', 45 => 't', 46 => 'u', 47 => 'v', 48 => 'w',
		49 => 'x', 50 => 'y', 51 => 'z', 52 => '0', 53 => '1', 54 => '2', 55 => '3',
		56 => '4', 57 => '5', 58 => '6', 59 => '7', 60 => '8', 61 => '9', 62 => '+',
		63 => '/',
	);

	/**
	 * Constructor
	 */
	public function __construct(){
		// I leave it here for future reference
		// foreach(str_split('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/') as $i => $char)
		// {
		//	 $this->charToIntMap[$char] = $i;
		//	 $this->intToCharMap[$i] = $char;
		// }
	}

	/**
	 * Convert from a two-complement value to a value where the sign bit is
	 * is placed in the least significant bit.	For example, as decimals:
	 *	 1 becomes 2 (10 binary), -1 becomes 3 (11 binary)
	 *	 2 becomes 4 (100 binary), -2 becomes 5 (101 binary)
	 * We generate the value for 32 bit machines, hence -2147483648 becomes 1, not 4294967297,
	 * even on a 64 bit machine.
	 * @param string $aValue
	 */
	public function toVLQSigned($aValue){
		return 0xffffffff & ($aValue < 0 ? ((-$aValue) << 1) + 1 : ($aValue << 1) + 0);
	}

	/**
	 * Convert to a two-complement value from a value where the sign bit is
	 * is placed in the least significant bit. For example, as decimals:
	 *	 2 (10 binary) becomes 1, 3 (11 binary) becomes -1
	 *	 4 (100 binary) becomes 2, 5 (101 binary) becomes -2
	 * We assume that the value was generated with a 32 bit machine in mind.
	 * Hence
	 *	 1 becomes -2147483648
	 * even on a 64 bit machine.
	 * @param integer $aValue
	 */
	public function fromVLQSigned($aValue){
		return $aValue & 1 ? $this->zeroFill(~$aValue + 2, 1) | (-1 - 0x7fffffff) : $this->zeroFill($aValue, 1);
	}

	/**
	 * Return the base 64 VLQ encoded value.
	 *
	 * @param string $aValue The value to encode
	 * @return string The encoded value
	 */
	public function encode($aValue){
		$encoded = '';
		$vlq = $this->toVLQSigned($aValue);
		do
		{
			$digit = $vlq & $this->mask;
			$vlq = $this->zeroFill($vlq, $this->shift);
			if($vlq > 0){
				$digit |= $this->continuationBit;
			}
			$encoded .= $this->base64Encode($digit);
		} while($vlq > 0);

		return $encoded;
	}

	/**
	 * Return the value decoded from base 64 VLQ.
	 *
	 * @param string $encoded The encoded value to decode
	 * @return integer The decoded value
	 */
	public function decode($encoded){
		$vlq = 0;
		$i = 0;
		do
		{
			$digit = $this->base64Decode($encoded[$i]);
			$vlq |= ($digit & $this->mask) << ($i * $this->shift);
			$i++;
		} while($digit & $this->continuationBit);

		return $this->fromVLQSigned($vlq);
	}

	/**
	 * Right shift with zero fill.
	 *
	 * @param integer $a number to shift
	 * @param integer $b number of bits to shift
	 * @return integer
	 */
	public function zeroFill($a, $b){
		return ($a >= 0) ? ($a >> $b) : ($a >> $b) & (PHP_INT_MAX >> ($b - 1));
	}

	/**
	 * Encode single 6-bit digit as base64.
	 *
	 * @param integer $number
	 * @return string
	 * @throws Exception If the number is invalid
	 */
	public function base64Encode($number){
		if($number < 0 || $number > 63){
			throw new Exception(sprintf('Invalid number "%s" given. Must be between 0 and 63.', $number));
		}
		return $this->intToCharMap[$number];
	}

	/**
	 * Decode single 6-bit digit from base64
	 *
	 * @param string $char
	 * @return number
	 * @throws Exception If the number is invalid
	 */
	public function base64Decode($char){
		if(!array_key_exists($char, $this->charToIntMap)){
			throw new Exception(sprintf('Invalid base 64 digit "%s" given.', $char));
		}
		return $this->charToIntMap[$char];
	}

}
 

/**
 * Source map generator
 *
 * @package Less
 * @subpackage Output
 */
class Less_SourceMap_Generator extends Less_Configurable {

	/**
	 * What version of source map does the generator generate?
	 */
	const VERSION = 3;

	/**
	 * Array of default options
	 *
	 * @var array
	 */
	protected $defaultOptions = array(
			// an optional source root, useful for relocating source files
			// on a server or removing repeated values in the 'sources' entry.
			// This value is prepended to the individual entries in the 'source' field.
			'sourceRoot'			=> '',

			// an optional name of the generated code that this source map is associated with.
			'sourceMapFilename'		=> null,

			// url of the map
			'sourceMapURL'			=> null,

			// absolute path to a file to write the map to
			'sourceMapWriteTo'		=> null,

			// output source contents?
			'outputSourceFiles'		=> false,

			// base path for filename normalization
			'sourceMapBasepath'		=> ''
	);

	/**
	 * The base64 VLQ encoder
	 *
	 * @var Less_SourceMap_Base64VLQ
	 */
	protected $encoder;

	/**
	 * Array of mappings
	 *
	 * @var array
	 */
	protected $mappings = array();

	/**
	 * The root node
	 *
	 * @var Less_Tree_Ruleset
	 */
	protected $root;

	/**
	 * Array of contents map
	 *
	 * @var array
	 */
	protected $contentsMap = array();

	/**
	 * File to content map
	 *
	 * @var array
	 */
	protected $sources = array();

	/**
	 * Constructor
	 *
	 * @param Less_Tree_Ruleset $root The root node
	 * @param array $options Array of options
	 */
	public function __construct(Less_Tree_Ruleset $root, $contentsMap, $options = array()){
		$this->root = $root;
		$this->contentsMap = $contentsMap;
		$this->encoder = new Less_SourceMap_Base64VLQ();

		$this->SetOptions($options);


		// fix windows paths
		if( isset($this->options['sourceMapBasepath']) ){
			$this->options['sourceMapBasepath'] = str_replace('\\', '/', $this->options['sourceMapBasepath']);
		}
	}

	/**
	 * Generates the CSS
	 *
	 * @return string
	 */
	public function generateCSS(){
		$output = new Less_Output_Mapped($this->contentsMap, $this);

		// catch the output
		$this->root->genCSS($output);


		$sourceMapUrl				= $this->getOption('sourceMapURL');
		$sourceMapFilename			= $this->getOption('sourceMapFilename');
		$sourceMapContent			= $this->generateJson();
		$sourceMapWriteTo			= $this->getOption('sourceMapWriteTo');

		if( !$sourceMapUrl && $sourceMapFilename ){
			$sourceMapUrl = $this->normalizeFilename($sourceMapFilename);
		}

		// write map to a file
		if( $sourceMapWriteTo ){
			$this->saveMap($sourceMapWriteTo, $sourceMapContent);
		}

		// inline the map
		if( !$sourceMapUrl ){
			$sourceMapUrl = sprintf('data:application/json,%s', Less_Functions::encodeURIComponent($sourceMapContent));
		}

		if( $sourceMapUrl ){
			$output->add( sprintf('/*# sourceMappingURL=%s */', $sourceMapUrl) );
		}

		return $output->toString();
	}

	/**
	 * Saves the source map to a file
	 *
	 * @param string $file The absolute path to a file
	 * @param string $content The content to write
	 * @throws Exception If the file could not be saved
	 */
	protected function saveMap($file, $content){
		$dir = dirname($file);
		// directory does not exist
		if( !is_dir($dir) ){
			// FIXME: create the dir automatically?
			throw new Exception(sprintf('The directory "%s" does not exist. Cannot save the source map.', $dir));
		}
		// FIXME: proper saving, with dir write check!
		if(file_put_contents($file, $content) === false){
			throw new Exception(sprintf('Cannot save the source map to "%s"', $file));
		}
		return true;
	}

	/**
	 * Normalizes the filename
	 *
	 * @param string $filename
	 * @return string
	 */
	protected function normalizeFilename($filename){
		$filename = str_replace('\\', '/', $filename);
		$basePath = $this->getOption('sourceMapBasepath');

		if( $basePath && ($pos = strpos($filename, $basePath)) !== false ){
			$filename = substr($filename, $pos + strlen($basePath));
			if(strpos($filename, '\\') === 0 || strpos($filename, '/') === 0){
				$filename = substr($filename, 1);
			}
		}
		return sprintf('%s%s', $this->getOption('sourceMapRootpath'), $filename);
	}

	/**
	 * Adds a mapping
	 *
	 * @param integer $generatedLine The line number in generated file
	 * @param integer $generatedColumn The column number in generated file
	 * @param integer $originalLine The line number in original file
	 * @param integer $originalColumn The column number in original file
	 * @param string $sourceFile The original source file
	 */
	public function addMapping($generatedLine, $generatedColumn, $originalLine, $originalColumn, $sourceFile){
		$this->mappings[] = array(
			'generated_line' => $generatedLine,
			'generated_column' => $generatedColumn,
			'original_line' => $originalLine,
			'original_column' => $originalColumn,
			'source_file' => $sourceFile
		);


		$norm_file = $this->normalizeFilename($sourceFile);

		$this->sources[$norm_file] = $sourceFile;
	}


	/**
	 * Generates the JSON source map
	 *
	 * @return string
	 * @see https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit#
	 */
	protected function generateJson(){

		$sourceMap = array();
		$mappings = $this->generateMappings();

		// File version (always the first entry in the object) and must be a positive integer.
		$sourceMap['version'] = self::VERSION;


		// An optional name of the generated code that this source map is associated with.
		$file = $this->getOption('sourceMapFilename');
		if( $file ){
			$sourceMap['file'] = $file;
		}


		// An optional source root, useful for relocating source files on a server or removing repeated values in the 'sources' entry.	This value is prepended to the individual entries in the 'source' field.
		$root = $this->getOption('sourceRoot');
		if( $root ){
			$sourceMap['sourceRoot'] = $root;
		}


		// A list of original sources used by the 'mappings' entry.
		$sourceMap['sources'] = array_keys($this->sources);



		// A list of symbol names used by the 'mappings' entry.
		$sourceMap['names'] = array();

		// A string with the encoded mapping data.
		$sourceMap['mappings'] = $mappings;

		if( $this->getOption('outputSourceFiles') ){
			// An optional list of source content, useful when the 'source' can't be hosted.
			// The contents are listed in the same order as the sources above.
			// 'null' may be used if some original sources should be retrieved by name.
			$sourceMap['sourcesContent'] = $this->getSourcesContent();
		}

		// less.js compat fixes
		if( count($sourceMap['sources']) && empty($sourceMap['sourceRoot']) ){
			unset($sourceMap['sourceRoot']);
		}

		return json_encode($sourceMap);
	}

	/**
	 * Returns the sources contents
	 *
	 * @return array|null
	 */
	protected function getSourcesContent(){
		if(empty($this->sources)){
			return;
		}
		$content = array();
		foreach($this->sources as $sourceFile){
			$content[] = file_get_contents($sourceFile);
		}
		return $content;
	}

	/**
	 * Generates the mappings string
	 *
	 * @return string
	 */
	public function generateMappings(){

		if( !count($this->mappings) ){
			return '';
		}

		// group mappings by generated line number.
		$groupedMap = $groupedMapEncoded = array();
		foreach($this->mappings as $m){
			$groupedMap[$m['generated_line']][] = $m;
		}
		ksort($groupedMap);

		$lastGeneratedLine = $lastOriginalIndex = $lastOriginalLine = $lastOriginalColumn = 0;

		foreach($groupedMap as $lineNumber => $line_map){
			while(++$lastGeneratedLine < $lineNumber){
				$groupedMapEncoded[] = ';';
			}

			$lineMapEncoded = array();
			$lastGeneratedColumn = 0;

			foreach($line_map as $m){
				$mapEncoded = $this->encoder->encode($m['generated_column'] - $lastGeneratedColumn);
				$lastGeneratedColumn = $m['generated_column'];

				// find the index
				if( $m['source_file'] ){
					$index = $this->findFileIndex($this->normalizeFilename($m['source_file']));
					if( $index !== false ){
						$mapEncoded .= $this->encoder->encode($index - $lastOriginalIndex);
						$lastOriginalIndex = $index;

						// lines are stored 0-based in SourceMap spec version 3
						$mapEncoded .= $this->encoder->encode($m['original_line'] - 1 - $lastOriginalLine);
						$lastOriginalLine = $m['original_line'] - 1;

						$mapEncoded .= $this->encoder->encode($m['original_column'] - $lastOriginalColumn);
						$lastOriginalColumn = $m['original_column'];
					}
				}

				$lineMapEncoded[] = $mapEncoded;
			}

			$groupedMapEncoded[] = implode(',', $lineMapEncoded) . ';';
		}

		return rtrim(implode($groupedMapEncoded), ';');
	}

	/**
	 * Finds the index for the filename
	 *
	 * @param string $filename
	 * @return integer|false
	 */
	protected function findFileIndex($filename){
		return array_search($filename, array_keys($this->sources));
	}

} 
lessphp/less.php000060400000002223152455303030007674 0ustar00<?php
/** 
 *------------------------------------------------------------------------------
 * @package       T3 Framework for Joomla!
 *------------------------------------------------------------------------------
 * @copyright     Copyright (C) 2004-2013 JoomlArt.com. All Rights Reserved.
 * @license       GNU General Public License version 2 or later; see LICENSE.txt
 * @authors       JoomlArt, JoomlaBamboo, (contribute to this project at github 
 *                & Google group to become co-author)
 * @Google group: https://groups.google.com/forum/#!forum/t3fw
 * @Link:         http://t3-framework.org 
 *------------------------------------------------------------------------------
 */

// No direct access
defined('_JEXEC') or die();

T3::import('lessphp/less/less');

/**
 * T3LessCompiler class compile less
 *
 * @package T3
 */
// prevent over max_nesting config in some case
@ini_set('xdebug.max_nesting_level', 120);
 
class T3LessCompiler
{
	public static function compile ($source, $importdirs) {
		$parser = new Less_Parser();
		$parser->SetImportDirs($importdirs);
		$parser->parse($source);
		$output = $parser->getCss();
		return $output;
	}
}
lessphp/lessc.inc.php000060400000263262152455303030010623 0ustar00<?php

/**
 * lessphp v0.4.0
 * http://leafo.net/lessphp
 *
 * LESS css compiler, adapted from http://lesscss.org
 *
 * Copyright 2012, Leaf Corcoran <leafot@gmail.com>
 * Licensed under MIT or GPLv3, see LICENSE
 */


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

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

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

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

	protected $numberPrecision = null;

	protected $allParsedFiles = array();

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

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

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

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

		return null;
	}

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

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

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

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

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

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

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

		$realPath = $this->findImport($url);

		if ($realPath === null) return false;

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

		if (isset($this->allParsedFiles[realpath($realPath)])) {
			return array(false, null);
		}

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

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

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

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

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

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

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

		$oldImport = $this->importDir;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

		return $scope;
	}

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

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

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

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

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

		$out->lines = array_values(array_unique($out->lines));
	}

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

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

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

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

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

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

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

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

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

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

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

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

		return $selectors;
	}


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

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

			return $selectors;
		}

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

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

		return $out;
	}

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

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

		return $out;
	}

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

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

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

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

					$this->popEnv();

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

				if ($groupPassed) break;
			}

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

		if (empty($block->args)) {
			return $block->isVararg || empty($orderedArgs) && empty($keywordArgs);
		}

		$remainingArgs = $block->args;
		if ($keywordArgs) {
			$remainingArgs = array();
			foreach ($block->args as $arg) {
				if ($arg[0] == "arg" && isset($keywordArgs[$arg[1]])) {
					continue;
				}

				$remainingArgs[] = $arg;
			}
		}

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

		if ($block->isVararg) {
			return true; // not having enough is handled above
		} else {
			$numMatched = $i + 1;
			// greater than becuase default values always match
			return $numMatched >= count($orderedArgs);
		}
	}

	protected function patternMatchAll($blocks, $orderedArgs, $keywordArgs, $skip=array()) {
		$matches = null;
		foreach ($blocks as $block) {
			// skip seen blocks that don't have arguments
			if (isset($skip[$block->id]) && !isset($block->args)) {
				continue;
			}

			if ($this->patternMatch($block, $orderedArgs, $keywordArgs)) {
				$matches[] = $block;
			}
		}

		return $matches;
	}

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

		$name = $path[0];

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

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

				return count($matches) > 0 ? $matches : null;
			}
		}
		if ($searchIn->parent === $searchIn) return null;
		return $this->findBlocks($searchIn->parent, $path, $orderedArgs, $keywordArgs, $seen);
	}

	// sets all argument names in $args to either the default value
	// or the one passed in through $values
	protected function zipSetArgs($args, $orderedValues, $keywordValues) {
		$assignedValues = array();

		$i = 0;
		foreach ($args as  $a) {
			if ($a[0] == "arg") {
				if (isset($keywordValues[$a[1]])) {
					// has keyword arg
					$value = $keywordValues[$a[1]];
				} elseif (isset($orderedValues[$i])) {
					// has ordered arg
					$value = $orderedValues[$i];
					$i++;
				} elseif (isset($a[2])) {
					// has default value
					$value = $a[2];
				} else {
					$this->throwError("Failed to assign arg " . $a[1]);
					$value = null; // :(
				}

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

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

		// wow is this the only true use of PHP's + operator for arrays?
		$this->env->arguments = $assignedValues + $orderedValues;
	}

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

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

			$orderedArgs = array();
			$keywordArgs = array();
			foreach ((array)$args as $arg) {
				$argval = null;
				switch ($arg[0]) {
				case "arg":
					if (!isset($arg[2])) {
						$orderedArgs[] = $this->reduce(array("variable", $arg[1]));
					} else {
						$keywordArgs[$arg[1]] = $this->reduce($arg[2]);
					}
					break;

				case "lit":
					$orderedArgs[] = $this->reduce($arg[1]);
					break;
				default:
					$this->throwError("Unknown arg type: " . $arg[0]);
				}
			}

			$mixins = $this->findBlocks($block, $path, $orderedArgs, $keywordArgs);

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

			foreach ($mixins as $mixin) {
				if ($mixin === $block && !$orderedArgs) {
					continue;
				}

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

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

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

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

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

				$mixin->parent = $oldParent;

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

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

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

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

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

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

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


	/**
	 * Compiles a primitive value into a CSS property value.
	 *
	 * Values in lessphp are typed by being wrapped in arrays, their format is
	 * typically:
	 *
	 *     array(type, contents [, additional_contents]*)
	 *
	 * The input is expected to be reduced. This function will not work on
	 * things like expressions and variables.
	 */
	protected function compileValue($value) {
		switch ($value[0]) {
		case 'list':
			// [1] - delimiter
			// [2] - array of values
			return implode($value[1], array_map(array($this, 'compileValue'), $value[2]));
		case 'raw_color':
			if (!empty($this->formatter->compressColors)) {
				return $this->compileValue($this->coerceColor($value));
			}
			return $value[1];
		case 'keyword':
			// [1] - the keyword
			return $value[1];
		case 'number':
			list(, $num, $unit) = $value;
			// [1] - the number
			// [2] - the unit
			if ($this->numberPrecision !== null) {
				$num = round($num, $this->numberPrecision);
			}
			return $num . $unit;
		case 'string':
			// [1] - contents of string (includes quotes)
			list(, $delim, $content) = $value;
			foreach ($content as &$part) {
				if (is_array($part)) {
					$part = $this->compileValue($part);
				}
			}
			return $delim . implode($content) . $delim;
		case 'color':
			// [1] - red component (either number or a %)
			// [2] - green component
			// [3] - blue component
			// [4] - optional alpha component
			list(, $r, $g, $b) = $value;
			$r = round($r);
			$g = round($g);
			$b = round($b);

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

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

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

			return $h;

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

	protected function lib_pow($args) {
		list($base, $exp) = $this->assertArgs($args, 2, "pow");
		return pow($this->assertNumber($base), $this->assertNumber($exp));
	}

	protected function lib_pi() {
		return pi();
	}

	protected function lib_mod($args) {
		list($a, $b) = $this->assertArgs($args, 2, "mod");
		return $this->assertNumber($a) % $this->assertNumber($b);
	}

	protected function lib_tan($num) {
		return tan($this->assertNumber($num));
	}

	protected function lib_sin($num) {
		return sin($this->assertNumber($num));
	}

	protected function lib_cos($num) {
		return cos($this->assertNumber($num));
	}

	protected function lib_atan($num) {
		$num = atan($this->assertNumber($num));
		return array("number", $num, "rad");
	}

	protected function lib_asin($num) {
		$num = asin($this->assertNumber($num));
		return array("number", $num, "rad");
	}

	protected function lib_acos($num) {
		$num = acos($this->assertNumber($num));
		return array("number", $num, "rad");
	}

	protected function lib_sqrt($num) {
		return sqrt($this->assertNumber($num));
	}

	protected function lib_extract($value) {
		list($list, $idx) = $this->assertArgs($value, 2, "extract");
		$idx = $this->assertNumber($idx);
		// 1 indexed
		if ($list[0] == "list" && isset($list[2][$idx - 1])) {
			return $list[2][$idx - 1];
		}
	}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

		$d = $string[0] == "string" ? $string[1] : '"';
		return array("string", $d, array($template));
	}

	protected function lib_floor($arg) {
		$value = $this->assertNumber($arg);
		return array("number", floor($value), $arg[2]);
	}

	protected function lib_ceil($arg) {
		$value = $this->assertNumber($arg);
		return array("number", ceil($value), $arg[2]);
	}

	protected function lib_round($arg) {
		$value = $this->assertNumber($arg);
		return array("number", round($value), $arg[2]);
	}

	protected function lib_unit($arg) {
		if ($arg[0] == "list") {
			list($number, $newUnit) = $arg[2];
			return array("number", $this->assertNumber($number),
				$this->compileValue($this->lib_e($newUnit)));
		} else {
			return array("number", $this->assertNumber($arg), "");
		}
	}

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

		return array($color, $delta);
	}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	protected function lib_hue($color) {
		$hsl = $this->toHSL($this->assertColor($color));
		return round($hsl[1]);
	}

	protected function lib_saturation($color) {
		$hsl = $this->toHSL($this->assertColor($color));
		return round($hsl[2]);
	}

	protected function lib_lightness($color) {
		$hsl = $this->toHSL($this->assertColor($color));
		return round($hsl[3]);
	}

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

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

	protected function lib_percentage($arg) {
		$num = $this->assertNumber($arg);
		return array("number", $num*100, "%");
	}

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

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

		$first_a = $this->lib_alpha($first);
		$second_a = $this->lib_alpha($second);

		if (isset($args[2][2])) {
			$weight = $args[2][2][1] / 100.0;
		} else {
			$weight = 0.5;
		}

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

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

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

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

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

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

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

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

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

		return $lightColor;
	}

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

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

	protected function assertArgs($value, $expectedArgs, $name="") {
		if ($expectedArgs == 1) {
			return $value;
		} else {
			if ($value[0] !== "list" || $value[1] != ",") $this->throwError("expecting list");
			$values = $value[2];
			$numValues = count($values);
			if ($expectedArgs != $numValues) {
				if ($name) {
					$name = $name . ": ";
				}

				$this->throwError("{$name}expecting $expectedArgs arguments, got $numValues");
			}

			return $values;
		}
	}

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

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

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

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

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

		}

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

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

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

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

		return $temp1;
	}

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

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

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

			$temp1 = 2.0 * $L - $temp2;

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

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

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

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

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

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

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

			while (count($hsl) < 4) $hsl[] = 0;
			return $this->toRGB($hsl);

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

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

		return false;
	}

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

			if ($res[0] == "raw_color") {
				$res = $this->coerceColor($res);
			}

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

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

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

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

			$seen[$key] = true;
			$out = $this->reduce($this->get($key, self::$defaultValue));
			$seen[$key] = false;
			return $out;
		case "list":
			foreach ($value[2] as &$item) {
				$item = $this->reduce($item, $forExpression);
			}
			return $value;
		case "expression":
			return $this->evaluate($value);
		case "string":
			foreach ($value[2] as &$part) {
				if (is_array($part)) {
					$strip = $part[0] == "variable";
					$part = $this->reduce($part);
					if ($strip) $part = $this->lib_e($part);
				}
			}
			return $value;
		case "escape":
			list(,$inner) = $value;
			return $this->lib_e($this->reduce($inner));
		case "function":
			$color = $this->funcToColor($value);
			if ($color) return $color;

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

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

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

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

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

				return $ret;
			}

			// plain function, reduce args
			$value[2] = $this->reduce($value[2]);
			return $value;
		case "unary":
			list(, $op, $exp) = $value;
			$exp = $this->reduce($exp);

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

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

		return $value;
	}


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

		return $c;
	}

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

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

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

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

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

		return $color[1];
	}

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

		return $color[2];
	}

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

		return $color[3];
	}


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

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

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


	/* environment functions */

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

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

		$this->env = $e;
		return $e;
	}

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

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


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

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

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

		return $default;
	}

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

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

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

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

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

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

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

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

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

		ob_start();
		$this->formatter->block($this->scope);
		$out = ob_get_clean();
		setlocale(LC_NUMERIC, $locale);
		return $out;
	}

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

		$pi = pathinfo($fname);

		$oldImport = $this->importDir;

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

		$this->addParsedFile($fname);

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

		$this->importDir = $oldImport;

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

		return $out;
	}

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

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

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

		if ($root !== null) {
			// If we have a root value which means we should rebuild.
			$out = array();
			$out['root'] = $root;
			$out['compiled'] = $this->compileFile($root);
			$out['files'] = $this->allParsedFiles();
			$out['updated'] = time();
			return $out;
		} else {
			// No changes, pass back the structure
			// we were given initially.
			return $in;
		}

	}

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

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

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

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

		$this->registeredVars = $oldVars;
		return $out;
	}

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

		return $parser;
	}

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

	protected function newFormatter() {
		$className = "lessc_formatter_lessjs";
		if (!empty($this->formatterName)) {
			if (!is_string($this->formatterName))
				return $this->formatterName;
			$className = "lessc_formatter_$this->formatterName";
		}

		return new $className;
	}

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

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

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

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

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

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

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

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

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

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

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

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

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

// responsible for taking a string of LESS code and converting it into a
// syntax tree
class lessc_parser {
	static protected $nextBlockId = 0; // used to uniquely identify blocks

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

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

	static protected $whitePattern;
	static protected $commentMulti;

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

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

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

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

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

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

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

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

		$this->writeComments = false;

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

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

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

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

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

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

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

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

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

		return $this->env;
	}

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

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


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

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

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

			$this->seek($s);
		}

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

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

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

		// opening a simple block
		if ($this->tags($tags) && $this->literal('{')) {
			$tags = $this->fixTags($tags);
			$this->pushBlock($tags);
			return true;
		} else {
			$this->seek($s);
		}

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

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

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

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

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

		// mixin
		if ($this->mixinTags($tags) &&
			($this->argumentDef($argv, $isVararg) || true) &&
			($this->keyword($suffix) || true) && $this->end())
		{
			$tags = $this->fixTags($tags);
			$this->append(array('mixin', $tags, $argv, $suffix), $s);
			return true;
		} else {
			$this->seek($s);
		}

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

		return false; // got nothing, throw error
	}

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

		return preg_match($pattern, $dirname);
	}

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

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

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

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

		$exps = lessc::compressList($values, ' ');
		return true;
	}

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

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

			return true;
		}
		return false;
	}

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

		while (true) {
			$whiteBefore = isset($this->buffer[$this->count - 1]) &&
				ctype_space($this->buffer[$this->count - 1]);

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

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


				$whiteAfter = isset($this->buffer[$this->count - 1]) &&
					ctype_space($this->buffer[$this->count - 1]);

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

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

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

				continue;
			}

			break;
		}

		$this->seek($ss);

		return $lhs;
	}

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

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

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

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

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

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

		$value = lessc::compressList($values, ', ');
		return true;
	}

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

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

		$inParens = $this->inParens;
		if ($this->literal("(") &&
			($this->inParens = true) && $this->expression($exp) &&
			$this->literal(")"))
		{
			$out = $exp;
			$this->inParens = $inParens;
			return true;
		} else {
			$this->inParens = $inParens;
			$this->seek($s);
		}

		return false;
	}

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

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

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

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

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

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

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

		return false;
	}

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

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

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

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

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

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

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


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

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

		$out = $parts;
		return true;
	}

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

		$this->seek($s);
		return false;
	}

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

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

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

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

		$nestingLevel = 0;

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

			$tok = $m[2];

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

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

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

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

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

		$this->eatWhiteDefault = $oldWhite;

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

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

		$out = array("string", "", $content);
		return true;
	}

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

		$content = array();

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

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

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

		$this->eatWhiteDefault = $oldWhite;

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

		$this->seek($s);
		return false;
	}

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

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

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

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

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

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

		return false;
	}

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

		$values = array();
		$delim = ",";
		$method = "expressionList";

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

			if ($this->$method($value)) {
				if ($value[0] == "variable") {
					$arg = array("arg", $value[1]);
					$ss = $this->seek();

					if ($this->assign() && $this->$method($rhs)) {
						$arg[] = $rhs;
					} else {
						$this->seek($ss);
						if ($this->literal("...")) {
							$arg[0] = "rest";
							$isVararg = true;
						}
					}

					$values[] = $arg;
					if ($isVararg) break;
					continue;
				} else {
					$values[] = array("lit", $value);
				}
			}


			if (!$this->literal($delim)) {
				if ($delim == "," && $this->literal(";")) {
					// found new delim, convert existing args
					$delim = ";";
					$method = "propertyValue";

					// transform arg list
					if (isset($values[1])) { // 2 items
						$newList = array();
						foreach ($values as $i => $arg) {
							switch($arg[0]) {
							case "arg":
								if ($i) {
									$this->throwError("Cannot mix ; and , as delimiter types");
								}
								$newList[] = $arg[2];
								break;
							case "lit":
								$newList[] = $arg[1];
								break;
							case "rest":
								$this->throwError("Unexpected rest before semicolon");
							}
						}

						$newList = array("list", ", ", $newList);

						switch ($values[0][0]) {
						case "arg":
							$newArg = array("arg", $values[0][1], $newList);
							break;
						case "lit":
							$newArg = array("lit", $newList);
							break;
						}

					} elseif ($values) { // 1 item
						$newArg = $values[0];
					}

					if ($newArg) {
						$values = array($newArg);
					}
				} else {
					break;
				}
			}
		}

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

		$args = $values;

		return true;
	}

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

		return true;
	}

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

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

		return true;
	}

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

		$s = $this->seek();

		$hasInterpolation = false;

		if ($this->literal("[", false)) {
			$attrParts = array("[");
			// keyword, string, operator
			while (true) {
				if ($this->literal("]", false)) {
					$this->count--;
					break; // get out early
				}

				if ($this->match('\s+', $m)) {
					$attrParts[] = " ";
					continue;
				}
				if ($this->string($str)) {
					// escape parent selector, (yuck)
					foreach ($str[2] as &$chunk) {
						$chunk = str_replace($this->lessc->parentSelector, "$&$", $chunk);
					}

					$attrParts[] = $str;
					$hasInterpolation = true;
					continue;
				}

				if ($this->keyword($word)) {
					$attrParts[] = $word;
					continue;
				}

				if ($this->interpolation($inter, false)) {
					$attrParts[] = $inter;
					$hasInterpolation = true;
					continue;
				}

				// operator, handles attr namespace too
				if ($this->match('[|-~\$\*\^=]+', $m)) {
					$attrParts[] = $m[0];
					continue;
				}

				break;
			}

			if ($this->literal("]", false)) {
				$attrParts[] = "]";
				foreach ($attrParts as $part) {
					$parts[] = $part;
				}
				$hasExpression = $hasExpression || $hasInterpolation;
				return true;
			}
			$this->seek($s);
		}

		$this->seek($s);
		return false;
	}

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

		$s = $this->seek();

		$hasExpression = false;
		$parts = array();
		while ($this->tagBracket($parts, $hasExpression));

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

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

				while ($this->tagBracket($parts, $hasExpression));
				continue;
			}

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

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

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

			break;
		}

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

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

		$this->whitespace();
		return true;
	}

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

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

			$sPreArgs = $this->seek();

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

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

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

		$this->seek($s);
		return false;
	}

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

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

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

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

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

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

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

		$guards = array();

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

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

		return true;
	}

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

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

		return true;
	}

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

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

		$this->seek($s);
		return false;
	}

	/* raw parsing functions */

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

		// shortcut on single letter
		if (!isset($what[1]) && isset($this->buffer[$this->count])) {
			if ($this->buffer[$this->count] == $what) {
				if (!$eatWhitespace) {
					$this->count++;
					return true;
				}
				// goes below...
			} else {
				return false;
			}
		}

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

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

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

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

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

		return true;
	}


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

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

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

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

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

		return $result;
	}

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

	/* misc functions */

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

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

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

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

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

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

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

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

		$this->env = $b;
		return $b;
	}

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

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

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

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

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

			if (is_null($min)) break;

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

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

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

			$min = null;
		}

		return $out.$text;
	}

}

class lessc_formatter_classic {
	public $indentChar = "  ";

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

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

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

	public $compressColors = false;

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

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

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

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

			return true;
		}
		return false;
	}

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

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

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

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

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

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

		}

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

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

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

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

			$this->indentLevel--;
		}
	}
}

class lessc_formatter_compressed extends lessc_formatter_classic {
	public $disableSingle = true;
	public $open = "{";
	public $selectorSeparator = ",";
	public $assignSeparator = ":";
	public $break = "";
	public $compressColors = true;

	public function indentStr($n = 0) {
		return "";
	}
}

class lessc_formatter_lessjs extends lessc_formatter_classic {
	public $disableSingle = true;
	public $breakSelectors = true;
	public $assignSeparator = ": ";
	public $selectorSeparator = ",";
}


menu/t3bootstrap.php000060400000011415152455303030010503 0ustar00<?php
/**
 *------------------------------------------------------------------------------
 * @package       T3 Framework for Joomla!
 *------------------------------------------------------------------------------
 * @copyright     Copyright (C) 2004-2013 JoomlArt.com. All Rights Reserved.
 * @license       GNU General Public License version 2 or later; see LICENSE.txt
 * @authors       JoomlArt, JoomlaBamboo, (contribute to this project at github
 *                & Google group to become co-author)
 * @Google group: https://groups.google.com/forum/#!forum/t3fw
 * @Link:         http://t3-framework.org
 *------------------------------------------------------------------------------
 */

if (!class_exists('T3BootstrapTpl', false)) {
	T3::import('menu/t3bootstrap.tpl');
}

class T3Bootstrap
{

	/**
	 * Internal variables
	 */
	protected $menutype;
	protected $menu;

	/**
	 * @param string $menutype
	 */
	function __construct($menutype = 'mainmenu')
	{
		$this->menutype = $menutype;
		$this->menu = '';
	}

	/**
	 * @return string
	 */
	function render()
	{
		if(!$this->menu){
			ob_start();
			T3BootstrapTpl::render($this->getList());
			$this->menu = ob_get_contents();
			ob_end_clean();	
		}
		
		return $this->menu;
	}

	/**
	 * @return mixed
	 */
	function getList()
	{
		$app   = JFactory::getApplication();
		$menu  = $app->getMenu();

		// Get active menu item
		$items = $menu->getItems('menutype', $this->menutype);
		$lastitem = 0;

		if ($items) {
			foreach ($items as $i => $item) {

				$item->deeper = false;
				$item->shallower = false;
				$item->level_diff = 0;
				$itemParams = version_compare(JVERSION, '4','ge') ? $item->getParams() : $item->params;
				if (isset($items[$lastitem])) {
					$items[$lastitem]->deeper = ($item->level > $items[$lastitem]->level);
					$items[$lastitem]->shallower = ($item->level < $items[$lastitem]->level);
					$items[$lastitem]->level_diff = ($items[$lastitem]->level - $item->level);
				}

				$item->parent = (boolean)$menu->getItems('parent_id', (int)$item->id, true);

				$lastitem = $i;
				$item->active = false;
				$item->flink = $item->link;

				// Reverted back for CMS version 2.5.6
				switch ($item->type) {
					case 'separator':
					case 'heading':
						// No further action needed.
						break;

					case 'url':
						if ((strpos($item->link, 'index.php?') === 0) && (strpos($item->link, 'Itemid=') === false)) {
							// If this is an internal Joomla link, ensure the Itemid is set.
							$item->flink = $item->link . '&Itemid=' . $item->id;
						}
						break;

					case 'alias':
						// If this is an alias use the item id stored in the parameters to make the link.
						$item->flink = 'index.php?Itemid=' . $itemParams->get('aliasoptions');
						break;

					default:
						$router = $app::getRouter();
						if(version_compare(JVERSION, '4', 'lt')){
							if ($router->getMode() == JROUTER_MODE_SEF) {
								$item->flink = 'index.php?Itemid=' . $item->id;
							} else {
								$item->flink .= '&Itemid=' . $item->id;
							}
						}
                        else
                        {
                            if(strpos($item->flink,'Itemid=') === false)
                                $item->flink .= (strpos($item->flink,'?') === false ? '?' : '&').'Itemid=' . $item->id;
                        }
						
						break;
				}

				if (strcasecmp(substr($item->flink, 0, 4), 'http') && (strpos($item->flink, 'index.php?') !== false)) {
					$item->flink = JRoute::_($item->flink, true, $itemParams->get('secure'));
				} else {
					$item->flink = JRoute::_($item->flink);
				}

				// We prevent the double encoding because for some reason the $item is shared for menu modules and we get double encoding
				// when the cause of that is found the argument should be removed
				$item->title = htmlspecialchars($item->title, ENT_COMPAT, 'UTF-8', false);
				$item->anchor_css = htmlspecialchars($itemParams->get('menu-anchor_css', ''), ENT_COMPAT, 'UTF-8', false);
				$item->anchor_title = htmlspecialchars($itemParams->get('menu-anchor_title', ''), ENT_COMPAT, 'UTF-8', false);
				$item->menu_image = $itemParams->get('menu_image', '') ? htmlspecialchars($itemParams->get('menu_image', ''), ENT_COMPAT, 'UTF-8', false) : '';
			}

			if (isset($items[$lastitem])) {
				$items[$lastitem]->deeper = (1 > $items[$lastitem]->level);
				$items[$lastitem]->shallower = (1 < $items[$lastitem]->level);
				$items[$lastitem]->level_diff = ($items[$lastitem]->level - 1);
			}
		}

		return $items;
	}

	/**
	 * Get base menu item.
	 *
	 * @return   object
	 */
	public static function getBase()
	{
		return self::getActive();
	}

	/**
	 * Get active menu item.
	 *
	 * @return  object
	 */
	public static function getActive()
	{
		$menu = JFactory::getApplication()->getMenu();
		return $menu->getActive() ? $menu->getActive() : $menu->getDefault();
	}
}
menu/megamenu.php000060400000026036152455303030010022 0ustar00<?php
/** 
 *------------------------------------------------------------------------------
 * @package       T3 Framework for Joomla!
 *------------------------------------------------------------------------------
 * @copyright     Copyright (C) 2004-2013 JoomlArt.com. All Rights Reserved.
 * @license       GNU General Public License version 2 or later; see LICENSE.txt
 * @authors       JoomlArt, JoomlaBamboo, (contribute to this project at github 
 *                & Google group to become co-author)
 * @Google group: https://groups.google.com/forum/#!forum/t3fw
 * @Link:         http://t3-framework.org 
 *------------------------------------------------------------------------------
 */

if(!class_exists('T3MenuMegamenuTpl', false)){
	T3::import('menu/megamenu.tpl');
}
if (is_file(T3_TEMPLATE_PATH.'/html/megamenu.php')) {
	require_once T3_TEMPLATE_PATH.'/html/megamenu.php';
}

#[AllowDynamicProperties]
class T3MenuMegamenu {

	/**
	 * Internal variables
	 */
	protected $_items = array();
	protected $children = array();
	protected $settings = null;
	protected $params = null;
	protected $menu = '';
	protected $active_id = 0;
	protected $active_tree = array();
	protected $top_level_caption = false;

	/**
	 * @param  string  $menutype  menu type to render
	 * @param  array   $settings  settings information
	 * @param  null    $params    other parameters
	 */
	function __construct($menutype = 'mainmenu', $settings = array(), $params = null) {
		$app   = JFactory::getApplication();
		$menu  = $app->getMenu('site');

		$attributes = array('menutype');
		$values     = array($menutype);

		if(isset($settings['access'])){
			$attributes[] = 'access';
			$values[]     = $settings['access'];
		} else {
			$settings['access'] = array(1);
		}
		
		if(isset($settings['language'])){
			$attributes[] = 'language';
			$values[]     = $settings['language'];
		}

		$items = $menu->getItems($attributes, $values);
		
		$active            = ($menu->getActive()) ? $menu->getActive() : $menu->getDefault();
		$this->active_id   = $active ? $active->id : 0;
		$this->active_tree = $active->tree;
		
		$this->settings = $settings;
		$this->params   = $params;
		$this->editmode = isset($settings['editmode']);
		foreach ($items as &$item) {
			//remove all non-parent item (the parent has access higher access level)
			if($item->level >= 2 && !isset($this->_items[$item->parent_id])){
				continue;
			}
			
			//intergration with new params joomla 3.6.x (menu_show)
			$menu_show = $item->getParams()->get('menu_show');
			if (empty($menu_show) && $menu_show!==null)
				continue;

			$parent                           = isset($this->children[$item->parent_id]) ? $this->children[$item->parent_id] : array();
			$parent[]                         = $item;
			$this->children[$item->parent_id] = $parent;
			$this->_items[$item->id]          = $item;
		}
		foreach ($items as &$item) {
			// bind setting for this item
			$key     = 'item-' . $item->id;
			$setting = isset($this->settings[$key]) ? $this->settings[$key] : array();
			
			// decode html tag
			if (isset($setting['caption']) && $setting['caption'])
				$setting['caption'] = str_replace(array('[lt]', '[gt]'), array('<', '>'), $setting['caption']);
			if ($item->level == 1 && isset($setting['caption']) && $setting['caption'])
				$this->top_level_caption = true;
			
			// active - current
			$class = '';
			if ($item->id == $this->active_id) {
				$class .= ' current';
			}
			if (in_array($item->id, $this->active_tree)) {
				$class .= ' active';
			} elseif ($item->type == 'alias') {
				$aliasToId = $item->getParams()->get('aliasoptions');
				if (count($this->active_tree) > 0 && $aliasToId == $this->active_tree[count($this->active_tree) - 1]) {
					$class .= ' active';
				} elseif (in_array($aliasToId, $this->active_tree)) {
					$class .= ' alias-parent-active';
				}
			}
			
			$item->class    = $class;
			$item->mega     = 0;
			$item->group    = 0;
			$item->dropdown = 0;
			if (isset($setting['group']) && $item->level > 1) {
				$item->group = 1;
			} else {
				if ((isset($this->children[$item->id]) && ($this->editmode || !isset($setting['hidesub']))) || isset($setting['sub'])) {
					$item->dropdown = 1;
				}
			}
			$item->mega = $item->group || $item->dropdown;
			// set default sub if not exists
			if ($item->mega) {
			 	if (!isset($setting['sub'])) $setting['sub'] = array();
			 	if (isset($this->children[$item->id]) && (!isset($setting['sub']['rows']) || !count($setting['sub']['rows']))) {
					$c = $this->children[$item->id][0]->id;
					$setting['sub'] = array('rows'=>array(array(array('width'=>12, 'item'=>$c))));
				}
			}
			$item->setting = $setting;
			
			$item->flink = $item->link;
			
			// Reverted back for CMS version 2.5.6
			switch ($item->type) {
				case 'separator':
				case 'heading':
					// No further action needed.
					break;
				
				case 'url':
					if ((strpos($item->link, 'index.php?') === 0) && (strpos($item->link, 'Itemid=') === false)) {
						// If this is an internal Joomla link, ensure the Itemid is set.
						$item->flink = $item->link . '&Itemid=' . $item->id;
					}
					break;
				
				case 'alias':
					// If this is an alias use the item id stored in the parameters to make the link.
					$item->flink = 'index.php?Itemid=' . $item->getParams()->get('aliasoptions');
					break;
				
				default:
					//$router = JSite::getRouter();
					$item->flink = 'index.php?Itemid=' . $item->id;
					break;
			}
			
			if (strcasecmp(substr($item->flink, 0, 4), 'http') && (strpos($item->flink, 'index.php?') !== false)) {
				$item->flink = JRoute::_($item->flink, true, $item->getParams()->get('secure'));
			} else {
				$item->flink = JRoute::_($item->flink);
			}
			
			// We prevent the double encoding because for some reason the $item is shared for menu modules and we get double encoding
			// when the cause of that is found the argument should be removed
			$item->title        = htmlspecialchars($item->title, ENT_COMPAT, 'UTF-8', false);
			$item->anchor_css   = htmlspecialchars($item->getParams()->get('menu-anchor_css', ''), ENT_COMPAT, 'UTF-8', false);
			$item->anchor_title = htmlspecialchars($item->getParams()->get('menu-anchor_title', ''), ENT_COMPAT, 'UTF-8', false);
			$item->anchor_rel = htmlspecialchars($item->getParams()->get('menu-anchor_rel', ''), ENT_COMPAT, 'UTF-8', false);
			$item->menu_image   = $item->getParams()->get('menu_image', '') ? htmlspecialchars($item->getParams()->get('menu_image', ''), ENT_COMPAT, 'UTF-8', false) : '';
			$item->menu_image_css = htmlspecialchars($item->getParams()->get('menu_image_css', ''), ENT_COMPAT, 'UTF-8', false);
		}
	}
	
	function render($return = false) {
		$this->menu = '';
		
		$this->_('beginmenu');
		$keys = array_keys($this->_items);
		if (count($keys)) { //in case the keys is empty array
			$this->nav(null, $keys[0]);
		}
		$this->_('endmenu');
		
		if ($return) {
			return $this->menu;
		} else {
			echo $this->menu;
		}
	}
	
	function nav($pitem, $start = 0, $end = 0) {
		if ($start > 0) {
			if (!isset($this->_items[$start]))
				return;
			$pid     = $this->_items[$start]->parent_id;
			$items   = array();
			$started = false;
			foreach ($this->children[$pid] as $item) {
				if ($started) {
					if ($item->id == $end)
						break;
					$items[] = $item;
				} else {
					if ($item->id == $start) {
						$started = true;
						$items[] = $item;
					}
				}
			}
			if (!count($items))
				return;
		} else if ($start === 0) {
			$pid = $pitem->id;
			if (!isset($this->children[$pid]))
				return;
			$items = $this->children[$pid];
		} else {
			//empty menu
			return;
		}
		
		$this->_('beginnav', array(
			'item' => $pitem
		));
		
		foreach ($items as $item) {
			$this->item($item);
		}
		
		$this->_('endnav', array(
			'item' => $pitem
		));
	}
	
	function item($item) {
		// item content
		$setting = $item->setting;
		
		$this->_('beginitem', array(
			'item' => $item,
			'setting' => $setting,
			'menu' => $this
		));
		
		$this->menu .= $this->_('item', array(
			'item' => $item,
			'setting' => $setting,
			'menu' => $this
		));
		
		if ($item->mega) {
			$this->mega($item);
		}
		$this->_('enditem', array(
			'item' => $item
		));
	}
	
	function mega($item) {
		$setting   = $item->setting;
		$sub       = $setting['sub'];
		$items     = isset($this->children[$item->id]) ? $this->children[$item->id] : array();
		$firstitem = count($items) ? $items[0]->id : 0;
		
		$this->_('beginmega', array(
			'item' => $item
		));
		$endItems = array();
		$k1       = $k2 = 0;
		foreach ($sub['rows'] as $row) {
			foreach ($row as $col) {
				if (!isset($col['position'])) {
					if ($k1) {
						$k2 = $col['item'];
						if (!isset($this->_items[$k2]) || $this->_items[$k2]->parent_id != $item->id)
							break;
						$endItems[$k1] = $k2;
					}
					$k1 = $col['item'];
				}
			}
		}
		$endItems[$k1] = 0;
		
		$firstitemscol = true;
		foreach ($sub['rows'] as $row) {
			$this->_('beginrow', array(
				'menu' => $this
			));

			foreach ($row as $col) {
				$this->_('begincol', array(
					'setting' => $col,
					'menu' => $this
				));
				if (isset($col['position'])) {
					$this->module($col['position']);
				} else {
					if (!isset($endItems[$col['item']]))
						continue;
					$toitem    = $endItems[$col['item']];
					$startitem = $firstitemscol ? $firstitem : $col['item'];
					$this->nav($item, $startitem, $toitem);
					$firstitemscol = false;
				}
				$this->_('endcol');
			}
			$this->_('endrow');
		}
		$this->_('endmega');
	}
	
	function module($module) {
		// load module
		$id    = intval($module);
		$db    = JFactory::getDbo();
		$query = $db->getQuery(true);
		$query
			->select('m.id, m.title, m.module, m.position, m.content, m.showtitle, m.params')
			->from('#__modules AS m')
			->where('m.id = ' . $id)
			->where('m.published = 1')
			->where('m.access IN ('.implode(',', $this->settings['access']).')');
		$db->setQuery($query);
		$module = $db->loadObject();
		
		//check in case the module is unpublish or deleted
		if ($module && $module->id) {
			$style   = 'T3Xhtml';
			$content = JModuleHelper::renderModule($module, array(
				'style' => $style
			));

			$app = JFactory::getApplication();
			$frontediting = $app->get('frontediting', 1);
			$user = JFactory::getUser();

			$canEdit = $user->id && $frontediting && !(T3::isAdmin() && $frontediting < 2) && $user->authorise('core.edit', 'com_modules');
			$menusEditing = ($frontediting == 2) && $user->authorise('core.edit', 'com_menus');

			if ($app->isClient('site') && $canEdit && trim($content) != '' && $user->authorise('core.edit', 'com_modules.module.' . $module->id))
			{
				$displayData = array('moduleHtml' => &$content, 'module' => $module, 'position' => $module->position, 'menusediting' => $menusEditing);
				JLayoutHelper::render('joomla.edit.frontediting_modules', $displayData);
			}

			$this->menu .= $content . "\n";
		}
	}
	
	function _($tmpl, $vars = array()) {
		$vars['menu'] = $this;
		$this->menu .= T3MenuMegamenuTpl::_($tmpl, $vars);
	}
	
	function get($prop) {
		if (isset($this->$prop))
			return $this->$prop;
		return null;
	}
	
	function getParam($name, $default = null) {
		if (!$this->params)
			return $default;
		return $this->params->get($name, $default);
	}
}
menu/megamenu.tpl.php000060400000024345152455303030010621 0ustar00<?php
/**
 *------------------------------------------------------------------------------
 * @package       T3 Framework for Joomla!
 *------------------------------------------------------------------------------
 * @copyright     Copyright (C) 2004-2013 JoomlArt.com. All Rights Reserved.
 * @license       GNU General Public License version 2 or later; see LICENSE.txt
 * @authors       JoomlArt, JoomlaBamboo, (contribute to this project at github
 *                & Google group to become co-author)
 * @Google group: https://groups.google.com/forum/#!forum/t3fw
 * @Link:         http://t3-framework.org
 *------------------------------------------------------------------------------
 */

class T3MenuMegamenuTpl
{
	static function beginmenu($vars)
	{
		$menu          = $vars['menu'];
		$animation     = $menu->getParam('navigation_animation', '');
		$trigger       = $menu->getParam('navigation_trigger', 'hover');
		$responsive    = $menu->getParam('responsive', 1);
		$anim_duration = $menu->getParam('navigation_animation_duration', 0);

		$cls  = ' class="t3-megamenu' . ($trigger == 'hover' && $animation ? ' animate ' . $animation : '') . '"';
		$data = $animation && $anim_duration ? ' data-duration="' . $anim_duration . '"' : '';
		$data = $data . ($responsive ? ' data-responsive="true"' : '');

		return "<div $cls $data>";
	}

	static function endmenu($vars)
	{
		return '</div>';
	}

	static function beginnav($vars)
	{
		$item = $vars['item'];
		$cls  = '';
		if (!$item) {
			// first nav
			$cls = 'nav navbar-nav level0';
		} else {
			$cls .= ' mega-nav';
			$cls .= ' level' . $item->level;
		}
		if ($cls) $cls = 'class="' . trim($cls) . '"';

		return '<ul itemscope itemtype="http://www.schema.org/SiteNavigationElement" ' . $cls . '>';

	}

	static function endnav($vars)
	{
		return '</ul>';
	}

	static function beginmega($vars)
	{
		$item    = $vars['item'];
		$setting = $item->setting;
		$sub     = $setting['sub'];
		$cls     = 'nav-child ' . ($item->dropdown ? 'dropdown-menu mega-dropdown-menu' : 'mega-group-ct');
		$style   = '';
		$data    = '';
		if (isset($sub['class'])) {
			$data .= " data-class=\"{$sub['class']}\"";
			$cls  .= " {$sub['class']}";
		}
		if (isset($setting['alignsub']) && $setting['alignsub'] == 'justify') {
			$cls  .= ' ' . ($vars['menu']->editmode ? 'span' : T3_BASE_NONRSP_WIDTH_PREFIX) . '12';
		} else {
			if (isset($sub['width'])) {
				if ($item->dropdown) $style = ' style="width: ' . str_replace('px', '', $sub['width']) . 'px"';
				$data .= ' data-width="' . str_replace('px', '', $sub['width']) . '"';
			}
		}

		if ($cls) $cls = 'class="' . trim($cls) . '"';

		return "<div $cls $style $data><div class=\"mega-dropdown-inner\">";
	}

	static function endmega($vars)
	{
		return '</div></div>';
	}

	static function beginrow($vars)
	{
		return '<div class="' . ($vars['menu']->editmode ? 'row-fluid' : T3_BASE_ROW_FLUID_PREFIX) . '">';
	}

	static function endrow($vars)
	{
		return '</div>';
	}

	static function begincol($vars)
	{
		$setting = isset($vars['setting']) ? $vars['setting'] : array();
		$width   = isset($setting['width']) ? $setting['width'] : T3_BASE_MAX_GRID;
		$data    = "data-width=\"$width\"";
		$cls     = ($vars['menu']->editmode ? 'span' : T3_BASE_NONRSP_WIDTH_PREFIX) . $width;

		if (isset($setting['position'])) {
			$cls  .= " mega-col-module";
			$data .= " data-position=\"{$setting['position']}\"";
		} else {
			$cls  .= " mega-col-nav";
		}
		if (isset($setting['class'])) {
			$cls  .= " {$setting['class']}";
			$data .= " data-class=\"{$setting['class']}\"";
		}
		if (isset($setting['hidewcol'])) {
			$cls  .= " hidden-collapse";
			$data .= " data-hidewcol=\"1\"";
		}
		if (isset($setting['groupstyle']) && $setting['groupstyle']) {
			$cls  .= " " . $setting['groupstyle'];
			$data .= " data-groupstyle=\"{$setting['groupstyle']}\"";
		}

		return "<div class=\"$cls\" $data><div class=\"mega-inner\">";
	}

	static function endcol($vars)
	{
		return '</div></div>';
	}

	static function beginitem($vars)
	{
		$item    = $vars['item'];
		$setting = $item->setting;
		$cls     = $item->class;

		if ($item->dropdown) {
			$cls .= $item->level == 1 ? ' dropdown' : ' dropdown-submenu';
		}

		if ($item->mega)  $cls .= ' mega';
		if ($item->group) $cls .= ' mega-group';
		if ($item->type == 'separator' && !$item->group && !$item->mega) $cls .= ' divider';

		$data = "data-id=\"{$item->id}\" data-level=\"{$item->level}\"";
		if ($item->group) $data .= " data-group=\"1\"";
		if (isset($setting['class'])) {
			$cls  .= " {$setting['class']}";
			$data .= " data-class=\"{$setting['class']}\"";
		}
		if (isset($setting['alignsub'])) {
			$cls  .= " mega-align-{$setting['alignsub']}";
			$data .= " data-alignsub=\"{$setting['alignsub']}\"";
		}
		if (isset($setting['hidesub'])) $data .= " data-hidesub=\"1\"";
		if (isset($setting['xicon']))   $data .= " data-xicon=\"{$setting['xicon']}\"";
		if (isset($setting['caption'])) $data .= " data-caption=\"" . htmlspecialchars($setting['caption']) . "\"";
		if (isset($setting['hidewcol'])) {
			$data .= " data-hidewcol=\"1\"";
			$cls  .= " sub-hidden-collapse";
		}

		if ($cls) $cls = 'class="' . trim($cls) . '"';

		return "<li itemprop='name' $cls $data>";
	}

	static function enditem($vars)
	{
		return '</li>';
	}

	static function item($vars)
	{
		$item    = $vars['item'];
		$setting = $item->setting;

		// Note. It is important to remove spaces between elements.
		$vars['class']    = $item->anchor_css ? $item->anchor_css : '';
		$vars['title']    = $item->anchor_title ? ' title="' . $item->anchor_title . '" ' : '';
		$vars['rel']    = $item->anchor_rel ? ' rel="' . $item->anchor_rel . '" ' : '';
		$vars['dropdown'] = ' data-target="#"';
		$vars['caret']    = '';
		$vars['icon']     = '';
		$vars['caption']  = '';
		$itemParams = version_compare(JVERSION, '4', 'ge') ? $item->getParams() : $item->params;
		if ($item->dropdown && $item->level < 2) {
			$vars['class']    .= ' dropdown-toggle';
			$vars['dropdown'] .= ' data-toggle="dropdown"'; // Note: data-target for JomSocial old bootstrap lib
			$vars['caret']     = '<em class="caret"></em>';
		}

		if($item->group){
			$vars['class']    .= ' dropdown-header mega-group-title';
		}
		if ($item->menu_image) {
			$itemParams->get('menu_text', 1) ?
				$vars['linktype'] = '<img class="' . $item->menu_image_css . '" src="' . $item->menu_image . '" alt="' . $item->title . '" /><span class="image-title">' . $item->title . '</span> ' :
				$vars['linktype'] = '<img class="' . $item->menu_image_css . '" src="' . $item->menu_image . '" alt="' . $item->title . '" />';
		} else {
			$vars['linktype'] = $item->title;
		}

		if (isset($setting['xicon']) && $setting['xicon']) {
			$vars['icon'] = '<span class="' . $setting['xicon'] . '"></span>';
		}
		if (isset($setting['caption']) && $setting['caption']) {
			$vars['caption'] = '<span class="mega-caption">' . $setting['caption'] . '</span>';
		} else if ($item->level == 1 && $vars['menu']->get('top_level_caption')) {
			$vars['caption'] = '<span class="mega-caption mega-caption-empty">&nbsp;</span>';
		}

		switch ($item->type) {
			case 'separator':
			case 'heading':
				$html = self::_('item_separator', $vars);
				break;
			case 'component':
				$html = self::_('item_component', $vars);
				break;
			case 'url':
			default:
				$html = self::_('item_url', $vars);
		}

		return $html;
	}

	static function item_url($vars)
	{
		$item     = $vars['item'];
		$class    = $vars['class'];
		$rel	  = $vars['rel'];
		$title    = $vars['title'];
		$dropdown = $vars['dropdown'];
		$caret    = $vars['caret'];
		$linktype = $vars['linktype'];
		$icon     = $vars['icon'];
		$caption  = $vars['caption'];

		$flink = $item->flink;
		$flink = JFilterOutput::ampReplace(htmlspecialchars($flink));

		switch ($item->browserNav) :
			default:
			case 0:
				$link = "<a itemprop='url' class=\"$class\" $rel href=\"$flink\" $title $dropdown>$icon$linktype$caret$caption</a>";
				break;
			case 1:
				// _blank
				$link = "<a itemprop='url' class=\"$class\" $rel href=\"$flink\" target=\"_blank\" $title $dropdown>$icon$linktype$caret$caption</a>";
				break;
			case 2:
				// window.open
				$options = 'toolbar=no,location=no,status=no,menubar=no,scrollbars=yes,resizable=yes';
				$link = "<a itemprop='url' class=\"$class\" $rel href=\"$flink\"" . (!$vars['menu']->editmode ? " onclick=\"window.open(this.href,'targetWindow','$options');return false;\"" : "") . " $title $dropdown>$icon$linktype$caret$caption</a>";
				break;
		endswitch;

		return $link;
	}

	static function item_separator($vars)
	{
		$item     = $vars['item'];
		$class    = $vars['class'];
		$title    = $vars['title'];
		$dropdown = $vars['dropdown'];
		$caret    = $vars['caret'];
		$linktype = $vars['linktype'];
		$icon     = $vars['icon'];
		$caption  = $vars['caption'];
		// Note. It is important to remove spaces between elements.

		$class .= " separator";

		return "<span class=\"$class\" $title $dropdown>$icon$title $linktype$caret$caption</span>";
	}

	static function item_component($vars)
	{
		$item     = $vars['item'];
		$class    = $vars['class'];
		$rel	  = $vars['rel'];
		$title    = $vars['title'];
		$dropdown = $vars['dropdown'];
		$caret    = $vars['caret'];
		$linktype = $vars['linktype'];
		$icon     = $vars['icon'];
		$caption  = $vars['caption'];
		// Note. It is important to remove spaces between elements.

		switch ($item->browserNav) :
			default:
			case 0:
				$link = "<a itemprop='url' class=\"$class\" $rel href=\"{$item->flink}\" $title $dropdown>$icon$linktype $caret$caption</a>";
				break;
			case 1:
				// _blank
				$link = "<a itemprop='url' class=\"$class\" $rel href=\"{$item->flink}\" target=\"_blank\" $title $dropdown>$icon$linktype $caret$caption</a>";
				break;
			case 2:
				// window.open
				$link = "<a itemprop='url' class=\"$class\" $rel href=\"{$item->flink}\"" . (!$vars['menu']->editmode ? " onclick=\"window.open(this.href,'targetWindow','toolbar=no,location=no,status=no,menubar=no,scrollbars=yes,resizable=yes');return false;\"" : "") . " $title $dropdown>$icon$linktype $caret$caption</a>";
				break;
		endswitch;

		return $link;
	}

	static function _($tmpl, $vars) {
		if (function_exists($func = 'T3MenuMegamenuTpl_'.$tmpl)) {
			return $func($vars) . "\n";
		} else if (method_exists('T3MenuMegamenuTpl', $tmpl)) {
			return T3MenuMegamenuTpl::$tmpl($vars) . "\n";
		} else {
			return "$tmpl\n";
		}
	}
}menu/t3bootstrap.tpl.php000060400000016223152455303030011303 0ustar00<?php
/**
 *------------------------------------------------------------------------------
 * @package       T3 Framework for Joomla!
 *------------------------------------------------------------------------------
 * @copyright     Copyright (C) 2004-2013 JoomlArt.com. All Rights Reserved.
 * @license       GNU General Public License version 2 or later; see LICENSE.txt
 * @authors       JoomlArt, JoomlaBamboo, (contribute to this project at github
 *                & Google group to become co-author)
 * @Google group: https://groups.google.com/forum/#!forum/t3fw
 * @Link:         http://t3-framework.org
 *------------------------------------------------------------------------------
 */

class T3BootstrapTpl
{
	static function render($list)
	{
		$base      = T3Bootstrap::getBase();
		$active    = T3Bootstrap::getActive();
		$active_id = $active->id;
		$path      = $base->tree;

		?>
		<ul class="nav navbar-nav">
			<?php
			foreach ($list as &$item) :
				$ItemParams = version_compare(JVERSION, '4', 'ge') ? $item->getParams() : $item->params;
				$item->itemParams = $ItemParams;
				//intergration with new params joomla 3.6.x (menu_show)
				$menu_show = (int)$ItemParams->get('menu_show', 1);
				if ($menu_show!=1)
					continue;
				$class = 'item-' . $item->id;
				if ($item->id == $active_id) {
					$class .= ' current';
				}

				if (in_array($item->id, $path)) {
					$class .= ' active';
				} elseif ($item->type == 'alias') {
					$aliasToId = $ItemParams->get('aliasoptions');
					if (count($path) > 0 && $aliasToId == $path[count($path) - 1]) {
						$class .= ' active';
					} elseif (in_array($aliasToId, $path)) {
						$class .= ' alias-parent-active';
					}
				}

				if ($item->type == 'separator' || $item->type == 'heading') {
					$class .= ' divider';
				}

				if ($item->deeper) {
					if ($item->level > 1) {
						$class .= ' dropdown-submenu';
					} else {
						$class .= ' deeper dropdown';
					}
				}

				if ($item->parent) {
					$class .= ' parent';
				}

				if (!empty($class)) {
					$class = ' class="' . trim($class) . '"';
				}

				echo '<li' . $class . '>';

				// Render the menu item.
				switch ($item->type) :
					case 'separator':
					case 'url':
					case 'component':
					case 'heading':
						echo self::item($item->type, $item);
						break;

					default:
						echo self::item('url', $item);
						break;
				endswitch;

				// The next item is deeper.
				if ($item->deeper) {
					echo '<ul class="dropdown-menu" role="menu">';
				} // The next item is shallower.
				elseif ($item->shallower) {
					echo '</li>';
					echo str_repeat('</ul></li>', $item->level_diff);
				} // The next item is on the same level.
				else {
					echo '</li>';
				}
			endforeach;
			?>
		</ul>
	<?php
	}

	public static function item($type, $item)
	{
		if (method_exists(__CLASS__, $type)) {
			return self::$type($item);
		} else {
			return $type;
		}
	}

	public static function component($item)
	{
		// Note. It is important to remove spaces between elements.
		$class    = $item->anchor_css ? $item->anchor_css : '';
		$title    = $item->anchor_title ? 'title="' . $item->anchor_title . '" ' : '';
		$caret    = '';
		$dropdown = '';

		if($item->deeper && $item->level < 2){
			$class    .= ' dropdown-toggle';
			$dropdown  = ' data-toggle="dropdown"';
			$caret     = '<em class="caret"></em>';
		}

		if(!empty($class)){
			$class = 'class="'. trim($class) .'" ';
		}

		if ($item->menu_image) {
			$item->itemParams->get('menu_text', 1) ?
				$linktype = '<img class="' . $item->menu_image_css . '"  src="' . $item->menu_image . '" alt="' . $item->title . '" /><span class="image-title">' . $item->title . '</span> ' :
				$linktype = '<img class="' . $item->menu_image_css . '"  src="' . $item->menu_image . '" alt="' . $item->title . '" />';
		} else {
			$linktype = $item->title;
		}

		switch ($item->browserNav) :
			default:
			case 0:
				?>
				<a <?php echo $class; ?>href="<?php echo $item->flink; ?>" <?php echo $title, $dropdown; ?>><?php echo $linktype, $caret; ?></a>
				<?php
				break;
			case 1:
				// _blank
				?>
				<a <?php echo $class; ?>href="<?php echo $item->flink; ?>" target="_blank" <?php echo $title, $dropdown; ?>><?php echo $linktype, $caret; ?></a>
				<?php
				break;
			case 2:
				// window.open
				?>
				<a <?php echo $class; ?>href="<?php echo $item->flink; ?>" onclick="window.open(this.href,'targetWindow','toolbar=no,location=no,status=no,menubar=no,scrollbars=yes,resizable=yes');return false;" <?php echo $title, $dropdown; ?>><?php echo $linktype, $caret; ?></a>
				<?php
				break;
		endswitch;
	}

	public static function heading($item)
	{
		?>
		<span class="nav-header"><?php echo $item->title; ?></span>
		<?php
	}

	public static function separator($item)
	{
		// Note. It is important to remove spaces between elements.
		$title = $item->anchor_title ? ' title="' . $item->anchor_title . '" ' : '';
		if ($item->menu_image) {
			$item->itemParams->get('menu_text', 1) ?
				$linktype = '<img class="' . $item->menu_image_css . '"  src="' . $item->menu_image . '" alt="' . $item->title . '" /><span class="image-title">' . $item->title . '</span> ' :
				$linktype = '<img class="' . $item->menu_image_css . '"  src="' . $item->menu_image . '" alt="' . $item->title . '" />';
		} else {
			$linktype = $item->title;
		}

		?>
		<span class="separator" <?php echo $title; ?>><?php echo $linktype; ?></span>
		<?php
	}

	public static function url($item)
	{

		// Note. It is important to remove spaces between elements.
		$class    = $item->anchor_css ? $item->anchor_css : '';
		$title    = $item->anchor_title ? 'title="' . $item->anchor_title . '" ' : '';
		$caret    = '';
		$dropdown = '';

		if($item->deeper && $item->level < 2){
			$class    .= ' dropdown-toggle';
			$dropdown  = ' data-toggle="dropdown"';
			$caret     = '<em class="caret"></em>';
		}

		if(!empty($class)){
			$class = 'class="'. trim($class) .'" ';
		}

		if ($item->menu_image) {
			$item->itemParams->get('menu_text', 1) ?
				$linktype = '<img class="' . $item->menu_image_css . '"  src="' . $item->menu_image . '" alt="' . $item->title . '" /><span class="image-title">' . $item->title . '</span> ' :
				$linktype = '<img class="' . $item->menu_image_css . '"  src="' . $item->menu_image . '" alt="' . $item->title . '" />';
		} else {
			$linktype = $item->title;
		}
		$flink = $item->flink;
		$flink = JFilterOutput::ampReplace(htmlspecialchars($flink));

		switch ($item->browserNav) :
			default:
			case 0:
				?>
				<a <?php echo $class; ?>href="<?php echo $flink; ?>" <?php echo $title, $dropdown; ?>><?php echo $linktype, $caret; ?></a>
				<?php
				break;
			case 1:
				// _blank
				?>
				<a <?php echo $class; ?>href="<?php echo $flink; ?>" target="_blank" <?php echo $title, $dropdown; ?>><?php echo $linktype, $caret; ?></a>
				<?php
				break;
			case 2:
				// window.open
				$options = 'toolbar=no,location=no,status=no,menubar=no,scrollbars=yes,resizable=yes,' . $item->itemParams->get('window_open');
				?>
				<a <?php echo $class; ?>href="<?php echo $flink; ?>" onclick="window.open(this.href,'targetWindow','<?php echo $options; ?>');return false;" <?php echo $title, $dropdown; ?>><?php echo $linktype, $caret; ?></a>
				<?php
				break;
		endswitch;
	}
}
depend/images/apply.gif000060400000001116152455303030011057 0ustar00GIF89a���1��S{�@��J������������������������k��V��E����͊�R�꒠�c��U�ವꁢ�k�摈�4��������u�4}�>��l���퉡�`��p��L��N��8��U��z�B��㋾\t�8����ю��k��g��r�ψ��L��������~����ʂ�+���z�>��]�������J��q��ز�y������߱�ӓ�ם��ܯ�{w�.~�;��Jw�9��K��Ι�Rm�)���S������@}�G�߯��J��^��\��g��m����Ј��ts�7��T��X��n��a��w�ͅ��kw�;�����P�ܩ��f�����~��7�⺔�i��ȑ�F��-��i���m�1y�<����\���!�,�����aY��N]9��HSv��@.Kw_lJ�32)[50�:gx+�`�%R �/u&G�o>h-�*b2jCA;$OQ�|TDfk{k~Xei�Z1n#BE8^cW�4	!sI�=U(yPڌ�r���&t4�@p�&\��q�A�4��}D`p1;depend/images/close-all.png000060400000001064152455303030011626 0ustar00�PNG


IHDR;mG�gAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDATxڬT�n�@\�tt �@І�/�h�)�)�)�BA�%|5U���!A$c>�]v��C�DYi�{��9�Wg���ӗ�b�5F�Qd�F��e�>)`��6��c:���r��ۭVJ��5�c�#����x<V���S�}�0�v��
��R�dљ1�L�|>���7�d2��|�l��A�z.����x��A�Z6����NWK`�i�&�}��h4N�[�-�N���¤��Hɐ��,���i��Xa2�l6�d2�'5�ͨSGET��04Y�g0���9�O�t�����VH�������rV�C׬C���������J���ѱ��p�hWl�}=F<A�v]W��k�Ch��g���ru�:�aBΥ��W{|�.�!�� ��ZqV�BI�_,��C���t�G;��w���<�'U����y�0�!�!�m�w��GM���]��AM4� �+IEND�B`�depend/images/arrow-blue.png000060400000000234152455303030012030 0ustar00�PNG


IHDR�3^gAMA��7��tEXtSoftwareAdobe ImageReadyq�e<.IDATx�bT����
���t� �X]C#�#�
��a��1Da�IEND�B`�depend/images/normal-check.jpg000060400000001550152455303030012312 0ustar00���JFIFdd��Duckyd��Adobed��������n
%!"AQ1���?�=6e�/ �X�9�,9.NbY)��8���AU�!����X�ϐ�����/�qj��ҳ1���q�e2Ҥ4�RY����5Ӯ���bB�A��u����IL�e���G�΀jH�e��~�m̃�b��X��e�]w9��hځ6Ię\�,K���=�d���b8�9�?��<��9
�f:OԸ:3Ns,�:��%�RǾ�kQd��n��s7⸱J�M`ǜ�b8�&��VUcr��[f�v�k��&�71�2;W�A�E��9
9��cM�E�kR-\n���h���:���Ty
�3��Q���^=s��ai���6H��!d�H�13ɩh�����ާ�Ψ�N,tBZ0�f̥�r��B�
��;�c����cud.�x�!1y�Xt�Å��z�?���6�O�=u�	��0qmZ3ᵡ-O(�m����$g�����?^�<b��l�y�n+d�*�Y�Y��X�XV��D)'�}	���+<��g3V��V�o^��*�AX�B��I]]�%���depend/images/message-bg.gif000060400000000163152455303030011745 0ustar00GIF89ag�������������������������������!�,g 0�I��X��y�`1������ᾄ �b�w��;depend/images/popup-list.gif000060400000000241152455303030012044 0ustar00GIF89a����������������������������������Ƴ�������������!�,`$�-9�(�q$
�Ń
��;depend/images/block-head.gif000060400000000140152455303030011717 0ustar00GIF89a�������������������������������!�,
PI �D�4
	�qD;depend/images/themes-default.gif000060400000000545152455303030012646 0ustar00GIF89a����rr����bb������������ff�dd�ii��������������������uu�yy��������cc�jj�tt�tt�kk���nn��������__�����^^������xx��������������������������������]]���!�,�@�pH,�jȤ2)�9�Ч�F�ZC�P��v	7�L+�c�M��p��FǼ��<c�R%�7-B&%7
Bt7$�B,'(7"�7,�,B..�)+��B0�7��B3�3��F�CA;depend/images/index.html000060400000000054152455303030011240 0ustar00<html><body bgcolor="#FFFFFF"></body></html>depend/images/icon-save.png000060400000001320152455303030011632 0ustar00�PNG


IHDR�agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<bIDATxڤS�KSQ��s7�RG]C�,��iH4	}���~=�EH�Q�?�V���z��A�(�
Wl���mj��5���s��\�� 5��9���|?��J�e����S����M��p�#oM`�H߹KR登��r��@�i�틡�)o���x�Ў��0M��p�� k[��Ln��O��2��g[������1x��m&F_�'1��M
H�'/8,N%.rTT�gK���"����t#:�js�TɁ�Q�ݛ0Ɛ�y��:1;�	����?H��^��eyS�
?��z>k�׃�z���I6P�"�����|*	)�6T!���U\IJ^Q|�t�����A�,��Z=rcCxoB����o�h�4|��v?E#㠚5l��[$�C�_pqX�6 �5���t2�T�=��+��q�@?�������}`�B	y%/� 1A��ƇF�:j���f��l�A�_!J#h���38%{+���f�\A�8a���(�L���X�,T�qIDh3i.BASx��C�����_Ԅ�]�Ř���KvЇN޹Ed�y�$gq���Ǫ*VBu�MvI�25-��iq6%��j�o�`w�5c�-R�IEND�B`�depend/images/icon-moved.png000060400000000655152455303030012020 0ustar00�PNG


IHDR

�2ϽgAMA��7��tEXtSoftwareAdobe ImageReadyq�e<?IDATx�TP�K�Q��{_5��\,��!��!����rn�������?�9��Ƣ�� �P"��IId���Fup�{|>w�����h�a����/�Պ�c�O�b�t"�$�ܰ��2�`�!xF��f�9�	�?�{���͆'�"J�x�yr�O�>���aX���@��v)��g� mh��`�Z,G��,�QN��&�V��}���o�̹*��}\YUi��̶�X7�7�*.�Ϋ��p��i��Ԁ��2��a��(}!�(;:��aM]M�L��t�[O�;O��t�*���R��-���{98�IEND�B`�depend/images/tooltip-bg.gif000060400000000514152455303030012013 0ustar00GIF89a�������������������������������������������������������������!�,�i@�p*���2�i:;���B�f�؉V��v`0a<F�͆t��fC��\��#�Ha�w����������������������������!���
��A;depend/images/icon-move.png000060400000000771152455303030011653 0ustar00�PNG


IHDR

�2ϽgAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDATx�,�=K#Q�ϝ{�ɘ��d7"*�JVR�����?A����[+�V���.�h'���#"�.��h �x��3�c>������
�50L�T
4Ls�Ć��ҫH��m|4x)���fi(5՝Fk��g�R����0T��c��y��|���7����O�1p�)-ՀG�T1�����:��t� �ƖO�����e��$�$��}�w~��HQ�[e�����Uc���T
����]�6�]ەE�j�p��&����׿(�m+ࢎz���ә/�*n'm�뚠6��G�T�'4���4�b���\1�S�]bǛ�>���\���v��ܼ�r��f�m�l���x3�n�/�	 �/�ӸA�_�D<D��-�u��IEND�B`�depend/images/table-bg.gif000060400000000160152455303030011405 0ustar00GIF89aL�������������������������������!�,L0�I���Ï�F(�B`H��C;p!DM$;depend/images/grad.png000060400000000225152455303030010666 0ustar00�PNG


IHDR!��V�gAMA��7��tEXtSoftwareAdobe ImageReadyq�e<'IDATx�b���?�ϟ?�@4�� ��M�6.1( �;���IEND�B`�depend/images/del.gif000060400000000131152455303030010472 0ustar00GIF89a
����������!�,
*�y���T؋��Q�|=�f}�x�*J�'⮰)�4����'*;depend/images/success-bg.gif000060400000000300152455303030011762 0ustar00GIF89ag��������������������������������������������������������!�,g=`'�YY6[�^,��&�IBTNE|4����p0$H�`	iB&�I��@T�W����v9��B&;Ύ;depend/images/icon-success.png000060400000003057152455303030012355 0ustar00�PNG


IHDR�ʄgAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDATx��VklTE��c��m)�E[(F�VS( ��
&�h4>�D~���ƄHD|%E4��h�A�@-5����؂E�Rؖ�}ܽ��3���[v��N2��{�|�|�;gFB�jM�.o���:JM�|P�>�MC��
���dҁUP��aֳ��G��)/y��
��k�{�nbV�ʯ����@���2^
�:�c*�����G�����ٖ*��< D6��\$�ie�a�W9�}?+f8/��O?C��`��i�"�N�E���mV�����v�./�t9�i�
L�5
���Շ�5��^�C���C�i���PY�Y��dwVPN�\�O��)��q�e����i��>U�3!<��j�$'�p,�9�yzCVz!q�heB���GF=���3tZ��u\r�q_�!=A�#¡4iY�C��>�j�S�(�.eD9A}%�	�L�'2RW���ꂏbs~vP���#��	��z�7.(�Mĺ�ѣ&P[�õm%�}1"p���D*�%@Y	���9D��4Nk^Xs/��(=5���v2�WP\Ǯ���n�+�L��K�JZ��L�Vʢ|�ϲGJ��M������.$�j��5�<�/nņ��#ˋogFJ�2R�Q����Θ������Z���8Kk|i�3�ZOވ�GU����̩T/���t����<sI=�x<��z������!F�V��b���0/�^�h�J�&=����εO��n��iݎX�����/+)?���B��(�XzQ@���n�ڬ�(Aەm�y�&��˺���Hq[��4�&5M�d�2�S��#EzT삄t��=;�J�q�ƁcSѳG�.wQ}�$�~�hi*�y�M8�d;�t��N�"9,�4���'1��3@��pI�s���y�����/��-�n�	ϕ�����N�U�I�mŋQ��Z���j�q���H)�r�)���r�mt]S�j#tv�?�hK��!+�ޒC�k҃(Ћ�Qt3αa���fT�߈�m!�;�-�2�\��ѧ.ڟ���q�T�(��X,׆�J㞷�b_��b�.��Ճw;�@ix:
*���:}��k �����H=���#�<���so����I�;�l�1�w��b�|�<����Hq'�bj�k���gS^)>��f��]�(udN� ��&RR�3����T���Wq��
�,d����u"�h(0�)W�4���Օ��mo��1�7
{�^+���L�)�i�,lx�e�ҷI�OU>��*�>���F��p���{LR�a���u��1wA#�STbAN��z�;l�0T1��;�R_
k�U6�-��JY�M%������B�AJf�)|O핗1�N��<�Uu��`���d�+����?,a�&�*<%�:u�6�ځG�|I
r��/Cv���Zr���Rɝi�[��������K������JeIEND�B`�depend/images/open-all.png000060400000001117152455303030011461 0ustar00�PNG


IHDR;mG�gAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDATxڬT�J�@��iZJ{іx(����E_��E�)ԃ>�x�.҃�)<�=,�?/��!�lv�6M�"EŁ���~�mf'�����1�
���2��6��)"Zk�����<OO�S��2k<�>x9"��z��
�@/3�~"b��9,����jբZ��ף���V
w���OJ�ҷ��{��>�@��^�X������<�C�Q(�/6�k�hc6�#�%�l]=|[Vb���r.��r"�t*EJFD�{��4L+�Ʋ��d2Y�d2s���F0s��ńݣM�/��2���!D���"ק��."1N�A�f�!�f�����f�+	���jǹY]Y�;�C�X�p���+�!���S�h�æ���P3D����q�&�o�f�&�!B���W;��ΐ�]�Rr��+R�$��f��u��q'�ijs��0
�8�N��-۶)�m��@<q�d~�'<.�?�'���X{��5�IEND�B`�depend/images/block-setting.gif000060400000000140152455303030012473 0ustar00GIF89a����������������������������������!�,
p�I0#��H�;depend/images/icon-message.png000060400000003102152455303030012320 0ustar00�PNG


IHDR�ʄgAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDATxڤV]lE=����?J�-X�B�)%�V1�15Q� &������M��F���P"RT��6B��6�?����;�3���%�T�޹wvvg�|�;�����.��g�$��P���]njMx�}FH&}�����P��Ʋ�㏕�y7ױ��n����.�>����j2�����;Σmj)v��V�wv�4�<�>ݒ\ �k4�!hhILB�LQe���M`��䐉0�l�*(��^��9��²�ݗ�~�\���D 1��h#H�Ӌek����ҍSeuh�}N�h�<	K*���+��鉲՟���*	*�M*c6%������P8�����Y5J�Ef�&g̗X9�r���*"Ɉ��ʈ"$��B�Y���9� D�
�22s�'Z��d��*t������fڴ��P[�4"(�\*��hK�ε��$s��2�qGz��'!+1!h��k9�V�!�By�����}G*-pj#�X��%����->�YA�9�헟�
��J���B{��W�T�F�S�jz���h�� `f����^1�lRC8���{a�2���YLaK��H[�E���q�����ɋ�ĭ\�m��s"�:=��ѷ�-��O}�F��8ܞ6$����1���G�O gW!X�R���&$�F+7)$��1�G���O���w{�b7Y+pTV�\-!-�(�VrM@�c�EL��?:��iW�X��?�
���?��l;k���w�n
�OI��"�]QH�N���ޫ&t��g���=��Ƀ�~�y�.wV�Ã��7���߆c�k@^Ka�U\��\,ҹs��I��F~P������k�M���L]��Ethi��~�=d:�h�>N$ۖk�qm8	9�.�My	��Dϑ�~l3:Z/����&���e~FK)rZ�?ۇ8�K]�ԃ�J!�Mx�c�|��'E:}�>�f{e� ����;Θ���p%*V?����h�R˶��&��^!�_kj���*�Ê-5�GAL_��S?Qg3�:Q�|
p�u&��x�9�>����${�7:V�>�iv)��OE�SA�ܲ/;�B���mۙ����d_�Uo؊S���W�p��8�Q��|��B��'�WW�%����̽n��n\Ѕ5��=�5��e*�#)�>^�1�ln���|���4?�ivE����t�!�>���.b>ub��Һ�/����f/,:��B�B�kO�qS8��f�����F{�\�X�a;98�$�$�7:�<*1�Ɵ-<XbV���,��Kb��v,X�0г�*d#Hn.^ڵ�4ݏ�
�;�]{J��J֜�Q�W�D��iEL��ĉ~S�!<�@	�+[Y�8�j�$$�l�c�i��
���*�i��]'~�a)5�<{�:U�\Y:�]�#�t��̩�Z��Ι�n��_uм�)���J��x/z\�g���e����,�
��\�0LH�Ke��IEND�B`�depend/images/tabs-setting.gif000060400000000152152455303030012335 0ustar00GIF89a%�����������������������������������������������!�,%𕲪�ư
�9Ҝ���N;;depend/images/cancel.gif000060400000001126152455303030011160 0ustar00GIF89a�G������������h�P.쩛�J(�`D����K)�?�pU���]�nO�I'옆����wU��vW�qO��p�<�{Y�2�[9�R0�U3�cA�L1����E&��j��w��`�H&�A�M+����}�G%�:�dB�^<�lJ��b�cA�rP����]B�u^��kS��q�����Ÿ��d��j�d�b@����a?��{�W=����"�fD���!�G,��G�����(FF(�G	$#DD#$	�2.%EE%.2�"?C5�7FD"�13:��E1�6��4�*/�DEG/*�&G���G&�,8��@,�
0�9>0
� !<���G!@���D�<�8��B!V���
 5H�Aԇ
 �,;depend/images/admin-bg.gif000060400000000247152455303030011414 0ustar00GIF89aC����������������������������������������������������������������������������������������!�,C$ '�di���h��S�D(�eTeY��pp�	�;depend/images/level2-block.gif000060400000000107152455303030012212 0ustar00GIF89a�������������������������!�,x�[^�H!��`�;depend/images/level1-block.gif000060400000000152152455303030012211 0ustar00GIF89a%�����������������������������������������������!�,%𕲪�ư
�9Ҝ���N;;depend/images/bt-close.gif000060400000001215152455303030011442 0ustar00GIF89a�����˥�Ѭ�������ʤ�ž����������۾���ǡ����Ğ����ɣ�̭�Ы����Ş����›����߻���ӹ�����������Ȩ�ϲ����Ժ�ջ�Ƥ����������β����������Ǧ������������ϳ�ţ������ռ�Ի����Ģ�������������������������!�,�C��

���E���������
��E
�������3!�C	�&@9�
6)4�	?�+DD�<�D'���7�0�;�������8�/��,�BƠA�ꦡʁP-��H7m.Kz�Z0�]>��pq�@{Et,�q�Ă	�$R뒈��:���K�P�$H��� �zT�U�8
!�dJ
<�A����J(lp);depend/images/arrow-list.gif000060400000000061152455303030012033 0ustar00GIF89a�mmm���!�,�o�z
Y(;depend/images/arrow-level1.png000060400000000226152455303030012272 0ustar00�PNG


IHDR�3^gAMA��7��tEXtSoftwareAdobe ImageReadyq�e<(IDATx�b```��t� #.-8��m��f	��IEND�B`�depend/images/icon-default.png000060400000000622152455303030012324 0ustar00�PNG


IHDR

�2ϽgAMA��7��tEXtSoftwareAdobe ImageReadyq�e<$IDATx�T��jA��YVW���J��D}����v>��]R'��H�h�`!Ia'�Q�,����73�Ʌa���{���v�R�A��R*��{�m��m�{�}S��ı�b!�1���I�u�	Ca�߿*}�`�!���Ry��8N>Y.a��l���j>'�4�lF�h aH��!�"�x�?����}�ZE�u䶆��P�.�jHiES����S�
���ᒆ�,`|�Q�+�5��D��4c��(nn�m�e��J���
dzөR�fs����B��UO��
0��S�~3IEND�B`�depend/images/copy.png000060400000001033152455303030010721 0ustar00�PNG


IHDR�a�IDATx�cd��iG��a�n\�0)�z����?dyF(�ҹ���B[6�G~���Ƿ�,��d��?Ȇ�`���g�=Â�	���2h�0��������k�7�3��h��M��`΢����[0����Ï�^�K��0|���w�ۊb܀��~L��pz�31靟pB~�1��/��w�a�y�B��?��>~U ��S��20222�db�y��3�����߿Ż�D
��
�[����+��3����i�����ay�@��+>��u��mfb�y��~e���ư&^ ����r�2����0��v��\�bȳ�@l	��@ffiy�k�`(��̰(
�&�+������y�:�A�V���(0B1�;_aށ{�����0'�?(t[�y��m�45�d���Ď����j�/N������RIEND�B`�depend/images/level2-close.gif000060400000000144152455303030012226 0ustar00GIF89a������������������!�,P�f�m��œG�q($��;depend/images/toggle-btn.png000060400000000366152455303030012021 0ustar00�PNG


IHDR+1��gAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDATxڴ��
� Cq���S�JUhC|!>�%a�j�GJ)��n�[�1^sJ�es�A~.�i^�Ɋ������ڠٶ�]<���
	����}v�n��l����0�&+DHm��I��g/�d���v
0˛)\�S�IEND�B`�depend/images/lightbulb.png000060400000002730152455303030011730 0ustar00�PNG


IHDR  szz�tEXtSoftwareAdobe ImageReadyq�e<zIDATxڴWklU�����n�,�ݾl����H4�D"���?F��|���??��AI�B�DM��"��Z
%�
"h��mwwv��}�x��
����=��{^�9��s�J�ib�!I�T���m+�pɢ��
&���l(�16=�⾏iɘJy*_R���[V<體�*�f
̬r�Eۏ$�d�GXϬZ��}/����O<�T�l�?_
�4�}�Z���[��#��L�@����;&g�R������ﮆ��^H��¤�ad&H�B&c�6�B�̩�c�Տ�޾gBp*_N�z��{^K�
���`f�d){5�W�d�Ŀ�ע����SA��΁(�\�tE���
^Py�Հ�����kijdH�uX�m�S(.�WY;�_E�sQ�3d��^_[��@|[�tX�?^K��D���B��j�ˌSƓ�i�~H�	�dA����c[�pJ�	��Ez��\JW20QTWO�DΩ;����:Մd�#
F��bE��0�v��y
{ϓ��E<�5�G2����L�Њ;�i3�+S�B��"%p��sX~_M�1��֚B <0,���-|�
�͈�>�G�(�|4�T:�*�-��6��c�,�9�1�e�+`]�Q�jHw��ڴ�A@�r����䷃k#�<�ט�2,�:��6�V9R��{��._�'��P-'�A�rK����~;�5�˲�
�UV��>�y�5:x��.̩��b؄��,[�s^c˰,�.�(7�o�7?�;��}q�����j}�V�G�3��s���eXvW��u��6ʭ|㌾���m�/�	D;r�����~��0W��Z<���om��{ d�@�L�"~mc��A�G-x�J75��M@��c�����)�̚���$���k��y�
���<>OQS���	a]���L�cA���d/٭׼��b\����h.q���_B�.�}�6`�������S�A��e�ղiNg_��č�����`�I�NMs�O7����h���'�ekT*�U,o�����z*9��A:�C4#�B�c�i�}�?xs5�g�y��O��P@Q\��lzLG<G2N�xz<��d�%"v�k��C
�~4�Q�DJG6���ٍh��AL��iƮ��=P��R2��5r��9J�K�,��@�ѣ��9��Ę����z��W��`�\T�g�����������Т�֛��::�{�����ѥ��<��A,��i�l\0:K9%�_�[�]���[�)�����–4Ͻ��P�g�^S���c8��*���ϼ���x���Z�뻯6�s~�E�:�7��t��.�#j��<�W	��on��E&2���Ӟ�.�B�`�@~ga�#_IEND�B`�depend/images/del2.gif000060400000001007152455303030010557 0ustar00GIF89a�J�F7�S?�F6�g[���������û��6��1�6"������������F3��}؅}�7&�.�wv�������dO�ws�"�re�4��޾���WB�,�����ȣ�����џ���}k¸����ƻ��������G2�����۸{x����0���������ò�����2����������w�)�����뤛��̹XLՀu���\Q����ӿ��!�J,@d�GJ��$	
+�JF6�J?�.D1'%�#�H@9
)�,�*4J/>A7�3&0"JE!8<�J2=�;- (�C�B�5�:IȆ�;depend/css/index.html000060400000000054152455303030010563 0ustar00<html><body bgcolor="#FFFFFF"></body></html>depend/css/depend.css000060400000000000152455303030010526 0ustar00depend/helper.php000060400000004257152455303030007777 0ustar00<?php
/** 
 *------------------------------------------------------------------------------
 * @package       T3 Framework for Joomla!
 *------------------------------------------------------------------------------
 * @copyright     Copyright (C) 2004-2013 JoomlArt.com. All Rights Reserved.
 * @license       GNU General Public License version 2 or later; see LICENSE.txt
 * @authors       JoomlArt, JoomlaBamboo, (contribute to this project at github 
 *                & Google group to become co-author)
 * @Google group: https://groups.google.com/forum/#!forum/t3fw
 * @Link:         http://t3-framework.org 
 *------------------------------------------------------------------------------
 */

if (!defined('_JEXEC')) {
    // no direct access
	define('_JEXEC', 1);
	defined ( '_JEXEC' ) or die ( 'Restricted access' ); 
	$path = dirname(dirname(dirname(dirname(__FILE__))));
	define('JPATH_BASE', $path);

	if (strpos(php_sapi_name(), 'cgi') !== false && !empty($_SERVER['REQUEST_URI'])) {
        //Apache CGI
		$_SERVER['PHP_SELF'] = rtrim(dirname(dirname(dirname($_SERVER['PHP_SELF']))), '/\\');
	} else {
        //Others
		$_SERVER['SCRIPT_NAME'] = rtrim(dirname(dirname(dirname($_SERVER['SCRIPT_NAME']))), '/\\');
	}

	require_once (JPATH_BASE . DIRECTORY_SEPARATOR . 'includes' . DIRECTORY_SEPARATOR . 'defines.php');
	require_once (JPATH_BASE . DIRECTORY_SEPARATOR . 'includes' . DIRECTORY_SEPARATOR . 'framework.php');
	JDEBUG ? $_PROFILER->mark('afterLoad') : null;

	/**
	 * CREATE THE APPLICATION
	 *
	 * NOTE :
	 */
	$japp = JFactory::getApplication('administrator');

	/**
	 * INITIALISE THE APPLICATION
	 *
	 * NOTE :
	 */
	$japp->initialise(array('language' => $japp->getUserState('application.lang', 'lang')));
}

$user = JFactory::getUser();

jimport('joomla.filesystem.folder');
jimport('joomla.filesystem.file');


if(!$user->authorise('core.manage', 'com_templates')){
	die(json_encode(array(JText::_('NO_PERMISSION'))));
}


$helpcls = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'fileconfig.php';
if(file_exists($helpcls))
include_once $helpcls;

$task = isset($_REQUEST['dptask']) ? $_REQUEST['dptask'] : '';
if ($task != '' && method_exists('JAFileConfig', $task)) {
	JAFileConfig::$task();
}depend/t3form.php000060400000010751152455303030007726 0ustar00<?php
/** 
 *------------------------------------------------------------------------------
 * @package       T3 Framework for Joomla!
 *------------------------------------------------------------------------------
 * @copyright     Copyright (C) 2004-2013 JoomlArt.com. All Rights Reserved.
 * @license       GNU General Public License version 2 or later; see LICENSE.txt
 * @authors       JoomlArt, JoomlaBamboo, (contribute to this project at github 
 *                & Google group to become co-author)
 * @Google group: https://groups.google.com/forum/#!forum/t3fw
 * @Link:         http://t3-framework.org 
 *------------------------------------------------------------------------------
 */

use Joomla\CMS\Form\Form;

// No direct access
defined('_JEXEC') or die();

/**
 * Radio List Element
 *
 * @package  JAT3.Core.Element
 */
class T3Form extends Form
{

	public function __construct($name, array $options = array()){

		if($name instanceof Form){
			
			foreach($name as $property => $value) {
				$this->$property = $value;
			}

		} else {
			parent::__construct($name, $options);
		}
	}


	/**
	 * Method to load the form description from an XML string or object.
	 *
	 * The replace option works per field.  If a field being loaded already exists in the current
	 * form definition then the behavior or load will vary depending upon the replace flag.  If it
	 * is set to true, then the existing field will be replaced in its exact location by the new
	 * field being loaded.  If it is false, then the new field being loaded will be ignored and the
	 * method will move on to the next field to load.
	 *
	 * @param   string  $data     The name of an XML string or object.
	 * @param   string  $replace  Flag to toggle whether form fields should be replaced if a field
	 *                            already exists with the same group/name.
	 * @param   string  $xpath    An optional xpath to search for the fields.
	 *
	 * @return  boolean  True on success, false otherwise.
	 *
	 * @since   11.1
	 */
	public function load($data, $replace = true, $xpath = false)
	{
		// If the data to load isn't already an XML element or string return false.
		if ((!($data instanceof SimpleXMLElement)) && (!is_string($data)))
		{
			return false;
		}

		// Attempt to load the XML if a string.
		if (is_string($data))
		{
			try
			{
				$data = new SimpleXMLElement($data);
			}
			catch (Exception $e)
			{
				return false;
			}

			// Make sure the XML loaded correctly.
			if (!$data)
			{
				return false;
			}
		}

		// If we have no XML definition at this point let's make sure we get one.
		if (empty($this->xml))
		{
			// If no XPath query is set to search for fields, and we have a <form />, set it and return.
			if (!$xpath && ($data->getName() == 'form'))
			{
				$this->xml = $data;

				// Synchronize any paths found in the load.
				$this->syncPaths();

				return true;
			}
			// Create a root element for the form.
			else
			{
				$this->xml = new SimpleXMLElement('<form></form>');
			}
		}

		// Get the XML elements to load.
		$elements = array();
		if ($xpath)
		{
			$elements = $data->xpath($xpath);
		}
		elseif ($data->getName() == 'form')
		{
			$elements = $data->children();
		}

		// If there is nothing to load return true.
		if (empty($elements))
		{
			return true;
		}

		// Load the found form elements.
		foreach ($elements as $element)
		{
			// Get an array of fields with the correct name.
			$fields = $element->xpath('descendant-or-self::field');
			foreach ($fields as $field)
			{
				// Get the group names as strings for ancestor fields elements.
				$attrs = $field->xpath('ancestor::fields[@name]/@name');
				$groups = array_map('strval', $attrs ? $attrs : array());

				// Check to see if the field exists in the current form.
				if ($current = $this->findField((string) $field['name'], implode('.', $groups)))
				{

					// If set to replace found fields, replace the data and remove the field so we don't add it twice.
					if ($replace)
					{
						$olddom = dom_import_simplexml($current);
						$loadeddom = dom_import_simplexml($field);
						$addeddom = $olddom->ownerDocument->importNode($loadeddom, true); // Import child nodes too
						$olddom->parentNode->replaceChild($addeddom, $olddom);
						$loadeddom->parentNode->removeChild($loadeddom);
					}
					else
					{
						unset($field);
					}
				}
			}

			// Merge the new field data into the existing XML document.
			self::addNode($this->xml, $element);
		}

		// Synchronize any paths found in the load.
		$this->syncPaths();

		return true;
	}
}depend/index.html000060400000000054152455303030007773 0ustar00<html><body bgcolor="#FFFFFF"></body></html>depend/t3modules.php000060400000007166152455303030010441 0ustar00<?php
/** 
 *------------------------------------------------------------------------------
 * @package       T3 Framework for Joomla!
 *------------------------------------------------------------------------------
 * @copyright     Copyright (C) 2004-2013 JoomlArt.com. All Rights Reserved.
 * @license       GNU General Public License version 2 or later; see LICENSE.txt
 * @authors       JoomlArt, JoomlaBamboo, (contribute to this project at github 
 *                & Google group to become co-author)
 * @Google group: https://groups.google.com/forum/#!forum/t3fw
 * @Link:         http://t3-framework.org 
 *------------------------------------------------------------------------------
 */

// No direct access
defined('_JEXEC') or die();

/**
 * Radio List Element
 *
 * @package  T3.Core.Element
 */
class JFormFieldT3Modules extends JFormField
{
	/**
	 * Element name
	 *
	 * @access    protected
	 * @var        string
	 */
	protected $type = 'T3Modules';

	/**
	 * Check and load assets file if needed
	 */
	function loadAsset(){
		if (!defined ('_T3_DEPEND_ASSET_')) {
			define ('_T3_DEPEND_ASSET_', 1);
			
			if(!defined('T3')){
				$t3url = str_replace(DIRECTORY_SEPARATOR, '/', JURI::base(true) . '/' . substr(dirname(__FILE__), strlen(JPATH_SITE)));
				$t3url = str_replace('/administrator/', '/', $uri);
				$t3url = str_replace('//', '/', $uri);
			} else {
				$t3url = T3_ADMIN_URL;
			}

			$jdoc = JFactory::getDocument();

			if(!defined('T3_TEMPLATE')){
				JFactory::getLanguage()->load(T3_PLUGIN, JPATH_ADMINISTRATOR);

				if(version_compare(JVERSION, '3.0', 'ge')){
					JHtml::_('jquery.framework');
				} else {
					$jdoc->addScript(T3_ADMIN_URL . '/admin/js/jquery-1.x.min.js');
					$jdoc->addScript(T3_ADMIN_URL . '/admin/js/jquery.noconflict.js');
				}

				$jdoc->addStyleSheet(T3_ADMIN_URL . '/includes/depend/css/depend.css');
				$jdoc->addScript(T3_ADMIN_URL . '/includes/depend/js/depend.js');
			}

			JFactory::getDocument()->addScriptDeclaration ( '
				jQuery.extend(T3Depend, {
					adminurl: \'' . JUri::getInstance()->toString() . '\',
					rooturl: \'' . JURI::root() . '\'
				});
			');
		}
	}
	
	/**
	 * Method to get the field input markup.
	 *
	 * @return  string  The field input markup.
	 */
	function getInput()
	{
		$this->loadAsset();

		$show_default = $this->toBoolean((string) $this->element['show_default']);
		$show_none    = $this->toBoolean((string) $this->element['show_none']);
		$multiple     = $this->toBoolean((string) $this->element['multiple']);
		$disabled     = $this->toBoolean((string) $this->element['disabled']);

		$db    = JFactory::getDbo();
		$query = $db->getQuery(true);
		$query
			->select('id, title, module, position')
			->from('#__modules')
			->where('published = 1')
			->where('client_id = 0')
			->order('title');
		$db->setQuery($query);
		
		$modules = $db->loadObjectList();
		$moduleopts = array();

		if($show_default){
			$moduleopts[] = JHTML::_('select.option', 'default', JText::_('JDEFAULT'));
		}

		if($show_none){
			$moduleopts[] = JHTML::_('select.option', 'none', JText::_('JNONE'));
		} 

		if (is_array($modules)) {
			foreach ($modules as $module) {
				$moduleopts[] = JHTML::_('select.option', $module->id, $module->title);
			}
		}

		return JHTML::_('select.genericlist', $moduleopts, $this->name . ($multiple ? '[]' : ''), ($multiple ? 'multiple="multiple" size="10" ' : '') . ($disabled ? 'disabled="disabled"' : ''), 'value', 'text', $this->value);
	}


	/**
	 * Helper function, check the field attribute and return boolean value
	 *
	 * @return  boolean the check result
	 */
	function toBoolean($str){
		return !in_array($str, array('false', '', '0', 'no', 'off'));
	}
}depend/t3folderlist.php000060400000004142152455303030011127 0ustar00<?php
/** 
 *------------------------------------------------------------------------------
 * @package       T3 Framework for Joomla!
 *------------------------------------------------------------------------------
 * @copyright     Copyright (C) 2004-2013 JoomlArt.com. All Rights Reserved.
 * @license       GNU General Public License version 2 or later; see LICENSE.txt
 * @authors       JoomlArt, JoomlaBamboo, (contribute to this project at github 
 *                & Google group to become co-author)
 * @Google group: https://groups.google.com/forum/#!forum/t3fw
 * @Link:         http://t3-framework.org 
 *------------------------------------------------------------------------------
 */

defined('JPATH_PLATFORM') or die;

JFormHelper::loadFieldClass('folderlist');

/**
 * Supports an HTML select list of files
 *
 * @package     Joomla.Platform
 * @subpackage  Form
 * @since       11.1
 */
class JFormFieldT3FolderList extends JFormFieldFolderList
{

	/**
	 * The form field type.
	 *
	 * @var    string
	 * @since  11.1
	 */
	public $type = 'T3FolderList';

	/**
	 * Method to get the list of files for the field options.
	 * Specify the target directory with a directory attribute
	 * Attributes allow an exclude mask and stripping of extensions from file name.
	 * Default attribute may optionally be set to null (no file) or -1 (use a default).
	 *
	 * @return  array  The field option objects.
	 *
	 * @since   11.1
	 */
	protected function getOptions()
	{
		//$table = JTable::getInstance('Style', 'TemplatesTable', array());
		//$table->load((int) JFactory::getApplication()->input->getInt('id'));
		// update path to this template 
		$path = (string) $this->element['directory'];
		// process path in template
		$options = array();
		$vals = array();
		// get all path in template
		$paths = T3Path::getAllPath ($path, true);
		foreach ($paths as $path) {
			$this->directory = $this->element['directory'] = JPath::clean($path);
			$tmps = parent::getOptions();
			foreach ($tmps as $tmp) {
				if (in_array($tmp->value, $vals)) continue;
				$vals[] = $tmp->value;
				$options[] = $tmp;
			}
		}
		return $options;
	}
}
depend/js/index.html000060400000000054152455303030010407 0ustar00<html><body bgcolor="#FFFFFF"></body></html>depend/js/depend.js000060400000032141152455303030010211 0ustar00/** 
 *------------------------------------------------------------------------------
 * @package       T3 Framework for Joomla!
 *------------------------------------------------------------------------------
 * @copyright     Copyright (C) 2004-2013 JoomlArt.com. All Rights Reserved.
 * @license       GNU General Public License version 2 or later; see LICENSE.txt
 * @authors       JoomlArt, JoomlaBamboo, (contribute to this project at github 
 *                & Google group to become co-author)
 * @Google group: https://groups.google.com/forum/#!forum/t3fw
 * @Link:         http://t3-framework.org 
 *------------------------------------------------------------------------------
 */

!function($){

	var T3Depend = window.T3Depend = window.T3Depend || { 	
		
		depends: {},
		controls: {},
		infos: {},
		ajaxs: {},

		register: function(to, depend){
			var controls = this.controls;
			
			if(!controls[to]){
				controls[to] = [];
				
				var inst = this;
				this.elmsFrom(to).on('change.less', function(e){
					inst.change(this);
				});
			}
			
			if($.inArray(depend, controls[to]) == -1){
				controls[to].push(depend);
			}
		},
		
		change: function(ctrlelm){
			var controls = this.controls,
				depends = this.depends,
				ctrls = controls[ctrlelm.name],
				form = this;

				
			if(!ctrls){
				ctrls = controls[ctrlelm.name.substr(0, ctrlelm.name.length - 2)];
			}
			
			if(!ctrls){
				return false;
			}
			
			$.each(ctrls, function(idx, ectrl){
				var showup = true;
				
				$.each(depends[ectrl], function(ctrl, cvals){
					if(showup){
						var celms = form.elmsFrom(ctrl);
						showup = showup && !!($.grep(celms, function(celm){ return celm._disabled; }).length == 0);
						if(showup){
							showup = showup && !!($.grep(form.valuesFrom(celms), function(val){ return ($.inArray(val, cvals) != -1); }).length);
						}
					}
				});
				
				form.elmsFrom(ectrl).each(function(){
					if(showup){
						form.enable(this);
					} else {
						form.disable(this);
					}
				});
				
				if(controls[ectrl] && controls[ectrl] != ectrl){
					form.elmsFrom(this).eq(0).trigger('change');
				}
				
			});
		},
		
		add: function(control, info){
			
			var depends = this.depends,
				infos = this.infos,
				form = this,
				name = info.group + '[' + control + ']';
				
			info = $.extend({
				group: 'params',
				hide: true
			}, info);
			
			$.each(info.elms.split(','), function(el){
				var elm = info.group +'[' + $.trim(this) + ']';
				
				if (!depends[elm]) {
					depends[elm] = {};
				}

				//save info
				if (!infos[elm]){
					infos[elm] = info;
				} else {
					$.extend(infos[elm], info);
				}
				
				if (!depends[elm][name]) {
					depends[elm][name] = [];
				}
				
				depends[elm][name] = depends[elm][name].concat(info.vals.split(','));
				
				form.register(name, elm);
				
			});
		},
		
		start: function(){
			$(document.adminForm).find('h4.block-head').parent().addClass('segment');
			
			this.update();
		},
		
		update: function () {
			var form = this;
			$.each(this.controls, function(ctrl, ctrls){
				form.elmsFrom(ctrl).trigger('change');
			});
		},
		
		enable: function (el) {
			el._disabled = false; //selector 'li' is J2.5 compactible
			if(this.infos[el.name] && this.infos[el.name].hide){
				$(el).closest('.adminformlist > li, div.control-group').css('display', 'block');
			} else {
				$(el).closest('.controls, .t3-controls').children().removeClass('disabled');
			}
		},
		
		disable: function (el) {
			el._disabled = true; //selector 'li' is J2.5 compactible
			if(this.infos[el.name] && this.infos[el.name].hide){
				$(el).closest('.adminformlist > li, div.control-group').css('display', 'none');
			} else {
				$(el).closest('.controls, .t3-controls').children().addClass('disabled');	
			}
		},
		
		elmsFrom: function(name){
			var el = document.adminForm[name];
			if(!el){
				el = document.adminForm[name + '[]'];
			}
			
			return $(el);
		},
		
		valuesFrom: function(els){
			var vals = [];
			
			$(els).each(function(){
				var type = this.type,
					val = $.makeArray(((type == 'radio' || type == 'checkbox') && !this.checked) ? null : $(this).val());

				for (var i = 0, l = val.length; i < l; i++){
					if($.inArray(val[i], vals) == -1){
						vals.push(val[i]);
					}
				}
			});
			
			return vals;
		},

		addajax: function(name, info){
			var ajaxs = this.ajaxs;
				
			info = $.extend({
				url: info.site == 'admin' ? T3Depend.adminurl : T3Depend.rooturl,
				func: ''
			}, info);

			if(info.query){
				var urlparts = info.url.split('#');
				if(urlparts[0].indexOf('?') == -1){
					urlparts[0] += '?' + info.query;
				} else {
					urlparts[0] += '&' + info.query;
				}
				
				info.url = urlparts.join('#');
			}

			if(!ajaxs[name]){
				ajaxs[name] = {};

				var inst = this;
				this.elmsFrom(name).on('change.less', function(e){
					inst.loadajax(this);
				});
			}

			ajaxs[name].info = info;
		},

		loadajax: function(ctrlelm){
			var ajaxs = this.ajaxs,
				name = ctrlelm.name,
				ctrl = ajaxs[name],
				form = this;

			if(!ctrl){
				ctrl = ajaxs[name.substr(0, name.length - 2)];
			}
			
			if(!ctrl){
				return false;
			}

			var info = ctrl.info;
			if(!info){
				return false;
			}

			if(ctrl.elms && ctrl.elms.length){
				$(ctrl.elms).remove();
				ctrl.elms.length = 0;
			} else {
				ctrl.elms = [];
			}

			if(!this.progElm){

			}

			if(!this.progElm){
				this.progElm = $('.t3-progress');

				if(!this.progElm.length){
					this.progElm = $('<div class="t3-progress"></div>')
				}

				this.progElm.appendTo(document.body);

				var placed = $('#toolbar-box');
				if(!placed.length){
					placed = $('#t3-admin-toolbar');
				}

				if(placed.length){
					this.progElm.appendTo(placed);
				}
			}

			//progress bar
			//show it first
			if($.support.transition){
				form.progElm
					.removeClass('t3-anim-slow t3-anim-finish')
					.css('width', '');

				setTimeout(function(){
					if(!form.progElm.hasClass('t3-anim-finish')){
						form.progElm
							.addClass('t3-anim-slow')
							.css('width', 50 + Math.floor(Math.random() * 20) + '%');
					}
				});
			} else {
				form.progElm.stop(true).css({
					width: '0%',
					display: 'block'
				}).animate({
					width: 50 + Math.floor(Math.random() * 20) + '%'
				});
			}

			$.get(info.url, {
				jvalue: form.valuesFrom(form.elmsFrom(name))[0], 
				_: $.now() 
			}).always(function(){
				//progress bar
				if($.support.transition){
					
					form.progElm
						.removeClass('t3-anim-slow')
						.addClass('t3-anim-finish')
						.one($.support.transition.end, function () {
							setTimeout(function(){
								if(form.progElm.hasClass('t3-anim-finish')){
									$(form.progElm).removeClass('t3-anim-finish');
								}
							}, 1000);
						});

				} else {
					$(form.progElm).stop(true).animate({
						width: '100%'
					}, function(){
						$(form.progElm).hide();
					});
				}

			}).done(function(rsp){
				
				var parts = ctrl.info.func.split('.'),
					fobj = window;

				for(var i = 0; i < parts.length; i++){
					if(!(fobj = fobj[parts[i]])) {
						break;
					}
				}

				if(fobj && i == parts.length && $.isFunction(fobj)){
					fobj(form, ctrlelm, ctrl, rsp);
				}
			});
		},
		
		segment: function(seg){
			if($(seg).hasClass('close')){
				this.showseg(seg);
			} else {
				this.hideseg(seg);
			}
		},
		
		showseg: function(seg){
			
			var segelm = $(seg),
				snext = segelm.parent().next();
			
			while(snext.length && !snext.hasClass('segment')){
				snext.css('display', snext.data('jdisplay') || '');
				snext = snext.next();
			}
			
			segelm.removeClass('close').addClass('open');
		},
		
		hideseg: function(seg){
			var segelm = $(seg),
				snext = segelm.parent().next();
			
			while(snext.length && !snext.hasClass('segment')){
				snext.data('jdisplay', snext.css('display')).css('display', 'none');
				snext = snext.next();
			}
			
			segelm.removeClass('open').addClass('close');  
		}
	};

	var JAFileConfig = window.JAFileConfig = window.JAFileConfig || {
		
		vars: {
		},
		
		initialize: function(optionid){
			var vars = this.vars;
			vars.group = 't3form';
			vars.el = document.getElementById(optionid);
			
			var adminlist = $('#module-sliders').find('ul.adminformlist:first');
			if(adminlist.length){
				$('<li class="clearfix level2"></li>').appendTo(adminlist);
			}
		},
		
		changeProfile: function(profile){
			if(profile == ''){
				return;
			}
			
			this.vars.active = profile;
			this.fillData();
			
			if(T3Depend && T3Depend.update){
				T3Depend.update();
			}
		},
		
		serializeArray: function(){
			var vars = this.vars,
				els = [],
				allelms = document.adminForm.elements,
				pname1 = vars.group + '\\[params\\]\\[.*\\]',
				pname2 = vars.group + '\\[params\\]\\[.*\\]\\[\\]';
				
			for (var i = 0, il = allelms.length; i < il; i++){
			    var el = $(allelms[i]);
				
			    if (el.name && ( el.name.test(pname1) || el.name.test(pname2))){
			    	els.push(el);
			    }
			}
			
			return els;
		},

		fillData: function (){
			var vars = this.vars,
				els = this.serializeArray(),
				profile = T3Depend.profiles[vars.active],
				form = this;
				
			if(els.length == 0 || !profile){
				return;
			}
			
			$.each(els, function(){
				var name = this.getName(this),
					values = (profile[name] != undefined) ? profile[name] : '';
				
				form.setValues(this, $.makeArray(values));
			});
		},
		
		valuesFrom: function(els){
			var vals = [];
			
			$(els).each(function(){
				var type = this.type,
					val = $.makeArray(((type == 'radio' || type == 'checkbox') && !this.checked) ? null : $(this).val());

				for (var i = 0, l = val.length; i < l; i++){
					if($.inArray(val[i], vals) == -1){
						vals.push(val[i]);
					}
				}
			});
			
			return vals;
		},
		
		setValues: function(el, vals){
			var jel = $(el);
			
			if(jel.prop('tagName').toUpperCase() == 'SELECT'){
				jel.val(vals);
				
				if($.makeArray(jel.val())[0] != vals[0]){
					jel.val('-1');
				}
			}else {
				if(jel.prop('type') == 'checkbox' || jel.prop('type') == 'radio'){
					jel.prop('checked', $.inArray(el.value, vals) != -1);
				} else {
					jel.attr('placeholder', vals[0]);
					jel.val(vals[0]);
				}
			}
		},
		
		getName: function(el){
			var matches = el.name.match(this.vars.group + '\\[params\\]\\[([^\\]]*)\\]');
			if (matches){
				return matches[1];
			}
			
			return '';
		},
		
		
		deleteProfile: function(){
			if(confirm(JAFileConfig.langs.confirmDelete)){			
				this.submitForm(JAFileConfig.mod_url + '?dptask=delete&profile=' + this.vars.active + '&template='+ JAFileConfig.template, {}, 'profile');
			}		
		},
		
		duplicateProfile: function (){
			var nname = prompt(JAFileConfig.langs.enterName);
			
			if(nname){
				nname = nname.replace(/[^0-9a-zA-Z_-]/g, '').replace(/ /, '').toLowerCase();
				if(nname == ''){
					alert(JAFileConfig.langs.correctName);
					return this.cloneProfile();
				}
				
				JAFileConfig.profiles[nname] = JAFileConfig.profiles[this.vars.active];
				
				this.submitForm(JAFileConfig.mod_url + '?dptask=duplicate&profile=' + nname + '&from=' + this.vars.active + '&template=' + JAFileConfig.template, {}, 'profile');
			}
		},
		
		saveProfile: function (task){

			if(task){
				JAFileConfig.profiles[this.vars.active] = this.rebuildData();
				this.submitForm(JAFileConfig.mod_url + '?dptask=save&profile=' + this.vars.active, JAFileConfig.profiles[this.vars.active], 'profile', task);
			}
		},
		
		submitForm: function(url, request, type, task){
			if(JAFileConfig.run){
				JAFileConfig.ajax.cancel();
			}
			
			JAFileConfig.run = true;
	    	
			JAFileConfig.ajax = $.ajax({
				type: 'post',
				url: url,
				data: request,
				complete: function(result){
					
					JAFileConfig.run = false;
					
					if(result == ''){
						return;
					}
					
					var vars = JAFileConfig;
					
					alert(json.error || json.successfull);
					
					if(result.profile){
						switch (result.type){	
							case 'new':
								Joomla.submitbutton(document.adminForm.task.value);
							break;
							
							case 'delete':
								if(result.template == 0){
									var opts = vars.el.options;
									
									for(var j = 0, jl = opts.length; j < jl; j++){
										if(opts[j].value == result.profile){
											vars.el.remove(j);
											break;
										}
									}
								} else {
									JAFileConfig.profiles[result.profile] = JAFileConfig.tempprofiles[result.profile];
								}
								
								vars.el.options[0].selected = true;					
								JAFileConfig.changeProfile(vars.el.options[0].value);
							break;
							
							case 'duplicate':
								vars.el.options[vars.el.options.length] = new Option(result.profile, result.profile);							
								vars.el.options[vars.el.options.length - 1].selected = true;
								JAFileConfig.changeProfile(result.profile);
							break;
							
							default:
						}
					}
				}
			});
		},
		
		rebuildData: function (){
			var els = this.serializeArray(this.group),
				form = this,
				json = {};
				
			$.each(els, function(){
				var values = form.valuesFrom(this);
				if(values.length){
					json[this.getName(this)] = this.name.substr(-2) == '[]' ? values : values[0];
				}
			});
			
			return json;
		}
	};

	$(window).on('load', function() {
		setTimeout($.proxy(T3Depend.start, T3Depend), 100);
	});

}(jQuery);

depend/t3layoutlist.php000060400000004156152455303030011176 0ustar00<?php
/** 
 *------------------------------------------------------------------------------
 * @package       T3 Framework for Joomla!
 *------------------------------------------------------------------------------
 * @copyright     Copyright (C) 2004-2013 JoomlArt.com. All Rights Reserved.
 * @license       GNU General Public License version 2 or later; see LICENSE.txt
 * @authors       JoomlArt, JoomlaBamboo, (contribute to this project at github 
 *                & Google group to become co-author)
 * @Google group: https://groups.google.com/forum/#!forum/t3fw
 * @Link:         http://t3-framework.org 
 *------------------------------------------------------------------------------
 */

defined('JPATH_PLATFORM') or die;

JFormHelper::loadFieldClass('filelist');

/**
 * Supports an HTML select list of files
 *
 * @package     Joomla.Platform
 * @subpackage  Form
 * @since       11.1
 */
class JFormFieldT3LayoutList extends JFormFieldFileList
{

	/**
	 * The form field type.
	 *
	 * @var    string
	 * @since  11.1
	 */
	public $type = 'T3FileList';

	/**
	 * The initialised state of the document object.
	 *
	 * @var    boolean
	 * @since  1.6
	 */
	protected static $initialised = false;

	/**
	 * Method to get the list of files for the field options.
	 * Specify the target directory with a directory attribute
	 * Attributes allow an exclude mask and stripping of extensions from file name.
	 * Default attribute may optionally be set to null (no file) or -1 (use a default).
	 *
	 * @return  array  The field option objects.
	 *
	 * @since   11.1
	 */
	protected function getOptions()
	{
		// update path to this template 
		$path = (string) $this->element['directory'];
		$this->directory = $this->element['directory'] = T3_TEMPLATE_PATH . DIRECTORY_SEPARATOR . $path;

		$options = parent::getOptions();

		// get addon layouts
		$folders = JFolder::folders(T3_TEMPLATE_PATH . '/addons');

		// Build the options list from the list of folders.
		if (is_array($folders))
		{
			foreach ($folders as $folder)
			{
				$options[] = JHtml::_('select.option', 'addon.'.$folder, 'addon - '.$folder);
			}
		}

		return $options;

	}
}
?>depend/t3media.php000060400000020777152455303030010053 0ustar00<?php
/** 
 *------------------------------------------------------------------------------
 * @package       T3 Framework for Joomla!
 *------------------------------------------------------------------------------
 * @copyright     Copyright (C) 2004-2013 JoomlArt.com. All Rights Reserved.
 * @license       GNU General Public License version 2 or later; see LICENSE.txt
 * @authors       JoomlArt, JoomlaBamboo, (contribute to this project at github 
 *                & Google group to become co-author)
 * @Google group: https://groups.google.com/forum/#!forum/t3fw
 * @Link:         http://t3-framework.org 
 *------------------------------------------------------------------------------
 */

defined('JPATH_PLATFORM') or die;

/**
 * Form Field class for the Joomla Platform.
 * Provides a modal media selector including upload mechanism
 *
 * @package     Joomla.Libraries
 * @subpackage  Form
 * @since       1.6
 */


if(version_compare(JVERSION, '3.0', 'ge')){
	class JFormFieldT3Media extends JFormFieldMedia {
		/**
		 * The form field type.
		 *
		 * @var    string
		 * @since  1.6
		 */
		protected $type = 'T3Media';
	}
} else {

	class JFormFieldT3Media extends JFormField
	{
		/**
		 * The form field type.
		 *
		 * @var    string
		 * @since  1.6
		 */
		protected $type = 'T3Media';

		/**
		 * The initialised state of the document object.
		 *
		 * @var    boolean
		 * @since  1.6
		 */
		protected static $initialised = false;

		/**
		 * Method to get the field input markup for a media selector.
		 * Use attributes to identify specific created_by and asset_id fields
		 *
		 * @return  string  The field input markup.
		 *
		 * @since   1.6
		 */
		protected function getInput()
		{
			$assetField = $this->element['asset_field'] ? (string) $this->element['asset_field'] : 'asset_id';
			$authorField = $this->element['created_by_field'] ? (string) $this->element['created_by_field'] : 'created_by';
			$asset = $this->form->getValue($assetField) ? $this->form->getValue($assetField) : (string) $this->element['asset_id'];
			if ($asset == '')
			{
				$asset = JFactory::getApplication()->input->get('option');
			}

			$link = (string) $this->element['link'];
			if (!self::$initialised)
			{
				// Load the modal behavior script.
				JHtml::_('behavior.modal');

				// Build the script.
				$script = array();
				$script[] = '	function jInsertFieldValue(value, id) {';
				$script[] = '		var old_value = document.getElementById(id).value;';
				$script[] = '		if (old_value != value) {';
				$script[] = '			var elem = document.getElementById(id);';
				$script[] = '			elem.value = value;';
				$script[] = '			elem.fireEvent("change");';
				$script[] = '			if (typeof(elem.onchange) === "function") {';
				$script[] = '				elem.onchange();';
				$script[] = '			}';
				$script[] = '			jMediaRefreshPreview(id);';
				$script[] = '		}';
				$script[] = '	}';

				$script[] = '	function jMediaRefreshPreview(id) {';
				$script[] = '		var value = document.getElementById(id).value;';
				$script[] = '		var img = document.getElementById(id + "_preview");';
				$script[] = '		if (img) {';
				$script[] = '			if (value) {';
				$script[] = '				img.src = "' . JURI::root() . '" + value;';
				$script[] = '				document.getElementById(id + "_preview_empty").setStyle("display", "none");';
				$script[] = '				document.getElementById(id + "_preview_img").setStyle("display", "");';
				$script[] = '			} else { ';
				$script[] = '				img.src = ""';
				$script[] = '				document.getElementById(id + "_preview_empty").setStyle("display", "");';
				$script[] = '				document.getElementById(id + "_preview_img").setStyle("display", "none");';
				$script[] = '			} ';
				$script[] = '		} ';
				$script[] = '	}';

				$script[] = '	function jMediaRefreshPreviewTip(tip)';
				$script[] = '	{';
				$script[] = '		var img = tip.getElement("img.media-preview");';
				$script[] = '		tip.getElement("div.tip").setStyle("max-width", "none");';
				$script[] = '		var id = img.getProperty("id");';
				$script[] = '		id = id.substring(0, id.length - "_preview".length);';
				$script[] = '		jMediaRefreshPreview(id);';
				$script[] = '		tip.setStyle("display", "block");';
				$script[] = '	}';

				// Add the script to the document head.
				JFactory::getDocument()->addScriptDeclaration(implode("\n", $script));

				self::$initialised = true;
			}

			$html = array();
			$attr = '';

			// Initialize some field attributes.
			$attr .= $this->element['class'] ? ' class="' . (string) $this->element['class'] . '"' : '';
			$attr .= $this->element['size'] ? ' size="' . (int) $this->element['size'] . '"' : '';

			// Initialize JavaScript field attributes.
			$attr .= $this->element['onchange'] ? ' onchange="' . (string) $this->element['onchange'] . '"' : '';

			// The text field.
			$html[] = '<div class="input-prepend input-append">';

			// The Preview.
			$preview = (string) $this->element['preview'];
			$showPreview = true;
			$showAsTooltip = false;
			switch ($preview)
			{
				case 'no': // Deprecated parameter value
				case 'false':
				case 'none':
					$showPreview = false;
					break;

				case 'yes': // Deprecated parameter value
				case 'true':
				case 'show':
					break;

				case 'tooltip':
				default:
					$showAsTooltip = true;
					$options = array(
						'onShow' => 'jMediaRefreshPreviewTip',
					);
					JHtml::_('behavior.tooltip', '.hasTipPreview', $options);
					break;
			}

			if ($showPreview)
			{
				if ($this->value && file_exists(JPATH_ROOT . '/' . $this->value))
				{
					$src = JURI::root() . $this->value;
				}
				else
				{
					$src = '';
				}

				$width = isset($this->element['preview_width']) ? (int) $this->element['preview_width'] : 300;
				$height = isset($this->element['preview_height']) ? (int) $this->element['preview_height'] : 200;
				$style = '';
				$style .= ($width > 0) ? 'max-width:' . $width . 'px;' : '';
				$style .= ($height > 0) ? 'max-height:' . $height . 'px;' : '';

				$imgattr = array(
					'id' => $this->id . '_preview',
					'class' => 'media-preview',
					'style' => $style,
				);
				$img = JHtml::image($src, JText::_('JLIB_FORM_MEDIA_PREVIEW_ALT'), $imgattr);
				$previewImg = '<div id="' . $this->id . '_preview_img"' . ($src ? '' : ' style="display:none"') . '>' . $img . '</div>';
				$previewImgEmpty = '<div id="' . $this->id . '_preview_empty"' . ($src ? ' style="display:none"' : '') . '>'
					. JText::_('JLIB_FORM_MEDIA_PREVIEW_EMPTY') . '</div>';

				$html[] = '<div class="media-preview add-on">';
				if ($showAsTooltip)
				{
					$tooltip = $previewImgEmpty . $previewImg;
					$options = array(
						'title' => JText::_('JLIB_FORM_MEDIA_PREVIEW_SELECTED_IMAGE'),
						'text' => '<i class="icon-eye-open"></i>',
						'class' => 'hasTipPreview'
					);
					$html[] = JHtml::tooltip($tooltip, $options);
				}
				else
				{
					$html[] = ' ' . $previewImgEmpty;
					$html[] = ' ' . $previewImg;
				}
				$html[] = '</div>';
			}

			$html[] = '	<input type="text" class="input-small" name="' . $this->name . '" id="' . $this->id . '"' . ' value="'
				. htmlspecialchars($this->value, ENT_COMPAT, 'UTF-8') . '"' . ' readonly="readonly"' . $attr . ' />';

			$directory = (string) $this->element['directory'];
			if ($this->value && file_exists(JPATH_ROOT . '/' . $this->value))
			{
				$folder = explode('/', $this->value);
				$folder = array_diff_assoc($folder, explode('/', JComponentHelper::getParams('com_media')->get('image_path', 'images')));
				array_pop($folder);
				$folder = implode('/', $folder);
			}
			elseif (file_exists(JPATH_ROOT . '/' . JComponentHelper::getParams('com_media')->get('image_path', 'images') . '/' . $directory))
			{
				$folder = $directory;
			}
			else
			{
				$folder = '';
			}

			// The button.
			if ($this->element['disabled'] != true)
			{
				
				$html[] = '<a class="modal btn" title="' . JText::_('JLIB_FORM_BUTTON_SELECT') . '"' . ' href="'
					. ($this->element['readonly'] ? ''
					: ($link ? $link
						: 'index.php?option=com_media&amp;view=images&amp;tmpl=component&amp;asset=' . $asset . '&amp;author='
						. $this->form->getValue($authorField)) . '&amp;fieldid=' . $this->id . '&amp;folder=' . $folder) . '"'
					. ' rel="{handler: \'iframe\', size: {x: 800, y: 500}}">';
				$html[] = JText::_('JLIB_FORM_BUTTON_SELECT') . '</a><a class="btn hasTooltip" title="' . JText::_('JLIB_FORM_BUTTON_CLEAR') . '"' . ' href="#" onclick="';
				$html[] = 'jInsertFieldValue(\'\', \'' . $this->id . '\');';
				$html[] = 'return false;';
				$html[] = '">';
				$html[] = '<i class="icon-remove"></i></a>';
			}

			$html[] = '</div>';

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

}depend/t3filelist.php000060400000004407152455303030010577 0ustar00<?php
/** 
 *------------------------------------------------------------------------------
 * @package       T3 Framework for Joomla!
 *------------------------------------------------------------------------------
 * @copyright     Copyright (C) 2004-2013 JoomlArt.com. All Rights Reserved.
 * @license       GNU General Public License version 2 or later; see LICENSE.txt
 * @authors       JoomlArt, JoomlaBamboo, (contribute to this project at github 
 *                & Google group to become co-author)
 * @Google group: https://groups.google.com/forum/#!forum/t3fw
 * @Link:         http://t3-framework.org 
 *------------------------------------------------------------------------------
 */

defined('JPATH_PLATFORM') or die;

JFormHelper::loadFieldClass('filelist');

/**
 * Supports an HTML select list of files
 *
 * @package     Joomla.Platform
 * @subpackage  Form
 * @since       11.1
 */
class JFormFieldT3FileList extends JFormFieldFileList
{

	/**
	 * The form field type.
	 *
	 * @var    string
	 * @since  11.1
	 */
	public $type = 'T3FileList';

	/**
	 * The initialised state of the document object.
	 *
	 * @var    boolean
	 * @since  1.6
	 */
	protected static $initialised = false;

	/**
	 * Method to get the list of files for the field options.
	 * Specify the target directory with a directory attribute
	 * Attributes allow an exclude mask and stripping of extensions from file name.
	 * Default attribute may optionally be set to null (no file) or -1 (use a default).
	 *
	 * @return  array  The field option objects.
	 *
	 * @since   11.1
	 */
	protected function getOptions()
	{
		// update path to this template 
		$path = (string) $this->element['directory'];
		$path = JPath::clean($path);
		$options = array();
		// get files in template path
		$this->directory = $this->element['directory'] = T3_TEMPLATE_PATH . DIRECTORY_SEPARATOR . $path;
		$options = parent::getOptions();
		// get files in template local path

		if (!defined('T3_LOCAL_DISABLED') && is_dir (T3_LOCAL_PATH . DIRECTORY_SEPARATOR . $path)) {
			$this->directory = $this->element['directory'] = T3_LOCAL_PATH . DIRECTORY_SEPARATOR . $path;
			$options2 = parent::getOptions();
			foreach ($options2 as $option) {
				$option->text .= ' (local)';
				$options[] = $option;
			}
		}
		return $options;
	}
}
?>depend/t3depend.php000060400000030533152455303030010222 0ustar00<?php
/** 
 *------------------------------------------------------------------------------
 * @package       T3 Framework for Joomla!
 *------------------------------------------------------------------------------
 * @copyright     Copyright (C) 2004-2013 JoomlArt.com. All Rights Reserved.
 * @license       GNU General Public License version 2 or later; see LICENSE.txt
 * @authors       JoomlArt, JoomlaBamboo, (contribute to this project at github 
 *                & Google group to become co-author)
 * @Google group: https://groups.google.com/forum/#!forum/t3fw
 * @Link:         http://t3-framework.org 
 *------------------------------------------------------------------------------
 */

// Ensure this file is being included by a parent file
defined('_JEXEC') or die( 'Restricted access' );

jimport('joomla.filesystem.file');
jimport('joomla.filesystem.folder');

/**
 * Radio List Element
 *
 * @since      Class available since Release 1.2.0
 */
class JFormFieldT3Depend extends JFormField
{
	/**
	 * Element name
	 *
	 * @access	protected
	 * @var		string
	 */
	protected $type = 'T3Depend';
	
	/**
	 * Check and load assets file if needed
	 */
	function loadAsset(){
		if (!defined ('_T3_DEPEND_ASSET_')) {
			define ('_T3_DEPEND_ASSET_', 1);

			$jdoc = JFactory::getDocument();

			if(!defined('T3_TEMPLATE')){
				JFactory::getLanguage()->load(T3_PLUGIN, JPATH_ADMINISTRATOR);

				if(version_compare(JVERSION, '3.0', 'ge')){
					JHtml::_('jquery.framework');
				} else {
					$jdoc->addScript(T3_ADMIN_URL . '/admin/js/jquery-1.x.min.js');
					$jdoc->addScript(T3_ADMIN_URL . '/admin/js/jquery.noconflict.js');
				}
			}

			if(JFactory::getApplication()->isClient('site') || !defined('T3_TEMPLATE')){
				$jdoc->addStyleSheet(T3_ADMIN_URL . '/includes/depend/css/depend.css');
				$jdoc->addScript(T3_ADMIN_URL . '/includes/depend/js/depend.js');
			}

			JFactory::getDocument()->addScriptDeclaration ( '
				jQuery.extend(T3Depend, {
					adminurl: \'' . JUri::getInstance()->toString() . '\',
					rooturl: \'' . JURI::root() . '\'
				});
			');
		}
	}

	/**
	 * Element name
	 *
	 * @access	protected
	 * @var		string
	 */
	protected function getInput(){
		$this->loadAsset();
		
		$func 	= (string)$this->element['function'] ? (string)$this->element['function'] : '';
		$value 	= $this->value ? $this->value : (string) $this->element['default'];

		if (substr($func, 0, 1) == '@'){
			$func = substr($func, 1);
			if (method_exists($this, $func)) {
				return $this->$func();
			}
		} else {
			$subtype = ( isset( $this->element['subtype'] ) ) ? trim($this->element['subtype']) : '';
			if (method_exists ($this, $subtype)) {
				return $this->$subtype ();
			}
		}
		return; 
	}
	
	/**
     *
     * Get profile config
     * @return Ambigous <string, multitype:>|string
     */
    protected function profile()
    {
        $this->loadAsset();

        $module = $this->element['module'];

        if(!$module){
        	 return JText::_('UNKNOWN_MODULE_PATH');
        }

        /* Get all profiles name folder from folder profiles */
        $profiles = array();
        $jsonData = array();
        // get in module
        $path = JPATH_SITE . DIRECTORY_SEPARATOR . 'modules' . DIRECTORY_SEPARATOR . $module . DIRECTORY_SEPARATOR . 'profiles';
        if (!JFolder::exists($path)){
            return JText::_('PROFILE_FOLDER_NOT_EXIST');
		}
        $files = JFolder::files($path, '.ini');
        if ($files) {
            foreach ($files as $fname) {
                $fname = substr($fname, 0, -4);

                $f = new stdClass();
                $f->id = $fname;
                $f->title = $fname;

                $profiles[$fname] = $f;
				
				$params = new JRegistry(file_get_contents($path . DIRECTORY_SEPARATOR . $fname . '.ini'));
                $jsonData[$fname] = $params->toArray();
            }
        }

        $xmlparams = JPATH_SITE . DIRECTORY_SEPARATOR . 'modules' . DIRECTORY_SEPARATOR . $module . DIRECTORY_SEPARATOR . 'config.xml';
        if (file_exists($xmlparams)) {
            /* For General Form */
            $t3form = JForm::getInstance('jform', $xmlparams, array('control' => 't3form'));

			$profileHTML = JHTML::_('select.genericlist', $profiles, '' . $this->name, 'onchange="JAFileConfig.changeProfile(this.value)"', 'id', 'title', $this->value);

			ob_start();
				require_once dirname(__FILE__) . DIRECTORY_SEPARATOR . 'tpls' . DIRECTORY_SEPARATOR . 'profile.php';
				$content = ob_get_clean();
			ob_end_flush();
			
			return $content;
		}
    }
	
    /**
     *
     * Get Label of element param
     * @return string label
     */
	function getLabel()
	{
		$func 	= (string)$this->element['function']?(string)$this->element['function']:'';
		if (substr($func, 0, 1) == '@' || !isset( $this->label ) || !$this->label){
			return;
		} else {
			return parent::getLabel ();
		}
	}
	
	/**
	 * render title: name="@title"
     * @param	string	$name The name of element param
     * @param	string	$value	The value of element
     * @param	object	$node The node of element
     * @param	string	$control_name
     * @return	string  title
     */
    function title()
    {
        $_title = (string) $this->element['label'];
        $_description = $this->description;
        $_url = (isset($this->element['url'])) ? (string) $this->element['url'] : '';
        $class = (isset($this->element['class'])) ? (string) $this->element['class'] : '';
        $level = (isset($this->element['level'])) ? (string) $this->element['level'] : '';
        $group = (isset($this->element['group'])) ? (string) $this->element['group'] : '';
        $group = $group ? "id='params$group-group'" : "";
        if ($_title) {
            $_title = html_entity_decode(JText::_($_title));
        }

        if ($_description) {
            $_description = html_entity_decode(JText::_($_description));
        }
        if ($_url) {
            $_url = " <a target='_blank' href='{$_url}' >[" . html_entity_decode(JText::_("Demo")) . "]</a> ";
        }
		
		$regionID = time()+rand();
		
		$class_name = trim(str_replace(" ", "", strtolower($_title) ));
		
		if($level==1){
			$html = '
				<h4 rel="'.$level.'" class="block-head block-head-'.$class_name.' open '.$class.' " '.$group.' id="'.$regionID.'">
					<span class="block-setting" >'.$_title.$_url.'</span> 
					<span class="icon-help editlinktip hasTip" title="'.htmlentities($_description).'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>
					<a class="toggle-btn open" title="'.JText::_('Expand all').'" onclick="T3Depend.showseg(\''.$regionID.'\', \'level'.$level.'\'); return false;">'.JText::_('Expand all').'</a>
					<a class="toggle-btn close" title="'.JText::_('Collapse all').'" onclick="T3Depend.showseg(\''.$regionID.'\', \'level'.$level.'\'); return false;">'.JText::_('Collapse all').'</a>
		    </h4>';
		} else {
			$html = '
				<h4 rel="'.$level.'" class="block-head block-head-'.$class_name.' open '.$class.' " '.$group.' id="'.$regionID.'">
					<span class="block-setting" >'.$_title.$_url.'</span> 
					<span class="icon-help editlinktip hasTip" title="'.htmlentities($_description).'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>
					<a class="toggle-btn" title="'.JText::_('Click here to expand or collapse').'" onclick="T3Depend.segment(\''.$regionID.'\', \'level'.$level.'\'); return false;">open</a>
		    </h4>';
		} 
		//<div class="block-des '.$class.'"  id="desc-'.$regionID.'">'.$_description.'</div>';
		
		return $html;
	}
	
	/**
	 * Subtype - Checkbox: subtype="checkbox"
	 */
	function checkbox(){		
		$k = 0;
		$html = "";
		
		$cols = intval($this->element['cols']);
		if($cols == 0){
			$cols = 1;
		}
		$width = floor(100/$cols);
		$style = ' style="width:'.$width.'%;"';
		if($this->element->children()){
			foreach ($this->element->children() as $option)
			{
				$group = isset($option['group'])?intval($option['group']):0;
				$odesc	= isset($option['description'])?JText::_($option['description']):'';
				$otext	= JText::_(trim((string) $option));
	
				$tooltip	= addslashes(htmlspecialchars($odesc, ENT_QUOTES, 'UTF-8'));
				$titletip		= addslashes(htmlspecialchars($otext, ENT_QUOTES, 'UTF-8'));
	
				if($titletip) {
					$titletip = $titletip.'::';
				}
				
				if($group) {
					$html .= "\n\t<div class=\"group_title\"><span class=\"hasTip\" title=\"{$titletip}{$tooltip}\">$otext</span></div>";
				} else {
				
					
					$oval	= $option['value'];
					$children	= $option['children'];
					$alt = ($children) ? ' alt="'.$children.'"' : '';
					$extra	 = '';
		
					if (is_array( $this->value ))
					{
						foreach ($this->value as $val)
						{
							$val2 = is_object( $val ) ? $val->$key : $val;
							if ($oval == $val2)
							{
								$extra .= ' checked="checked"';
								break;
							}
						}
					} else {
						$extra .= ( (string)$oval == (string)$this->value  ? ' checked="checked"' : '' );
					}
					
					$html .= "\n\t<div class=\"group_item\" $style>";	
					$html .= "\n\t<input type=\"checkbox\" name=\"{$this->name}[]\" id=\"{$this->id}{$k}\" value=\"$oval\"$extra $alt />";
					$html .= "\n\t<label id=\"{$this->id}{$k}-label\" class=\"hasTip\" title=\"{$titletip}{$tooltip}\" for=\"{$this->id}{$k}\">$otext</label>";
					$html .= "\n\t</div>";
					
					$k++;
				}
			}
		}

		return $html;
	}
	
	/**
	 * render js to control setting form.
     * @param	string	$name The name of element param
     * @param	string	$value	The value of element
     * @param	object	$node The node of element
     * @param	string	$control_name
     * @return	string  group param
	 */
	function group(){
		$this->loadAsset();

		if(preg_match_all('@\[([^\]]*)\]@', $this->name, $matches)) {

			$group_name = str_replace(end($matches[0]), '', $this->name);

			$script = 'jQuery(document).ready(function(){';
			foreach ($this->element->children() as $option) {
				$elms = preg_replace('/\s+/', '', (string)$option[0]);
				$vals = preg_replace('/\s+/', '', $option['value']);
				$hide = isset($option['hide']) ? !in_array($option['hide'], array('false', '', '0', 'no', 'off')) : 1;
				$hide = (int)$hide;
			
				$script .= "T3Depend.add('" . $option['for'] . "', { \n"
					. "vals: '$vals',\n"
					. "elms: '$elms',\n"
					. "group: '$group_name',\n"
					. "hide: $hide"
				. "});";
			}

			$script .= "});";

			$jdoc = JFactory::getDocument();
			$jdoc->addScriptDeclaration($script);
		}

/*
		?>
		<script type="text/javascript">
			jQuery(document).ready(function(){
			<?php 
			foreach ($this->element->children() as $option):
				$elms = preg_replace('/\s+/', '', (string)$option[0]);
				$vals = preg_replace('/\s+/', '', $option['value']);
				$hide = isset($option['hide']) ? !in_array($option['hide'], array('false', '', '0', 'no', 'off')) : 1;
			?>
				T3Depend.add('<?php echo $option['for']; ?>', {
					vals: '<?php echo $vals ?>',
					elms: '<?php echo $elms?>',
					group: '<?php echo $group_name; ?>',
					hide: <?php echo (int)$hide; ?>
				});
			<?php
				endforeach;
			?>
			});
		</script>
		<?php
		endif; */
	}

	function ajax(){
		$fcalls = array();

		foreach ($this->element->children() as $option) {
			$fparams = array();
			if (!empty($option['url'])){
				$fparams['url'] = (string)$option['url'];
			}

			if (!empty($option['site'])){
				$fparams['site'] = (string)$option['site'];
			}

			if (!empty($option['query'])){
				$fparams['query'] = (string)$option['query'];				
			} else {
				$fparams['query'] = '';
			}
			// append styleid into query
			$input = JFactory::getApplication()->input;
			$task = $input->getCmd('task') !== null ? $input->getCmd('task') : '';
			if($input->getCmd('option') == 'com_templates' && 
					(preg_match('/style\./', $task) || $input->getCmd('view') == 'style' || $input->getCmd('view') == 'template')){
				$fparams['query'] .= '&styleid='.$input->getInt('id');
			}

			if (!empty($option['func'])){
				$fparams['func'] = (string)$option['func'];
			}

			$fcalls[] = 'T3Depend.addajax(\'' . $this->getName($option['for']) . '\', ' . json_encode($fparams) . ');';
		}

		$jdoc = JFactory::getDocument();
		$jdoc->addScriptDeclaration("jQuery(window).on('load', function(){ " . implode("\n", $fcalls) . "});");
		/*
		?>
		<script type="text/javascript">
			//<![CDATA[
			jQuery(window).on('load', function(){
				<?php echo implode("\n", $fcalls); ?>
			});
			//]]>
		</script>
		<?php */
	}

	function legend(){
		return '<legend class="t3-admin-form-legend">' . JText::_($this->element['label']) . '<small class="t3-admin-form-legend-desc">' . JText::_($this->element['description']) . '</small> </legend>';
	}
} depend/t3megamenu.php000060400000007574152455303030010572 0ustar00<?php
/** 
 *------------------------------------------------------------------------------
 * @package       T3 Framework for Joomla!
 *------------------------------------------------------------------------------
 * @copyright     Copyright (C) 2004-2013 JoomlArt.com. All Rights Reserved.
 * @license       GNU General Public License version 2 or later; see LICENSE.txt
 * @authors       JoomlArt, JoomlaBamboo, (contribute to this project at github 
 *                & Google group to become co-author)
 * @Google group: https://groups.google.com/forum/#!forum/t3fw
 * @Link:         http://t3-framework.org 
 *------------------------------------------------------------------------------
 */


defined('JPATH_PLATFORM') or die;

JFormHelper::loadFieldClass('hidden');

// Import the com_menus helper.
require_once realpath(JPATH_ADMINISTRATOR . '/components/com_menus/helpers/menus.php');

/**
 * Supports an HTML select list of menus
 *
 * @package     Joomla.Libraries
 * @subpackage  Form
 * @since       1.6
 */
class JFormFieldT3MegaMenu extends JFormFieldHidden
{
	/**
	 * The form field type.
	 *
	 * @var    string
	 * @since  1.6
	 */
	public $type = 'T3MegaMenu';

	/**
	 * Method to get the list of menus for the field options.
	 *
	 * @return  array  The field option objects.
	 *
	 * @since   1.6
	 */
	protected function getOptions()
	{
		// Merge any additional options in the XML definition.
		$options = array_merge(parent::getOptions(), JHtml::_('menu.menus'));

		return $options;
	}

	/**
	 * Method to get the field input markup for a generic list.
	 * Use the multiple attribute to enable multiselect.
	 *
	 * @return  string  The field input markup.
	 *
	 * @since   11.1
	 */
	protected function getInput()
	{
		return parent::getInput() . "\n" . $this->getMegaMenuMarkup();
	}

	/**
	 * Method to get the field input markup for a generic list.
	 * Use the multiple attribute to enable multiselect.
	 *
	 * @return  string  The field input markup.
	 *
	 * @since   11.1
	 */
	protected function getMegaMenuMarkup()
	{
		if(!defined('T3')){
			return false;
		}

		if(!defined('T3_TEMPLATE')){
			$this->loadT3Depend();
		}

		$t3path = T3_ADMIN_PATH;
		
		if(!defined('__T3_MEGAMENU_ASSET__')){
			define('__T3_MEGAMENU_ASSET__', 1);

			$jdoc = JFactory::getDocument();

			if(is_file(T3_PATH . '/css/megamenu.css')){
				$jdoc->addStylesheet(T3_URL . '/css/megamenu.css');
			}

			if(is_file(T3_ADMIN_PATH . '/admin/megamenu/css/megamenu.css')){
				$jdoc->addStylesheet(T3_ADMIN_URL . '/admin/megamenu/css/megamenu.css');
			}

			if(version_compare(JVERSION, '3.0', 'ge')){
				JHtml::_('jquery.framework');
			} else {
				$jdoc->addScript(T3_ADMIN_URL . '/admin/js/jquery-1.x.min.js');
				$jdoc->addScript(T3_ADMIN_URL . '/admin/js/jquery.noconflict.js');
			}
			
			if(is_file(T3_ADMIN_PATH . '/admin/megamenu/js/megamenu.js')){
				$jdoc->addScript(T3_ADMIN_URL . '/admin/megamenu/js/megamenu.js');
			}
		}

		if(is_file(T3_ADMIN_PATH . '/admin/megamenu/megamenu.tpl.php')){
			include T3_ADMIN_PATH . '/admin/megamenu/megamenu.tpl.php';
		}

		if($this->element['hide']):
		?>
		<script type="text/javascript">
			//<![CDATA[
			jQuery(document).ready(function($){
				$('#<?php echo $this->id ?>').closest('li, div.control-group').css('display', 'none');
			});
			//]]>
		</script>
		<?php
		endif;
	}

	/**
	 * Check and load assets file if needed
	 */
	function loadT3Depend(){
		if (!defined ('_T3_DEPEND_ASSET_')) {
			define ('_T3_DEPEND_ASSET_', 1);
			
			JFactory::getLanguage()->load(T3_PLUGIN, JPATH_ADMINISTRATOR);
			
			$jdoc = JFactory::getDocument();	
			$jdoc->addStyleSheet(T3_ADMIN_URL . '/includes/depend/css/depend.css');
			$jdoc->addScript(T3_ADMIN_URL . '/includes/depend/js/depend.js');

			JFactory::getDocument()->addScriptDeclaration ( '
				jQuery.extend(T3Depend, {
					adminurl: \'' . JUri::getInstance()->toString() . '\',
					rooturl: \'' . JURI::root() . '\'
				});
			');
		}
	}
}depend/tpls/profile.php000060400000010713152455303030011134 0ustar00<?php
/** 
 *------------------------------------------------------------------------------
 * @package       T3 Framework for Joomla!
 *------------------------------------------------------------------------------
 * @copyright     Copyright (C) 2004-2013 JoomlArt.com. All Rights Reserved.
 * @license       GNU General Public License version 2 or later; see LICENSE.txt
 * @authors       JoomlArt, JoomlaBamboo, (contribute to this project at github 
 *                & Google group to become co-author)
 * @Google group: https://groups.google.com/forum/#!forum/t3fw
 * @Link:         http://t3-framework.org 
 *------------------------------------------------------------------------------
 */

// no direct access
defined ( '_JEXEC' ) or die ( 'Restricted access' );

$javersion = new JVersion;

?>
	<script type="text/javascript">
		!function($){
			var JAFileConfig = window.JAFileConfig || {};

			JAFileConfig.profiles = <?php echo json_encode($jsonData)?>;
			JAFileConfig.mod_url = '<?php echo JURI::base(true) ?>/modules/<?php echo $module; ?>/helper.php';
			JAFileConfig.template = '<?php echo $template ?>';
			JAFileConfig.langs = <?php json_encode(array(
					'confirmCancel' => JText::_('ARE_YOUR_SURE_TO_CANCEL'),
					'enterName' => JText::_('ENTER_PROFILE_NAME'),
					'correctName' => JText::_('PROFILE_NAME_NOT_EMPTY'),
					'confirmDelete' => JText::_('CONFIRM_DELETE_PROFILE')
				)); ?>;
			
			$(window).on('load', function(){
				JAFileConfig.initialize('jformparams<?php echo str_replace('holder', '', $this->fieldname);?>');
				JAFileConfig.changeProfile($('jformparams<?php echo str_replace('holder', '', $this->fieldname);?>').val());
			});

		}(jQuery);
	</script>

	<div class="t3-profile">
		<label class="hasTip" for="jform_params_<?php echo $this->field_name?>" id="jform_params_<?php echo $this->field_name?>-lbl" title="<?php echo JText::_($this->element['description'])?>"><?php echo JText::_($this->element["label"])?></label>
		<?php echo $profileHTML; ?>
		<div class="profile_action">
			<span class="clone">
				<a href="javascript:void(0)" onclick="JAFileConfig.cloneProfile()" title="<?php echo JText::_('CLONE_DESC')?>"><?php echo JText::_('Clone')?></a>
			</span>
			| 
			<span class="delete">
				<a href="javascript:void(0)" onclick="JAFileConfig.deleteProfile()" title="<?php echo JText::_('DELETE_DESC')?>"><?php echo JText::_('Delete')?></a>
			</span>	
		</div>
	</div>

<?php if($javersion->isCompatible('3.0')) : ?>
	</div>
</div>
<?php else : ?>
</li>
<?php endif; ?>

<?php		
$fieldSets = $t3form->getFieldsets('params');

foreach ($fieldSets as $name => $fieldSet) :
	if (isset($fieldSet->description) && trim($fieldSet->description)){
		echo '<p class="tip">'.JText::_($fieldSet->description).'</p>';
	}
	
	$hidden_fields = '';
	foreach ($t3form->getFieldset($name) as $field) :
		if (!$field->hidden) :
			if($javersion->isCompatible('3.0')) : ?>
		<div class="control-group t3-control-group">
			<div class="control-label t3-control-label">
			<?php else: ?> 
		<li>
			<?php endif;
				echo $t3form->getLabel($field->fieldname,$field->group);
			
				if($javersion->isCompatible('3.0')) : ?>
			</div>
			<div class="controls t3-controls">
				<?php endif;
				echo $t3form->getInput($field->fieldname,$field->group);
				if($javersion->isCompatible('3.0')) : ?>
			</div>
		</div>
			<?php else: ?> 
		</li>
			<?php endif;
		else : 
			$hidden_fields .= $t3form->getInput($field->fieldname,$field->group);	
		endif;
	endforeach;
	echo $hidden_fields; 
endforeach; 
?>	
	
<?php 
	if($javersion->isCompatible('3.0')) : ?>
		<div class="control-group t3-control-group hide">
			<div class="control-label t3-control-label"></div>
				<div class="controls t3-controls">
	<?php else: ?> 
		<li>
	<?php endif; ?>
		<script type="text/javascript">
			// <![CDATA[ 
			window.addEvent('load', function(){
				Joomla.submitbutton = function(task){
					if (task == 'module.cancel' || document.formvalidator.isValid(document.getElementById('module-form'))) {	
						if(task != 'module.cancel' && document.formvalidator.isValid(document.getElementById('module-form'))){
							JAFileConfig.saveProfile(task);
						}else if(task == 'module.cancel' || document.formvalidator.isValid(document.getElementById('module-form'))){
							Joomla.submitform(task, document.getElementById('module-form'));
						}
						if (self != top) {
							window.top.setTimeout('window.parent.SqueezeBox.close()', 1000);
						}
					} else {
						alert('Invalid form');
					}
				}
			});
			// ]]> 
		</script>
depend/t3positions.php000060400000007460152455303030011015 0ustar00<?php
/** 
 *------------------------------------------------------------------------------
 * @package       T3 Framework for Joomla!
 *------------------------------------------------------------------------------
 * @copyright     Copyright (C) 2004-2013 JoomlArt.com. All Rights Reserved.
 * @license       GNU General Public License version 2 or later; see LICENSE.txt
 * @authors       JoomlArt, JoomlaBamboo, (contribute to this project at github 
 *                & Google group to become co-author)
 * @Google group: https://groups.google.com/forum/#!forum/t3fw
 * @Link:         http://t3-framework.org 
 *------------------------------------------------------------------------------
 */

// No direct access
defined('_JEXEC') or die;

/**
 * Radio List Element
 *
 * @package  T3.Core.Element
 */
class JFormFieldT3Positions extends JFormField
{
	/**
	 * Element name
	 *
	 * @access    protected
	 * @var        string
	 */
	protected $type = 'T3Positions';

	/**
	 * Check and load assets file if needed
	 */
	function loadAsset(){
		if (!defined ('_T3_DEPEND_ASSET_')) {
			define ('_T3_DEPEND_ASSET_', 1);

			$jdoc = JFactory::getDocument();

			if(!defined('T3_TEMPLATE')){
				JFactory::getLanguage()->load(T3_PLUGIN, JPATH_ADMINISTRATOR);

				if(version_compare(JVERSION, '3.0', 'ge')){
					JHtml::_('jquery.framework');
				} else {
					$jdoc->addScript(T3_ADMIN_URL . '/admin/js/jquery-1.x.min.js');
					$jdoc->addScript(T3_ADMIN_URL . '/admin/js/jquery.noconflict.js');
				}

				$jdoc->addStyleSheet(T3_ADMIN_URL . '/includes/depend/css/depend.css');
				$jdoc->addScript(T3_ADMIN_URL . '/includes/depend/js/depend.js');
			}

			JFactory::getDocument()->addScriptDeclaration ( '
				jQuery.extend(T3Depend, {
					adminurl: \'' . JUri::getInstance()->toString() . '\',
					rooturl: \'' . JURI::root() . '\'
				});
			');
		}
	}
	
	/**
	 * Method to get the field input markup.
	 *
	 * @return  string  The field input markup.
	 */
	function getInput()
	{
		$this->loadAsset();

		T3::import('admin/layout');
		
		return $this->getPositions();
	}
	
	function getPositions()
	{
		$path     = JPATH_SITE;
		$lang     = JFactory::getLanguage();
		$clientId = 0;
		$state    = 1;
		
		$templates      = array_keys(T3AdminLayout::getTemplates($clientId, $state));
		$templateGroups = array();
		
		// Add positions from templates
		foreach ($templates as $template) {
			$options = array();
			
			$positions = T3AdminLayout::getTplPositions($clientId, $template);
			if (is_array($positions))
				foreach ($positions as $position) {
					$text      = T3AdminLayout::getTranslatedModulePosition($clientId, $template, $position) . ' [' . $position . ']';
					$options[] = T3AdminLayout::createOption($position, $text);
				}
			
			$templateGroups[$template] = T3AdminLayout::createOptionGroup(ucfirst($template), $options);
		}
		
		// Add custom position to options
		$customGroupText                  = JText::_('T3_LAYOUT_CUSTOM_POSITION');
		$customPositions                  = T3AdminLayout::getDbPositions($clientId);
		$templateGroups[$customGroupText] = T3AdminLayout::createOptionGroup($customGroupText, $customPositions);


		$multiple = $this->toBoolean((string) $this->element['multiple']);
		$disabled = $this->toBoolean((string) $this->element['disabled']);
		
		
		return JHtml::_('select.groupedlist', $templateGroups, $this->name,
            array(
                'list.attr' => ($multiple ? ' multiple="multiple" size="10"' : '')
                    . ($disabled ? 'disabled="disabled"' : '') . "class='form-select form-select-color-state'",
                'list.select' => $this->value,
            )
        );
	}


	/**
	 * Helper function, check the field attribute and return boolean value
	 *
	 * @return  boolean the check result
	 */
	function toBoolean($attr){
		return !in_array($attr, array('false', '', '0', 'no', 'off'));
	}
}format/less3.3.php000060400000007423152455303030007741 0ustar00<?php
/** 
 *------------------------------------------------------------------------------
 * @package       T3 Framework for Joomla!
 *------------------------------------------------------------------------------
 * @copyright     Copyright (C) 2004-2013 JoomlArt.com. All Rights Reserved.
 * @license       GNU General Public License version 2 or later; see LICENSE.txt
 * @authors       JoomlArt, JoomlaBamboo, (contribute to this project at github 
 *                & Google group to become co-author)
 * @Google group: https://groups.google.com/forum/#!forum/t3fw
 * @Link:         http://t3-framework.org 
 *------------------------------------------------------------------------------
 */

namespace Joomla\Registry\Format;

use Joomla\Registry\AbstractRegistryFormat;
use stdClass;

/**
 * PHP class format handler for Registry
 *
 * @since  1.0
 */
class Less
{
	/**
	 * Converts a name/value pairs object into an LESS variables declaration
	 */
	public function objectToString($object, $params = array())
	{
		// Initialize variables.
		$result = array();
		$import_urls = '';

		// Iterate over the object to set the properties.
		foreach (get_object_vars($object) as $key => $value)
		{
			// If the value is an object then we need to put it in a local section.
			if ($key == 'import-external-urls') {
				$import_urls = explode ("\n", $value);
			} else {
				$result[] = $this->getKey($key) . ': ' . $this->getValue($value);
			}
		}

		$output = '';
		if (is_array ($import_urls)) {
			foreach ($import_urls as $url) {
				$output .= "@import url({$url});\n";
			}
		}

		$output .= "\n" . implode("\n", $result);

		return $output;
	}

	/**
	 * Converts an LESS variables string to name/value pair object
	 */
	public function stringToObject($data, array $options = array())   
	{
		// If no lines present just return the object.
		if (empty($data))
		{
			return new stdClass;
		}

		// Initialize variables.
		$obj = new stdClass;
		$lines = explode("\n", $data);
		$import_urls = array();

		// Process the lines.
		foreach ($lines as $line)
		{
			// Trim any unnecessary whitespace.
			$line = trim($line);

			// Ignore empty lines and comments.
			if (empty($line) || (substr($line, 0, 1) == '/') || (substr($line, 0, 1) == '*'))
			{
				continue;
			}

			// if url import
			if (preg_match ('/@import\s+url\((.+)\);/', $line, $match)) {
				$import_urls[] = $match[1];
				continue;
			}

			// Check that an equal sign exists and is not the first character of the line.
			if (!strpos($line, ':'))
			{
				// Maybe throw exception?
				continue;
			}

			// Get the key and value for the line.
			list ($key, $value) = explode(':', $line, 2);

			// Validate the key.
			if (preg_match('/@[^A-Z0-9_]/i', $key))
			{
				// Maybe throw exception?
				continue;
			}

			// Validate the value.
			//if (preg_match('/[^\(\)A-Z0-9_-];$/i', $value))
			//{
				// Maybe throw exception?
			//	continue;
			//}
			
			// If the value is quoted then we assume it is a string.
			
			$key = str_replace('@', '', $key);
			$value = str_replace(';', '', $value);
			$value = preg_replace('/\/\/(.*)/', '', $value);
			$value = trim($value);
			$obj->$key = $value;
		}

		// update font import
		$key = 'import-external-urls';
		$obj->$key = implode ("\n", $import_urls);

		// Cache the string to save cpu cycles -- thus the world :)
		
		return $obj;
	}

	/**
	 * Method to get a value in an INI format.
	 *
	 * @param   mixed  $value  The value to convert to INI format.
	 *
	 * @return  string  The value in INI format.
	 *
	 * @since   11.1
	 */
	protected function getValue($value)
	{
		return $value . ';';
	}
	
	/**
	 * Method to get a value in an INI format.
	 *
	 * @param   mixed  $key
	 *
	 * @return  string  The value in INI format.
	 *
	 * @since   11.1
	 */
	protected function getKey($key)
	{
		return '@' . $key;
	}
}
format/less.php000060400000010540152455303030007507 0ustar00<?php
/** 
 *------------------------------------------------------------------------------
 * @package       T3 Framework for Joomla!
 *------------------------------------------------------------------------------
 * @copyright     Copyright (C) 2004-2013 JoomlArt.com. All Rights Reserved.
 * @license       GNU General Public License version 2 or later; see LICENSE.txt
 * @authors       JoomlArt, JoomlaBamboo, (contribute to this project at github 
 *                & Google group to become co-author)
 * @Google group: https://groups.google.com/forum/#!forum/t3fw
 * @Link:         http://t3-framework.org 
 *------------------------------------------------------------------------------
 */

defined('JPATH_PLATFORM') or die;

/**
 * INI format handler for JRegistry.
 *
 * @package     Joomla.Platform
 * @subpackage  Registry
 * @since       11.1
 */
class JRegistryFormatLESS
{
	/**
	 * Converts an object into an INI formatted string
	 * -	Unfortunately, there is no way to have ini values nested further than two
	 * levels deep.  Therefore we will only go through the first two levels of
	 * the object.
	 *
	 * @param   object  $object   Data source object.
	 * @param   array   $options  Options used by the formatter.
	 *
	 * @return  string  INI formatted string.
	 *
	 * @since   11.1
	 */
	public function objectToString($object, $options = array())
	{
		// Initialize variables.
		$result = array();
		$import_urls = '';

		// Iterate over the object to set the properties.
		foreach (get_object_vars($object) as $key => $value)
		{
			// If the value is an object then we need to put it in a local section.
			if ($key == 'import-external-urls') {
				$import_urls = explode ("\n", $value);
			} else {
				$result[] = $this->getKey($key) . ': ' . $this->getValue($value);
			}
		}

		$output = '';
		if (is_array ($import_urls)) {
			foreach ($import_urls as $url) {
				$output .= "@import url({$url});\n";
			}
		}

		$output .= "\n" . implode("\n", $result);

		return $output;
	}

	/**
	 * Parse an INI formatted string and convert it into an object.
	 *
	 * @param   string  $data     INI formatted string to convert.
	 * @param   mixed   $options  An array of options used by the formatter, or a boolean setting to process sections.
	 *
	 * @return  object   Data object.
	 *
	 * @since   11.1
	 */
	public function stringToObject($data, $options = array())
	{
		// If no lines present just return the object.
		if (empty($data))
		{
			return new stdClass;
		}

		// Initialize variables.
		$obj = new stdClass;
		$lines = explode("\n", $data);
		$import_urls = array();

		// Process the lines.
		foreach ($lines as $line)
		{
			// Trim any unnecessary whitespace.
			$line = trim($line);

			// Ignore empty lines and comments.
			if (empty($line) || (substr($line, 0, 1) == '/') || (substr($line, 0, 1) == '*'))
			{
				continue;
			}

			// if url import
			if (preg_match ('/@import\s+url\((.+)\);/', $line, $match)) {
				$import_urls[] = $match[1];
				continue;
			}

			// Check that an equal sign exists and is not the first character of the line.
			if (!strpos($line, ':'))
			{
				// Maybe throw exception?
				continue;
			}

			// Get the key and value for the line.
			list ($key, $value) = explode(':', $line, 2);

			// Validate the key.
			if (preg_match('/@[^A-Z0-9_]/i', $key))
			{
				// Maybe throw exception?
				continue;
			}

			// Validate the value.
			//if (preg_match('/[^\(\)A-Z0-9_-];$/i', $value))
			//{
				// Maybe throw exception?
			//	continue;
			//}
			
			// If the value is quoted then we assume it is a string.
			
			$key = str_replace('@', '', $key);
			$value = str_replace(';', '', $value);
			$value = preg_replace('/\/\/(.*)/', '', $value);
			$value = trim($value);
			$obj->$key = $value;
		}

		// update font import
		$key = 'import-external-urls';
		$obj->$key = implode ("\n", $import_urls);

		// Cache the string to save cpu cycles -- thus the world :)
		
		return $obj;
	}

	/**
	 * Method to get a value in an INI format.
	 *
	 * @param   mixed  $value  The value to convert to INI format.
	 *
	 * @return  string  The value in INI format.
	 *
	 * @since   11.1
	 */
	protected function getValue($value)
	{
		return $value . ';';
	}
	
	/**
	 * Method to get a value in an INI format.
	 *
	 * @param   mixed  $key
	 *
	 * @return  string  The value in INI format.
	 *
	 * @since   11.1
	 */
	protected function getKey($key)
	{
		return '@' . $key;
	}
}
extendable/extendable.php000060400000003605152455303030011503 0ustar00<?php
 /** 
  *------------------------------------------------------------------------
  * T3 Framework for Joomla!
  * ------------------------------------------------------------------------
  * Copyright (C) 2004-2013 JoomlArt.com, Ltd. All Rights Reserved.
  * License - GNU/GPL, http://www.gnu.org/licenses/gpl.html
  * Authors:  JoomlArt, JoomlaBamboo 
  * If you want to be come co-authors of this project, please follow our guidelines at http://t3-framework.org/contribute
  * ------------------------------------------------------------------------
  */

// No direct access
defined('_JEXEC') or die();

define('_PHP_', intval(phpversion()));

if (! function_exists('property_exists')) {
    /**
     * Check property of object exists or not
     *
     * @param object $oObject    Checked object
     * @param string $sProperty  Property name
     *
     * @return bool  TRUE if exists, otherwise FALSE
     */
    function property_exists($oObject, $sProperty)
    {
        if (is_object($oObject)) {
            $oObject = get_class($oObject);
        }

        return array_key_exists($sProperty, get_class_vars($oObject));
    }
}

/**
 * Check method of object is callable or not
 *
 * @param object $oObject  Checked object
 * @param string $sMethod  Method name
 *
 * @return bool  TRUE if exists, otherwise FALSE
 */
function method_callable($oObject, $sMethod)
{
    // must be object or string
    if (! is_object($oObject) && ! is_string($oObject)) {
        return false;
    }

    return array_key_exists($sMethod, array_flip(get_class_methods($oObject)));
}

/**
 * Make object extendable
 *
 * @param string $classname  Class name
 *
 * @return void
 */
function make_object_extendable($classname)
{
    if (_PHP_ < 5) {
        overload($classname);
    }
}

if (_PHP_ >= 5) {
    include_once dirname(__FILE__) . '/object.5.php';
} else {
    include_once dirname(__FILE__) . '/object.4.php';
}extendable/object.5.php000060400000004064152455303030011001 0ustar00<?php
 /** 
  *------------------------------------------------------------------------
  * T3 Framework for Joomla!
  * ------------------------------------------------------------------------
  * Copyright (C) 2004-2013 JoomlArt.com, Ltd. All Rights Reserved.
  * License - GNU/GPL, http://www.gnu.org/licenses/gpl.html
  * Authors:  JoomlArt, JoomlaBamboo 
  * If you want to be come co-authors of this project, please follow our guidelines at http://t3-framework.org/contribute
  * ------------------------------------------------------------------------
  */

// No direct access
defined('_JEXEC') or die();

class ObjectExtendable extends JObject
{
    var $_extendableObjects = array();

    function _extend($oObject)
    {
        if (is_object($oObject)) {
            $this->_extendableObjects[] = $oObject;
        } else if (is_array($oObject)) {
            $this->_extendableObjects = array_merge($this->_extendableObjects, $oObject);
        }
    }

    function __get($sName)
    {
        foreach ($this->_extendableObjects as $oObject) {
            if (property_exists($oObject, $sName)) {
                $sValue = $oObject->$sName;
                return $sValue;
            }
        }

        return null;
    }

    function __set($sName, $sValue)
    {
        foreach ($this->_extendableObjects as $oObject) {
            if (property_exists($oObject, $sName)) {
                return $oObject->$sName = $sValue;
            }
        }
    }

    function __call($sName, $aArgs = array())
    {
        // try call itself method
        if (method_exists($this, $sName)) {
            $return = call_user_func_array(array($this, $sName), $aArgs);
            return $return;
        }

        // try to call method extended from objects
        foreach ($this->_extendableObjects as $oObject) {
            //if (method_callable($oObject, $sName)) {
            if (method_exists($oObject, $sName)) {
                $return = call_user_func_array(array($oObject, $sName), $aArgs);
                return $return;
            }
        }

        return NULL;
    }
}extendable/object.4.php000060400000004152152455303030010776 0ustar00<?php
 /** 
  *------------------------------------------------------------------------
  * T3 Framework for Joomla!
  * ------------------------------------------------------------------------
  * Copyright (C) 2004-2013 JoomlArt.com, Ltd. All Rights Reserved.
  * License - GNU/GPL, http://www.gnu.org/licenses/gpl.html
  * Authors:  JoomlArt, JoomlaBamboo 
  * If you want to be come co-authors of this project, please follow our guidelines at http://t3-framework.org/contribute
  * ------------------------------------------------------------------------
  */

// No direct access
defined('_JEXEC') or die();

class ObjectExtendable extends JObject
{
    var $_extendableObjects = array();

    function _extend($oObject)
    {
        $this->_extendableObjects = $oObject;
    }

    function __get($sName, &$sValue)
    {
        for ($i = 0; $i < count($this->_extendableObjects); $i++) {
            if (property_exists($this->_extendableObjects[$i], $sName)) {
                $sValue = $this->_extendableObjects[$i]->$sName;
                return true;
            }
        }

        return false;
    }

    function __set($sName, &$sValue)
    {
        for ($i = 0; $i < count($this->_extendableObjects); $i++) {
            if (property_exists($this->_extendableObjects[$i], $sName)) {
                $this->_extendableObjects[$i]->$sName = $sValue;
                return true;
            }
        }
        return false;
    }

    function __call($sName, $aArgs = array(), &$return)
    {
        // try call itself method
        if (method_exists($this, $sName)) {
            $return = call_user_func_array(array($this, $sName), $aArgs);
            return true;
        }

        // try to call method extended from objects
        for ($i = 0; $i < count($this->_extendableObjects); $i++) {
            //if (method_callable($this->_extendableObjects[$i], $sName)) {
            if (method_exists($this->_extendableObjects[$i], $sName)) {
                $return = call_user_func_array(array(&$this->_extendableObjects[$i], $sName), $aArgs);
                return true;
            }
        }

        return false;
    }
}joomla30/modulehelper.php000060400000040403152455303040011364 0ustar00<?php
/**
 * @package     Joomla.Libraries
 * @subpackage  Module
 *
 * @copyright   Copyright (C) 2005 - 2016 Open Source Matters, Inc. All rights reserved.
 * @license     GNU General Public License version 2 or later; see LICENSE
 */

defined('JPATH_PLATFORM') or die;

use Joomla\Registry\Registry;

/**
 * Module helper class
 *
 * @since  1.5
 */
abstract class JModuleHelper
{
	/**
	 * Get module by name (real, eg 'Breadcrumbs' or folder, eg 'mod_breadcrumbs')
	 *
	 * @param   string  $name   The name of the module
	 * @param   string  $title  The title of the module, optional
	 *
	 * @return  stdClass  The Module object
	 *
	 * @since   1.5
	 */
	public static function &getModule($name, $title = null)
	{
		$result = null;
		$modules =& static::load();
		$total = count($modules);

		for ($i = 0; $i < $total; $i++)
		{
			// Match the name of the module
			if ($modules[$i]->name == $name || $modules[$i]->module == $name)
			{
				// Match the title if we're looking for a specific instance of the module
				if (!$title || $modules[$i]->title == $title)
				{
					// Found it
					$result = &$modules[$i];
					break;
				}
			}
		}

		// If we didn't find it, and the name is mod_something, create a dummy object
		if (is_null($result) && substr($name, 0, 4) == 'mod_')
		{
			$result            = new stdClass;
			$result->id        = 0;
			$result->title     = '';
			$result->module    = $name;
			$result->position  = '';
			$result->content   = '';
			$result->showtitle = 0;
			$result->control   = '';
			$result->params    = '';
		}

		return $result;
	}

	/**
	 * Get modules by position
	 *
	 * @param   string  $position  The position of the module
	 *
	 * @return  array  An array of module objects
	 *
	 * @since   1.5
	 */
	public static function &getModules($position)
	{
		$position = strtolower($position);
		$result = array();
		$input  = JFactory::getApplication()->input;

		$modules =& static::load();

		$total = count($modules);

		for ($i = 0; $i < $total; $i++)
		{
			if ($modules[$i]->position == $position)
			{
				$result[] = &$modules[$i];
			}
		}

		if (count($result) == 0)
		{
			if ($input->getBool('tp') && JComponentHelper::getParams('com_templates')->get('template_positions_display'))
			{
				$result[0] = static::getModule('mod_' . $position);
				$result[0]->title = $position;
				$result[0]->content = $position;
				$result[0]->position = $position;
			}
		}

		return $result;
	}

	/**
	 * Checks if a module is enabled. A given module will only be returned
	 * if it meets the following criteria: it is enabled, it is assigned to
	 * the current menu item or all items, and the user meets the access level
	 * requirements.
	 *
	 * @param   string  $module  The module name
	 *
	 * @return  boolean See description for conditions.
	 *
	 * @since   1.5
	 */
	public static function isEnabled($module)
	{
		$result = static::getModule($module);

		return !is_null($result) && $result->id !== 0;
	}

	/**
	 * Render the module.
	 *
	 * @param   object  $module   A module object.
	 * @param   array   $attribs  An array of attributes for the module (probably from the XML).
	 *
	 * @return  string  The HTML content of the module output.
	 *
	 * @since   1.5
	 */
	public static function renderModule($module, $attribs = array())
	{
		static $chrome;

		// Check that $module is a valid module object
		if (!is_object($module) || !isset($module->module) || !isset($module->params))
		{
			if (JDEBUG)
			{
				JLog::addLogger(array('text_file' => 'jmodulehelper.log.php'), JLog::ALL, array('modulehelper'));
				JLog::add('JModuleHelper::renderModule($module) expects a module object', JLog::DEBUG, 'modulehelper');
			}

			return;
		}

		if (JDEBUG)
		{
			JProfiler::getInstance('Application')->mark('beforeRenderModule ' . $module->module . ' (' . $module->title . ')');
		}

		$app = JFactory::getApplication();

		// Record the scope.
		$scope = $app->scope;

		// Set scope to component name
		$app->scope = $module->module;

		// Get module parameters
		if (class_exists('Registry')) {
			$params = new Registry;
		} else {
			$params = new JRegistry;
		}
		$params->loadString($module->params);

		// Get the template
		$template = $app->getTemplate();

		// Get module path
		$module->module = preg_replace('/[^A-Z0-9_\.-]/i', '', $module->module);
		$path = JPATH_BASE . '/modules/' . $module->module . '/' . $module->module . '.php';

		// Load the module
		if (file_exists($path))
		{
			$lang = JFactory::getLanguage();

			$coreLanguageDirectory      = JPATH_BASE;
			$extensionLanguageDirectory = dirname($path);

			$langPaths = $lang->getPaths();

			// Only load the module's language file if it hasn't been already
			if (!$langPaths || (!isset($langPaths[$coreLanguageDirectory]) && !isset($langPaths[$extensionLanguageDirectory])))
			{
				// 1.5 or Core then 1.6 3PD
				$lang->load($module->module, $coreLanguageDirectory, null, false, true) ||
					$lang->load($module->module, $extensionLanguageDirectory, null, false, true);
			}

			$content = '';
			ob_start();
			include $path;
			$module->content = ob_get_contents() . $content;
			ob_end_clean();
		}

		// Load the module chrome functions
		if (!$chrome)
		{
			$chrome = array();
		}

		include_once JPATH_THEMES . '/system/html/modules.php';
		$chromePath = JPATH_THEMES . '/' . $template . '/html/modules.php';

		if (!isset($chrome[$chromePath]))
		{
			if (file_exists($chromePath))
			{
				include_once $chromePath;
			}

			$chrome[$chromePath] = true;
		}

		// Check if the current module has a style param to override template module style
		$paramsChromeStyle = $params->get('style');

		if ($paramsChromeStyle)
		{
			$attribs['style'] = preg_replace('/^(system|' . $template . ')\-/i', '', $paramsChromeStyle);
		}

		// Make sure a style is set
		if (!isset($attribs['style']))
		{
			$attribs['style'] = 'none';
		}

		// Dynamically add outline style
		if ($app->input->getBool('tp') && JComponentHelper::getParams('com_templates')->get('template_positions_display'))
		{
			$attribs['style'] .= ' outline';
		}

		// If the $module is nulled it will return an empty content, otherwise it will render the module normally.
		$app->triggerEvent('onRenderModule', array(&$module, &$attribs));

		if (is_null($module) || !isset($module->content))
		{
			return '';
		}

		foreach (explode(' ', $attribs['style']) as $style)
		{
			$chromeMethod = 'modChrome_' . $style;

			// Apply chrome and render module
			if (function_exists($chromeMethod))
			{
				$module->style = $attribs['style'];

				ob_start();
				$chromeMethod($module, $params, $attribs);
				$module->content = ob_get_contents();
				ob_end_clean();
			}
		}

		// Revert the scope
		$app->scope = $scope;

		$app->triggerEvent('onAfterRenderModule', array(&$module, &$attribs));

		if (JDEBUG)
		{
			JProfiler::getInstance('Application')->mark('afterRenderModule ' . $module->module . ' (' . $module->title . ')');
		}

		return $module->content;
	}

	/**
	 * Get the path to a layout for a module
	 *
	 * @param   string  $module  The name of the module
	 * @param   string  $layout  The name of the module layout. If alternative layout, in the form template:filename.
	 *
	 * @return  string  The path to the module layout
	 *
	 * @since   1.5
	 */
	public static function getLayoutPath($module, $layout = 'default')
	{
		$template = JFactory::getApplication()->getTemplate();
		$defaultLayout = $layout;

		if (strpos($layout, ':') !== false)
		{
			// Get the template and file name from the string
			$temp = explode(':', $layout);
			$template = ($temp[0] == '_') ? $template : $temp[0];
			$layout = $temp[1];
			$defaultLayout = ($temp[1]) ? $temp[1] : 'default';
		}

		// Do 3rd party stuff to detect layout path for the module
		// onGetLayoutPath should return the path to the $layout of $module or false
		// $results holds an array of results returned from plugins, 1 from each plugin.
		// if a path to the $layout is found and it is a file, return that path
		$app	= JFactory::getApplication();
		$result = $app->triggerEvent( 'onGetLayoutPath', array( $module, $layout ) );
		if (is_array($result))
		{
			foreach ($result as $path)
			{
				if ($path !== false && is_file ($path))
				{
					return $path;
				}
			}
		}

		// Build the template and base path for the layout
		$tPath = JPATH_THEMES . '/' . $template . '/html/' . $module . '/' . $layout . '.php';
		$bPath = JPATH_BASE . '/modules/' . $module . '/tmpl/' . $defaultLayout . '.php';
		$dPath = JPATH_BASE . '/modules/' . $module . '/tmpl/default.php';

		// If the template has a layout override use it
		if (file_exists($tPath))
		{
			return $tPath;
		}

		if (file_exists($bPath))
		{
			return $bPath;
		}

		return $dPath;
	}

	/**
	 * Load published modules.
	 *
	 * @return  array
	 *
	 * @since   1.5
	 * @deprecated  4.0  Use JModuleHelper::load() instead
	 */
	protected static function &_load()
	{
		return static::load();
	}

	/**
	 * Load published modules.
	 *
	 * @return  array
	 *
	 * @since   3.2
	 */
	protected static function &load()
	{
		static $modules;

		if (isset($modules))
		{
			return $modules;
		}

		$app = JFactory::getApplication();

		$modules = null;

		$app->triggerEvent('onPrepareModuleList', array(&$modules));

		// If the onPrepareModuleList event returns an array of modules, then ignore the default module list creation
		if (!is_array($modules))
		{
			$modules = static::getModuleList();
		}

		$app->triggerEvent('onAfterModuleList', array(&$modules));

		$modules = static::cleanModuleList($modules);

		$app->triggerEvent('onAfterCleanModuleList', array(&$modules));

		return $modules;
	}

	/**
	 * Module list
	 *
	 * @return  array
	 */
	public static function getModuleList()
	{
		$app = JFactory::getApplication();
		$Itemid = $app->input->getInt('Itemid');
		$groups = implode(',', JFactory::getUser()->getAuthorisedViewLevels());
		$lang = JFactory::getLanguage()->getTag();
		$clientId = (int) $app->getClientId();

		// Build a cache ID for the resulting data object
		$cacheId = $groups . $clientId . (int) $Itemid;

		$db = JFactory::getDbo();

		$query = $db->getQuery(true)
			->select('m.id, m.title, m.module, m.position, m.content, m.showtitle, m.params, mm.menuid')
			->from('#__modules AS m')
			->join('LEFT', '#__modules_menu AS mm ON mm.moduleid = m.id')
			->where('m.published = 1')
			->join('LEFT', '#__extensions AS e ON e.element = m.module AND e.client_id = m.client_id')
			->where('e.enabled = 1');

		$date = JFactory::getDate();
		$now = $date->toSql();
		$nullDate = $db->getNullDate();
		$query->where('(m.publish_up = ' . $db->quote($nullDate) . ' OR m.publish_up <= ' . $db->quote($now) . ')')
			->where('(m.publish_down = ' . $db->quote($nullDate) . ' OR m.publish_down >= ' . $db->quote($now) . ')')
			->where('m.access IN (' . $groups . ')')
			->where('m.client_id = ' . $clientId)
			->where('(mm.menuid = ' . (int) $Itemid . ' OR mm.menuid <= 0)');

		// Filter by language
		if ($app->isClient('site') && $app->getLanguageFilter())
		{
			$query->where('m.language IN (' . $db->quote($lang) . ',' . $db->quote('*') . ')');
			$cacheId .= $lang . '*';
		}

		$query->order('m.position, m.ordering');

		// Set the query
		$db->setQuery($query);

		try
		{
			/** @var JCacheControllerCallback $cache */
			$cache = JFactory::getCache('com_modules', 'callback');

			$modules = $cache->get(array($db, 'loadObjectList'), array(), md5($cacheId), false);
		}
		catch (RuntimeException $e)
		{
			JLog::add(JText::sprintf('JLIB_APPLICATION_ERROR_MODULE_LOAD', $e->getMessage()), JLog::WARNING, 'jerror');

			return array();
		}

		return $modules;
	}

	/**
	 * Clean the module list
	 *
	 * @param   array  $modules  Array with module objects
	 *
	 * @return  array
	 */
	public static function cleanModuleList($modules)
	{
		// Apply negative selections and eliminate duplicates
		$Itemid = JFactory::getApplication()->input->getInt('Itemid');
		$negId = $Itemid ? -(int) $Itemid : false;
		$clean = array();
		$dupes = array();

		foreach ($modules as $i => $module)
		{
			// The module is excluded if there is an explicit prohibition
			$negHit = ($negId === (int) $module->menuid);

			if (isset($dupes[$module->id]))
			{
				// If this item has been excluded, keep the duplicate flag set,
				// but remove any item from the modules array.
				if ($negHit)
				{
					unset($clean[$module->id]);
				}

				continue;
			}

			$dupes[$module->id] = true;

			// Only accept modules without explicit exclusions.
			if ($negHit)
			{
				continue;
			}

			$module->name = substr($module->module, 4);
			$module->style = null;
			$module->position = strtolower($module->position);

			$clean[$module->id] = $module;
		}

		unset($dupes);

		// Return to simple indexing that matches the query order.
		return array_values($clean);
	}

	/**
	 * Module cache helper
	 *
	 * Caching modes:
	 * To be set in XML:
	 * 'static'      One cache file for all pages with the same module parameters
	 * 'oldstatic'   1.5 definition of module caching, one cache file for all pages
	 *               with the same module id and user aid,
	 * 'itemid'      Changes on itemid change, to be called from inside the module:
	 * 'safeuri'     Id created from $cacheparams->modeparams array,
	 * 'id'          Module sets own cache id's
	 *
	 * @param   object  $module        Module object
	 * @param   object  $moduleparams  Module parameters
	 * @param   object  $cacheparams   Module cache parameters - id or url parameters, depending on the module cache mode
	 *
	 * @return  string
	 *
	 * @see     JFilterInput::clean()
	 * @since   1.6
	 */
	public static function moduleCache($module, $moduleparams, $cacheparams)
	{
		if (!isset($cacheparams->modeparams))
		{
			$cacheparams->modeparams = null;
		}

		if (!isset($cacheparams->cachegroup))
		{
			$cacheparams->cachegroup = $module->module;
		}

		$user = JFactory::getUser();
		$conf = JFactory::getConfig();

		/** @var JCacheControllerCallback $cache */
		$cache = JFactory::getCache($cacheparams->cachegroup, 'callback');

		// Turn cache off for internal callers if parameters are set to off and for all logged in users
		if ($moduleparams->get('owncache', null) === '0' || $conf->get('caching') == 0 || $user->get('id'))
		{
			$cache->setCaching(false);
		}

		// Module cache is set in seconds, global cache in minutes, setLifeTime works in minutes
		$cache->setLifeTime($moduleparams->get('cache_time', $conf->get('cachetime') * 60) / 60);

		$wrkaroundoptions = array('nopathway' => 1, 'nohead' => 0, 'nomodules' => 1, 'modulemode' => 1, 'mergehead' => 1);

		$wrkarounds = true;
		$view_levels = md5(serialize($user->getAuthorisedViewLevels()));

		switch ($cacheparams->cachemode)
		{
			case 'id':
				$ret = $cache->get(
					array($cacheparams->class, $cacheparams->method),
					$cacheparams->methodparams,
					$cacheparams->modeparams,
					$wrkarounds,
					$wrkaroundoptions
				);
				break;

			case 'safeuri':
				$secureid = null;

				if (is_array($cacheparams->modeparams))
				{
					$input   = JFactory::getApplication()->input;
					$uri     = $input->getArray();
					$safeuri = new stdClass;
					$noHtmlFilter = JFilterInput::getInstance();

					foreach ($cacheparams->modeparams as $key => $value)
					{
						// Use int filter for id/catid to clean out spamy slugs
						if (isset($uri[$key]))
						{
							$safeuri->$key = $noHtmlFilter->clean($uri[$key], $value);
						}
					}
				}

				$secureid = md5(serialize(array($safeuri, $cacheparams->method, $moduleparams)));
				$ret = $cache->get(
					array($cacheparams->class, $cacheparams->method),
					$cacheparams->methodparams,
					$module->id . $view_levels . $secureid,
					$wrkarounds,
					$wrkaroundoptions
				);
				break;

			case 'static':
				$ret = $cache->get(
					array($cacheparams->class, $cacheparams->method),
					$cacheparams->methodparams,
					$module->module . md5(serialize($cacheparams->methodparams)),
					$wrkarounds,
					$wrkaroundoptions
				);
				break;

			// Provided for backward compatibility, not really useful.
			case 'oldstatic':
				$ret = $cache->get(
					array($cacheparams->class, $cacheparams->method),
					$cacheparams->methodparams,
					$module->id . $view_levels,
					$wrkarounds,
					$wrkaroundoptions
				);
				break;

			case 'itemid':
			default:
				$ret = $cache->get(
					array($cacheparams->class, $cacheparams->method),
					$cacheparams->methodparams,
					$module->id . $view_levels . JFactory::getApplication()->input->getInt('Itemid', null),
					$wrkarounds,
					$wrkaroundoptions
				);
				break;
		}

		return $ret;
	}
}
joomla30/viewhtml.php000060400000010476152455303040010545 0ustar00<?php
/**
 * @package     Joomla.Platform
 * @subpackage  View
 *
 * @copyright   Copyright (C) 2005 - 2015 Open Source Matters, Inc. All rights reserved.
 * @license     GNU General Public License version 2 or later; see LICENSE
 */

defined('JPATH_PLATFORM') or die;

jimport('joomla.filesystem.path');

/**
 * Joomla Platform HTML View Class
 *
 * @since  12.1
 */
abstract class JViewHtml extends JViewBase
{
  /**
   * The view layout.
   *
   * @var    string
   * @since  12.1
   */
  protected $layout = 'default';

  /**
   * The paths queue.
   *
   * @var    SplPriorityQueue
   * @since  12.1
   */
  protected $paths;

  /* will override the template path */
  protected $_path = array('template' => array(), 'helper' => array());

  /**
   * Method to instantiate the view.
   *
   * @param   JModel            $model  The model object.
   * @param   SplPriorityQueue  $paths  The paths queue.
   *
   * @since   12.1
   */
  public function __construct(JModel $model, SplPriorityQueue $paths = null)
  {
    parent::__construct($model);

    // Setup dependencies.
    $this->paths = isset($paths) ? $paths : $this->loadPaths();

    /* T3: Add T3 html path to the priority paths of component view */
    // T3 html path
    $component = JApplicationHelper::getComponentName();
    $component = preg_replace('/[^A-Z0-9_\.-]/i', '', $component);
    $t3Path = T3_PATH . '/html/' . $component . '/' . $this->getName();
    // Setup the template path
    $this->paths->top();
    $defaultPath = $this->paths->current();
    $this->paths->next();
    $templatePath = $this->paths->current();
    // add t3 path
    $this->paths->insert($t3Path,3);

    $this->_path['template'] = array($defaultPath, $t3Path, $templatePath);
    /* //T3 */
  }

  /**
   * Magic toString method that is a proxy for the render method.
   *
   * @return  string
   *
   * @since   12.1
   */
  public function __toString()
  {
    return $this->render();
  }

  /**
   * Method to escape output.
   *
   * @param   string  $output  The output to escape.
   *
   * @return  string  The escaped output.
   *
   * @see     JView::escape()
   * @since   12.1
   */
  public function escape($output)
  {
    // Escape the output.
    return htmlspecialchars($output, ENT_COMPAT, 'UTF-8');
  }

  /**
   * Method to get the view layout.
   *
   * @return  string  The layout name.
   *
   * @since   12.1
   */
  public function getLayout()
  {
    return $this->layout;
  }

  /**
   * Method to get the layout path.
   *
   * @param   string  $layout  The layout name.
   *
   * @return  mixed  The layout file name if found, false otherwise.
   *
   * @since   12.1
   */
  public function getPath($layout)
  {
    // Get the layout file name.
    $file = JPath::clean($layout . '.php');

    // Find the layout file path.
    $path = JPath::find(clone $this->paths, $file);

    return $path;
  }

  /**
   * Method to get the view paths.
   *
   * @return  SplPriorityQueue  The paths queue.
   *
   * @since   12.1
   */
  public function getPaths()
  {
    return $this->paths;
  }

  /**
   * Method to render the view.
   *
   * @return  string  The rendered view.
   *
   * @since   12.1
   * @throws  RuntimeException
   */
  public function render()
  {
    // Get the layout path.
    $path = $this->getPath($this->getLayout());

    // Check if the layout path was found.
    if (!$path)
    {
      throw new RuntimeException('Layout Path Not Found');
    }

    // Start an output buffer.
    ob_start();

    // Load the layout.
    include $path;

    // Get the layout contents.
    $output = ob_get_clean();

    return $output;
  }

  /**
   * Method to set the view layout.
   *
   * @param   string  $layout  The layout name.
   *
   * @return  JViewHtml  Method supports chaining.
   *
   * @since   12.1
   */
  public function setLayout($layout)
  {
    $this->layout = $layout;

    return $this;
  }

  /**
   * Method to set the view paths.
   *
   * @param   SplPriorityQueue  $paths  The paths queue.
   *
   * @return  JViewHtml  Method supports chaining.
   *
   * @since   12.1
   */
  public function setPaths(SplPriorityQueue $paths)
  {
    $this->paths = $paths;

    return $this;
  }

  /**
   * Method to load the paths queue.
   *
   * @return  SplPriorityQueue  The paths queue.
   *
   * @since   12.1
   */
  protected function loadPaths()
  {
    return new SplPriorityQueue;
  }
}
joomla30/viewlegacy.php000060400000045407152455303040011047 0ustar00<?php
/**
 * @package     Joomla.Legacy
 * @subpackage  View
 *
 * @copyright   Copyright (C) 2005 - 2012 Open Source Matters, Inc. All rights reserved.
 * @license     GNU General Public License version 2 or later; see LICENSE
 */

defined('JPATH_PLATFORM') or die;

/**
 * Base class for a Joomla View
 *
 * Class holding methods for displaying presentation data.
 *
 * @package     Joomla.Legacy
 * @subpackage  View
 * @since       12.2
 */
class JViewLegacy extends JObject
{
	/**
	 * The name of the view
	 *
	 * @var    array
	 */
	protected $_name = null;

	/**
	 * Registered models
	 *
	 * @var    array
	 */
	protected $_models = array();

	/**
	 * The base path of the view
	 *
	 * @var    string
	 */
	protected $_basePath = null;

	/**
	 * The default model
	 *
	 * @var	string
	 */
	protected $_defaultModel = null;

	/**
	 * Layout name
	 *
	 * @var    string
	 */
	protected $_layout = 'default';

	/**
	 * Layout extension
	 *
	 * @var    string
	 */
	protected $_layoutExt = 'php';

	/**
	 * Layout template
	 *
	 * @var    string
	 */
	protected $_layoutTemplate = '_';

	/**
	 * The set of search directories for resources (templates)
	 *
	 * @var array
	 */
	protected $_path = array('template' => array(), 'helper' => array());

	/**
	 * The name of the default template source file.
	 *
	 * @var string
	 */
	protected $_template = null;

	/**
	 * The output of the template script.
	 *
	 * @var string
	 */
	protected $_output = null;

	/**
	 * Callback for escaping.
	 *
	 * @var string
	 * @deprecated 13.3
	 */
	protected $_escape = 'htmlspecialchars';

	/**
	 * Charset to use in escaping mechanisms; defaults to urf8 (UTF-8)
	 *
	 * @var string
	 */
	protected $_charset = 'UTF-8';

	/**
	 * Constructor
	 *
	 * @param   array  $config  A named configuration array for object construction.<br/>
	 *                          name: the name (optional) of the view (defaults to the view class name suffix).<br/>
	 *                          charset: the character set to use for display<br/>
	 *                          escape: the name (optional) of the function to use for escaping strings<br/>
	 *                          base_path: the parent path (optional) of the views directory (defaults to the component folder)<br/>
	 *                          template_plath: the path (optional) of the layout directory (defaults to base_path + /views/ + view name<br/>
	 *                          helper_path: the path (optional) of the helper files (defaults to base_path + /helpers/)<br/>
	 *                          layout: the layout (optional) to use to display the view<br/>
	 *
	 * @since   12.2
	 */
	public function __construct($config = array())
	{
		// Set the view name
		if (empty($this->_name))
		{
			if (array_key_exists('name', $config))
			{
				$this->_name = $config['name'];
			}
			else
			{
				$this->_name = $this->getName();
			}
		}

		// Set the charset (used by the variable escaping functions)
		if (array_key_exists('charset', $config))
		{
			JLog::add('Setting a custom charset for escaping is deprecated. Override JViewLegacy::escape() instead.', JLog::WARNING, 'deprecated');
			$this->_charset = $config['charset'];
		}

		// User-defined escaping callback
		if (array_key_exists('escape', $config))
		{
			$this->setEscape($config['escape']);
		}

		// Set a base path for use by the view
		if (array_key_exists('base_path', $config))
		{
			$this->_basePath = $config['base_path'];
		}
		else
		{
			$this->_basePath = JPATH_COMPONENT;
		}

		// Set the default template search path
		if (array_key_exists('template_path', $config))
		{
			// User-defined dirs
			$this->_setPath('template', $config['template_path']);
		}
		else
		{
			$this->_setPath('template', $this->_basePath . '/views/' . $this->getName() . '/tmpl');
		}

		// Set the default helper search path
		if (array_key_exists('helper_path', $config))
		{
			// User-defined dirs
			$this->_setPath('helper', $config['helper_path']);
		}
		else
		{
			$this->_setPath('helper', $this->_basePath . '/helpers');
		}

		// Set the layout
		if (array_key_exists('layout', $config))
		{
			$this->setLayout($config['layout']);
		}
		else
		{
			$this->setLayout('default');
		}

		$this->baseurl = JURI::base(true);
	}

	/**
	 * Execute and display a template script.
	 *
	 * @param   string  $tpl  The name of the template file to parse; automatically searches through the template paths.
	 *
	 * @return  mixed  A string if successful, otherwise a Error object.
	 *
	 * @see     fetch()
	 * @since   12.2
	 */
	public function display($tpl = null)
	{
		$result = $this->loadTemplate($tpl);
		if ($result instanceof Exception)
		{
			return $result;
		}

		echo $result;
	}

	/**
	 * Assigns variables to the view script via differing strategies.
	 *
	 * This method is overloaded; you can assign all the properties of
	 * an object, an associative array, or a single value by name.
	 *
	 * You are not allowed to set variables that begin with an underscore;
	 * these are either private properties for JView or private variables
	 * within the template script itself.
	 *
	 * <code>
	 * $view = new JView;
	 *
	 * // Assign directly
	 * $view->var1 = 'something';
	 * $view->var2 = 'else';
	 *
	 * // Assign by name and value
	 * $view->assign('var1', 'something');
	 * $view->assign('var2', 'else');
	 *
	 * // Assign by assoc-array
	 * $ary = array('var1' => 'something', 'var2' => 'else');
	 * $view->assign($obj);
	 *
	 * // Assign by object
	 * $obj = new stdClass;
	 * $obj->var1 = 'something';
	 * $obj->var2 = 'else';
	 * $view->assign($obj);
	 *
	 * </code>
	 *
	 * @return  boolean  True on success, false on failure.
	 *
	 * @deprecated  13.3 Use native PHP syntax.
	 */
	public function assign()
	{
		JLog::add(__METHOD__ . ' is deprecated. Use native PHP syntax.', JLog::WARNING, 'deprecated');

		// Get the arguments; there may be 1 or 2.
		$arg0 = @func_get_arg(0);
		$arg1 = @func_get_arg(1);

		// Assign by object
		if (is_object($arg0))
		{
			// Assign public properties
			foreach (get_object_vars($arg0) as $key => $val)
			{
				if (substr($key, 0, 1) != '_')
				{
					$this->$key = $val;
				}
			}
			return true;
		}

		// Assign by associative array
		if (is_array($arg0))
		{
			foreach ($arg0 as $key => $val)
			{
				if (substr($key, 0, 1) != '_')
				{
					$this->$key = $val;
				}
			}
			return true;
		}

		// Assign by string name and mixed value.

		// We use array_key_exists() instead of isset() because isset()
		// fails if the value is set to null.
		if (is_string($arg0) && substr($arg0, 0, 1) != '_' && func_num_args() > 1)
		{
			$this->$arg0 = $arg1;
			return true;
		}

		// $arg0 was not object, array, or string.
		return false;
	}

	/**
	 * Assign variable for the view (by reference).
	 *
	 * You are not allowed to set variables that begin with an underscore;
	 * these are either private properties for JView or private variables
	 * within the template script itself.
	 *
	 * <code>
	 * $view = new JView;
	 *
	 * // Assign by name and value
	 * $view->assignRef('var1', $ref);
	 *
	 * // Assign directly
	 * $view->ref = &$var1;
	 * </code>
	 *
	 * @param   string  $key   The name for the reference in the view.
	 * @param   mixed   &$val  The referenced variable.
	 *
	 * @return  boolean  True on success, false on failure.
	 *
	 * @since   12.2
	 * @deprecated  13.3  Use native PHP syntax.
	 */
	public function assignRef($key, &$val)
	{
		JLog::add(__METHOD__ . ' is deprecated. Use native PHP syntax.', JLog::WARNING, 'deprecated');

		if (is_string($key) && substr($key, 0, 1) != '_')
		{
			$this->$key = &$val;
			return true;
		}

		return false;
	}

	/**
	 * Escapes a value for output in a view script.
	 *
	 * If escaping mechanism is either htmlspecialchars or htmlentities, uses
	 * {@link $_encoding} setting.
	 *
	 * @param   mixed  $var  The output to escape.
	 *
	 * @return  mixed  The escaped value.
	 *
	 * @since   12.2
	 */
	public function escape($var)
	{
		if (in_array($this->_escape, array('htmlspecialchars', 'htmlentities')))
		{
			return call_user_func($this->_escape, $var, ENT_COMPAT, $this->_charset);
		}

		return call_user_func($this->_escape, $var);
	}

	/**
	 * Method to get data from a registered model or a property of the view
	 *
	 * @param   string  $property  The name of the method to call on the model or the property to get
	 * @param   string  $default   The name of the model to reference or the default value [optional]
	 *
	 * @return  mixed  The return value of the method
	 *
	 * @since   12.2
	 */
	public function get($property, $default = null)
	{
		// If $model is null we use the default model
		if (is_null($default))
		{
			$model = $this->_defaultModel;
		}
		else
		{
			$model = strtolower($default);
		}

		// First check to make sure the model requested exists
		if (isset($this->_models[$model]))
		{
			// Model exists, let's build the method name
			$method = 'get' . ucfirst($property);

			// Does the method exist?
			if (method_exists($this->_models[$model], $method))
			{
				// The method exists, let's call it and return what we get
				$result = $this->_models[$model]->$method();
				return $result;
			}

		}

		// Degrade to JObject::get
		$result = parent::get($property, $default);

		return $result;
	}

	/**
	 * Method to get the model object
	 *
	 * @param   string  $name  The name of the model (optional)
	 *
	 * @return  mixed  JModelLegacy object
	 *
	 * @since   12.2
	 */
	public function getModel($name = null)
	{
		if ($name === null)
		{
			$name = $this->_defaultModel;
		}
		return $this->_models[strtolower($name)];
	}

	/**
	 * Get the layout.
	 *
	 * @return  string  The layout name
	 */
	public function getLayout()
	{
		return $this->_layout;
	}

	/**
	 * Get the layout template.
	 *
	 * @return  string  The layout template name
	 */
	public function getLayoutTemplate()
	{
		return $this->_layoutTemplate;
	}

	/**
	 * Method to get the view name
	 *
	 * The model name by default parsed using the classname, or it can be set
	 * by passing a $config['name'] in the class constructor
	 *
	 * @return  string  The name of the model
	 *
	 * @since   12.2
	 * @throws  Exception
	 */
	public function getName()
	{
		if (empty($this->_name))
		{
			$classname = get_class($this);
			$viewpos = strpos($classname, 'View');

			if ($viewpos === false)
			{
				throw new Exception(JText::_('JLIB_APPLICATION_ERROR_VIEW_GET_NAME'), 500);
			}

			$this->_name = strtolower(substr($classname, $viewpos + 4));
		}

		return $this->_name;
	}

	/**
	 * Method to add a model to the view.  We support a multiple model single
	 * view system by which models are referenced by classname.  A caveat to the
	 * classname referencing is that any classname prepended by JModel will be
	 * referenced by the name without JModel, eg. JModelCategory is just
	 * Category.
	 *
	 * @param   JModelLegacy  $model    The model to add to the view.
	 * @param   boolean       $default  Is this the default model?
	 *
	 * @return  object   The added model.
	 *
	 * @since   12.2
	 */
	public function setModel($model, $default = false)
	{
		$name = strtolower($model->getName());
		$this->_models[$name] = $model;

		if ($default)
		{
			$this->_defaultModel = $name;
		}
		return $model;
	}

	/**
	 * Sets the layout name to use
	 *
	 * @param   string  $layout  The layout name or a string in format <template>:<layout file>
	 *
	 * @return  string  Previous value.
	 *
	 * @since   12.2
	 */
	public function setLayout($layout)
	{
		$previous = $this->_layout;
		if (strpos($layout, ':') === false)
		{
			$this->_layout = $layout;
		}
		else
		{
			// Convert parameter to array based on :
			$temp = explode(':', $layout);
			$this->_layout = $temp[1];

			// Set layout template
			$this->_layoutTemplate = $temp[0];
		}

		return $previous;
	}

	/**
	 * Allows a different extension for the layout files to be used
	 *
	 * @param   string  $value  The extension.
	 *
	 * @return  string   Previous value
	 *
	 * @since   12.2
	 */
	public function setLayoutExt($value)
	{
		$previous = $this->_layoutExt;
		if ($value = preg_replace('#[^A-Za-z0-9]#', '', trim($value)))
		{
			$this->_layoutExt = $value;
		}

		return $previous;
	}

	/**
	 * Sets the _escape() callback.
	 *
	 * @param   mixed  $spec  The callback for _escape() to use.
	 *
	 * @return  void
	 *
	 * @since   12.2
	 * @deprecated  13.3  Override JViewLegacy::escape() instead.
	 */
	public function setEscape($spec)
	{
		JLog::add(__METHOD__ . ' is deprecated. Override JViewLegacy::escape() instead.', JLog::WARNING, 'deprecated');

		$this->_escape = $spec;
	}

	/**
	 * Adds to the stack of view script paths in LIFO order.
	 *
	 * @param   mixed  $path  A directory path or an array of paths.
	 *
	 * @return  void
	 *
	 * @since   12.2
	 */
	public function addTemplatePath($path)
	{
		$this->_addPath('template', $path);
	}

	/**
	 * Adds to the stack of helper script paths in LIFO order.
	 *
	 * @param   mixed  $path  A directory path or an array of paths.
	 *
	 * @return  void
	 *
	 * @since   12.2
	 */
	public function addHelperPath($path)
	{
		$this->_addPath('helper', $path);
	}

	/**
	 * Load a template file -- first look in the templates folder for an override
	 *
	 * @param   string  $tpl  The name of the template source file; automatically searches the template paths and compiles as needed.
	 *
	 * @return  string  The output of the the template script.
	 *
	 * @since   12.2
	 * @throws  Exception
	 */
	public function loadTemplate($tpl = null)
	{
		// Clear prior output
		$this->_output = null;

		$template = JFactory::getApplication()->getTemplate();
		$layout = $this->getLayout();
		$layoutTemplate = $this->getLayoutTemplate();

		// Create the template file name based on the layout
		$file = isset($tpl) ? $layout . '_' . $tpl : $layout;

		// Clean the file name
		$file = preg_replace('/[^A-Z0-9_\.-]/i', '', $file);
		$tpl = isset($tpl) ? preg_replace('/[^A-Z0-9_\.-]/i', '', $tpl) : $tpl;

		// Load the language file for the template
		$lang = JFactory::getLanguage();
		$lang->load('tpl_' . $template, JPATH_BASE, null, false, false)
			|| $lang->load('tpl_' . $template, JPATH_THEMES . "/$template", null, false, false)
			|| $lang->load('tpl_' . $template, JPATH_BASE, $lang->getDefault(), false, false)
			|| $lang->load('tpl_' . $template, JPATH_THEMES . "/$template", $lang->getDefault(), false, false);

		// Change the template folder if alternative layout is in different template
		if (isset($layoutTemplate) && $layoutTemplate != '_' && $layoutTemplate != $template)
		{
			$this->_path['template'] = str_replace($template, $layoutTemplate, $this->_path['template']);
		}

		// Load the template script
		jimport('joomla.filesystem.path');
		$filetofind = $this->_createFileName('template', array('name' => $file));
		$this->_template = JPath::find($this->_path['template'], $filetofind);

		// If alternate layout can't be found, fall back to default layout
		if ($this->_template == false)
		{
			$filetofind = $this->_createFileName('', array('name' => 'default' . (isset($tpl) ? '_' . $tpl : $tpl)));
			$this->_template = JPath::find($this->_path['template'], $filetofind);
		}

		if ($this->_template != false)
		{
			// Unset so as not to introduce into template scope
			unset($tpl);
			unset($file);

			// Never allow a 'this' property
			if (isset($this->this))
			{
				unset($this->this);
			}

			// Start capturing output into a buffer
			ob_start();

			// Include the requested template filename in the local scope
			// (this will execute the view logic).
			include $this->_template;

			// Done with the requested template; get the buffer and
			// clear it.
			$this->_output = ob_get_contents();
			ob_end_clean();

			return $this->_output;
		}
		else
		{
			throw new Exception(JText::sprintf('JLIB_APPLICATION_ERROR_LAYOUTFILE_NOT_FOUND', $file), 500);
		}
	}

	/**
	 * Load a helper file
	 *
	 * @param   string  $hlp  The name of the helper source file automatically searches the helper paths and compiles as needed.
	 *
	 * @return  void
	 *
	 * @since   12.2
	 */
	public function loadHelper($hlp = null)
	{
		// Clean the file name
		$file = preg_replace('/[^A-Z0-9_\.-]/i', '', $hlp);

		// Load the template script
		jimport('joomla.filesystem.path');
		$helper = JPath::find($this->_path['helper'], $this->_createFileName('helper', array('name' => $file)));

		if ($helper != false)
		{
			// Include the requested template filename in the local scope
			include_once $helper;
		}
	}

	/**
	 * Sets an entire array of search paths for templates or resources.
	 *
	 * @param   string  $type  The type of path to set, typically 'template'.
	 * @param   mixed   $path  The new search path, or an array of search paths.  If null or false, resets to the current directory only.
	 *
	 * @return  void
	 *
	 * @since   12.2
	 */
	protected function _setPath($type, $path)
	{
		$component = JApplicationHelper::getComponentName();
		$app = JFactory::getApplication();

		// Clear out the prior search dirs
		$this->_path[$type] = array();

		// Actually add the user-specified directories
		$this->_addPath($type, $path);

		// Always add the fallback directories as last resort
		switch (strtolower($type))
		{
			case 'template':
				// Set the alternative template search dir
				if (isset($app))
				{
					$component = preg_replace('/[^A-Z0-9_\.-]/i', '', $component);
					
					//if it is T3 template, update search path for template
					$this->_addPath('template', T3_PATH . '/html/' . $component . '/' . $this->getName());

					$fallback = JPATH_THEMES . '/' . $app->getTemplate() . '/html/' . $component . '/' . $this->getName();
					$this->_addPath('template', $fallback);

					//search path for user custom folder
					if (!defined('T3_LOCAL_DISABLED')) $this->_addPath('template', T3_LOCAL_PATH . '/html/' . $component . '/' . $this->getName());
				}
				break;
		}
	}

	/**
	 * Adds to the search path for templates and resources.
	 *
	 * @param   string  $type  The type of path to add.
	 * @param   mixed   $path  The directory or stream, or an array of either, to search.
	 *
	 * @return  void
	 *
	 * @since   12.2
	 */
	protected function _addPath($type, $path)
	{
		// Just force to array
		settype($path, 'array');

		// Loop through the path directories
		foreach ($path as $dir)
		{
			// No surrounding spaces allowed!
			$dir = trim($dir);

			// Add trailing separators as needed
			if (substr($dir, -1) != DIRECTORY_SEPARATOR)
			{
				// Directory
				$dir .= DIRECTORY_SEPARATOR;
			}

			// Add to the top of the search dirs
			array_unshift($this->_path[$type], $dir);
		}
	}

	/**
	 * Create the filename for a resource
	 *
	 * @param   string  $type   The resource type to create the filename for
	 * @param   array   $parts  An associative array of filename information
	 *
	 * @return  string  The filename
	 *
	 * @since   12.2
	 */
	protected function _createFileName($type, $parts = array())
	{
		$filename = '';

		switch ($type)
		{
			case 'template':
				$filename = strtolower($parts['name']) . '.' . $this->_layoutExt;
				break;

			default:
				$filename = strtolower($parts['name']) . '.php';
				break;
		}
		return $filename;
	}
}
joomla30/pagination.php000060400000054215152455303040011036 0ustar00<?php
/**
 * @package     Joomla.Libraries
 * @subpackage  Pagination
 *
 * @copyright   Copyright (C) 2005 - 2014 Open Source Matters, Inc. All rights reserved.
 * @license     GNU General Public License version 2 or later; see LICENSE
 */

defined('JPATH_PLATFORM') or die;

/**
 * Pagination Class. Provides a common interface for content pagination for the Joomla! CMS.
 *
 * @package     Joomla.Libraries
 * @subpackage  Pagination
 * @since       1.5
 */
class JPagination
{
	/**
	 * @var    integer  The record number to start displaying from.
	 * @since  1.5
	 */
	public $limitstart = null;

	/**
	 * @var    integer  Number of rows to display per page.
	 * @since  1.5
	 */
	public $limit = null;

	/**
	 * @var    integer  Total number of rows.
	 * @since  1.5
	 */
	public $total = null;

	/**
	 * @var    integer  Prefix used for request variables.
	 * @since  1.6
	 */
	public $prefix = null;

	/**
	 * @var    integer  Value pagination object begins at
	 * @since  3.0
	 */
	public $pagesStart;

	/**
	 * @var    integer  Value pagination object ends at
	 * @since  3.0
	 */
	public $pagesStop;

	/**
	 * @var    integer  Current page
	 * @since  3.0
	 */
	public $pagesCurrent;

	/**
	 * @var    integer  Total number of pages
	 * @since  3.0
	 */
	public $pagesTotal;

	/**
	 * @var    boolean  View all flag
	 * @since  3.0
	 */
	protected $viewall = false;

	/**
	 * Additional URL parameters to be added to the pagination URLs generated by the class.  These
	 * may be useful for filters and extra values when dealing with lists and GET requests.
	 *
	 * @var    array
	 * @since  3.0
	 */
	protected $additionalUrlParams = array();

	/**
	 * Constructor.
	 *
	 * @param   integer  $total       The total number of items.
	 * @param   integer  $limitstart  The offset of the item to start at.
	 * @param   integer  $limit       The number of items to display per page.
	 * @param   string   $prefix      The prefix used for request variables.
	 *
	 * @since   1.5
	 */
	public function __construct($total, $limitstart, $limit, $prefix = '')
	{
		// Value/type checking.
		$this->total = (int) $total;
		$this->limitstart = (int) max($limitstart, 0);
		$this->limit = (int) max($limit, 0);
		$this->prefix = $prefix;

		if ($this->limit > $this->total)
		{
			$this->limitstart = 0;
		}

		if (!$this->limit)
		{
			$this->limit = $total;
			$this->limitstart = 0;
		}

		/*
		 * If limitstart is greater than total (i.e. we are asked to display records that don't exist)
		 * then set limitstart to display the last natural page of results
		 */
		if ($this->limitstart > $this->total - $this->limit)
		{
			$this->limitstart = max(0, (int) (ceil($this->total / $this->limit) - 1) * $this->limit);
		}

		// Set the total pages and current page values.
		if ($this->limit > 0)
		{
			$this->pagesTotal = ceil($this->total / $this->limit);
			$this->pagesCurrent = ceil(($this->limitstart + 1) / $this->limit);
		}

		// Set the pagination iteration loop values.
		$displayedPages = 10;
		$this->pagesStart = $this->pagesCurrent - ($displayedPages / 2);

		if ($this->pagesStart < 1)
		{
			$this->pagesStart = 1;
		}

		if ($this->pagesStart + $displayedPages > $this->pagesTotal)
		{
			$this->pagesStop = $this->pagesTotal;

			if ($this->pagesTotal < $displayedPages)
			{
				$this->pagesStart = 1;
			}
			else
			{
				$this->pagesStart = $this->pagesTotal - $displayedPages + 1;
			}
		}
		else
		{
			$this->pagesStop = $this->pagesStart + $displayedPages - 1;
		}

		// If we are viewing all records set the view all flag to true.
		if ($limit == 0)
		{
			$this->viewall = true;
		}
	}

	/**
	 * Method to set an additional URL parameter to be added to all pagination class generated
	 * links.
	 *
	 * @param   string  $key    The name of the URL parameter for which to set a value.
	 * @param   mixed   $value  The value to set for the URL parameter.
	 *
	 * @return  mixed  The old value for the parameter.
	 *
	 * @since   1.6
	 */
	public function setAdditionalUrlParam($key, $value)
	{
		// Get the old value to return and set the new one for the URL parameter.
		$result = isset($this->additionalUrlParams[$key]) ? $this->additionalUrlParams[$key] : null;

		// If the passed parameter value is null unset the parameter, otherwise set it to the given value.
		if ($value === null)
		{
			unset($this->additionalUrlParams[$key]);
		}
		else
		{
			$this->additionalUrlParams[$key] = $value;
		}

		return $result;
	}

	/**
	 * Method to get an additional URL parameter (if it exists) to be added to
	 * all pagination class generated links.
	 *
	 * @param   string  $key  The name of the URL parameter for which to get the value.
	 *
	 * @return  mixed  The value if it exists or null if it does not.
	 *
	 * @since   1.6
	 */
	public function getAdditionalUrlParam($key)
	{
		$result = isset($this->additionalUrlParams[$key]) ? $this->additionalUrlParams[$key] : null;

		return $result;
	}

	/**
	 * Return the rationalised offset for a row with a given index.
	 *
	 * @param   integer  $index  The row index
	 *
	 * @return  integer  Rationalised offset for a row with a given index.
	 *
	 * @since   1.5
	 */
	public function getRowOffset($index)
	{
		return $index + 1 + $this->limitstart;
	}

	/**
	 * Return the pagination data object, only creating it if it doesn't already exist.
	 *
	 * @return  object   Pagination data object.
	 *
	 * @since   1.5
	 */
	public function getData()
	{
		static $data;

		if (!is_object($data))
		{
			$data = $this->_buildDataObject();
		}

		return $data;
	}

	/**
	 * Create and return the pagination pages counter string, ie. Page 2 of 4.
	 *
	 * @return  string   Pagination pages counter string.
	 *
	 * @since   1.5
	 */
	public function getPagesCounter()
	{
		$html = null;

		if ($this->pagesTotal > 1)
		{
			$html .= JText::sprintf('JLIB_HTML_PAGE_CURRENT_OF_TOTAL', $this->pagesCurrent, $this->pagesTotal);
		}

		return $html;
	}

	/**
	 * Create and return the pagination result set counter string, e.g. Results 1-10 of 42
	 *
	 * @return  string   Pagination result set counter string.
	 *
	 * @since   1.5
	 */
	public function getResultsCounter()
	{
		$html = null;
		$fromResult = $this->limitstart + 1;

		// If the limit is reached before the end of the list.
		if ($this->limitstart + $this->limit < $this->total)
		{
			$toResult = $this->limitstart + $this->limit;
		}
		else
		{
			$toResult = $this->total;
		}

		// If there are results found.
		if ($this->total > 0)
		{
			$msg = JText::sprintf('JLIB_HTML_RESULTS_OF', $fromResult, $toResult, $this->total);
			$html .= "\n" . $msg;
		}
		else
		{
			$html .= "\n" . JText::_('JLIB_HTML_NO_RECORDS_FOUND');
		}

		return $html;
	}

	/**
	 * Create and return the pagination page list string, ie. Previous, Next, 1 2 3 ... x.
	 *
	 * @return  string  Pagination page list string.
	 *
	 * @since   1.5
	 */
	public function getPagesLinks()
	{
		$app = JFactory::getApplication();

		// Build the page navigation list.
		$data = $this->_buildDataObject();

		$list = array();
		$list['prefix'] = $this->prefix;

		$itemOverride = false;
		$listOverride = false;

		// $chromePath = JPATH_THEMES . '/' . $app->getTemplate() . '/html/pagination.php';
		// T3: detect if chrome pagination.php in template or in plugin
		$chromePath = T3Path::getPath ('html/pagination.php');

		if (file_exists($chromePath))
		{
			include_once $chromePath;

			if (function_exists('pagination_item_active') && function_exists('pagination_item_inactive'))
			{
				$itemOverride = true;
			}

			if (function_exists('pagination_list_render'))
			{
				$listOverride = true;
			}
		}

		// Build the select list
		if ($data->all->base !== null)
		{
			$list['all']['active'] = true;
			$list['all']['data'] = ($itemOverride) ? pagination_item_active($data->all) : $this->_item_active($data->all);
		}
		else
		{
			$list['all']['active'] = false;
			$list['all']['data'] = ($itemOverride) ? pagination_item_inactive($data->all) : $this->_item_inactive($data->all);
		}

		if ($data->start->base !== null)
		{
			$list['start']['active'] = true;
			$list['start']['data'] = ($itemOverride) ? pagination_item_active($data->start) : $this->_item_active($data->start);
		}
		else
		{
			$list['start']['active'] = false;
			$list['start']['data'] = ($itemOverride) ? pagination_item_inactive($data->start) : $this->_item_inactive($data->start);
		}

		if ($data->previous->base !== null)
		{
			$list['previous']['active'] = true;
			$list['previous']['data'] = ($itemOverride) ? pagination_item_active($data->previous) : $this->_item_active($data->previous);
		}
		else
		{
			$list['previous']['active'] = false;
			$list['previous']['data'] = ($itemOverride) ? pagination_item_inactive($data->previous) : $this->_item_inactive($data->previous);
		}

		// Make sure it exists
		$list['pages'] = array();

		foreach ($data->pages as $i => $page)
		{
			if ($page->base !== null)
			{
				$list['pages'][$i]['active'] = true;
				$list['pages'][$i]['data'] = ($itemOverride) ? pagination_item_active($page) : $this->_item_active($page);
			}
			else
			{
				$list['pages'][$i]['active'] = false;
				$list['pages'][$i]['data'] = ($itemOverride) ? pagination_item_inactive($page) : $this->_item_inactive($page);
			}
		}

		if ($data->next->base !== null)
		{
			$list['next']['active'] = true;
			$list['next']['data'] = ($itemOverride) ? pagination_item_active($data->next) : $this->_item_active($data->next);
		}
		else
		{
			$list['next']['active'] = false;
			$list['next']['data'] = ($itemOverride) ? pagination_item_inactive($data->next) : $this->_item_inactive($data->next);
		}

		if ($data->end->base !== null)
		{
			$list['end']['active'] = true;
			$list['end']['data'] = ($itemOverride) ? pagination_item_active($data->end) : $this->_item_active($data->end);
		}
		else
		{
			$list['end']['active'] = false;
			$list['end']['data'] = ($itemOverride) ? pagination_item_inactive($data->end) : $this->_item_inactive($data->end);
		}

		if ($this->total > $this->limit)
		{
			return ($listOverride) ? pagination_list_render($list) : $this->_list_render($list);
		}
		else
		{
			return '';
		}
	}

	/**
	 * Get the pagination links
	 *
	 * @param   string  $layoutId  Layout to render the links
	 * @param   array   $options   Optional array with settings for the layout
	 *
	 * @return  string  Pagination links.
	 *
	 * @since   3.3
	 */
	public function getPaginationLinks($layoutId = 'joomla.pagination.links', $options = array())
	{
		// Allow to receive a null layout
		$layoutId = (null === $layoutId) ? 'joomla.pagination.links' : $layoutId;

		$app = JFactory::getApplication();

		$list = array(
			'prefix'       => $this->prefix,
			'limit'        => $this->limit,
			'limitstart'   => $this->limitstart,
			'total'        => $this->total,
			'limitfield'   => $this->getLimitBox(),
			'pagescounter' => $this->getPagesCounter(),
			'pages'        => $this->getPaginationPages()
		);

		return JLayoutHelper::render($layoutId, array('list' => $list, 'options' => $options));
	}

	/**
	 * Create and return the pagination page list string, ie. Previous, Next, 1 2 3 ... x.
	 *
	 * @return  string  Pagination page list string.
	 *
	 * @since   3.3
	 */
	public function getPaginationPages()
	{
		$list = array();

		if ($this->total > $this->limit)
		{
			// Build the page navigation list.
			$data = $this->_buildDataObject();

			// All
			$list['all']['active'] = (null !== $data->all->base);
			$list['all']['data']   = $data->all;

			// Start
			$list['start']['active'] = (null !== $data->start->base);
			$list['start']['data']   = $data->start;

			// Previous link
			$list['previous']['active'] = (null !== $data->previous->base);
			$list['previous']['data']   = $data->previous;

			// Make sure it exists
			$list['pages'] = array();

			foreach ($data->pages as $i => $page)
			{
				$list['pages'][$i]['active'] = (null !== $page->base);
				$list['pages'][$i]['data']   = $page;
			}

			$list['next']['active'] = (null !== $data->next->base);
			$list['next']['data']   = $data->next;

			$list['end']['active'] = (null !== $data->end->base);
			$list['end']['data']   = $data->end;
		}

		return $list;
	}

	/**
	 * Return the pagination footer.
	 *
	 * @return  string  Pagination footer.
	 *
	 * @since   1.5
	 */
	public function getListFooter()
	{
		// Keep B/C for overrides done with chromes
		// $chromePath = JPATH_THEMES . '/' . JFactory::getApplication()->getTemplate() . '/html/pagination.php';
		// T3: detect if chrome pagination.php in template or in plugin
		$chromePath = T3Path::getPath ('html/pagination.php');

		if (file_exists($chromePath))
		{
			$list = array();
			$list['prefix'] = $this->prefix;
			$list['limit'] = $this->limit;
			$list['limitstart'] = $this->limitstart;
			$list['total'] = $this->total;
			$list['limitfield'] = $this->getLimitBox();
			$list['pagescounter'] = $this->getPagesCounter();
			$list['pageslinks'] = $this->getPagesLinks();

			include_once $chromePath;

			if (function_exists('pagination_list_footer'))
			{
				return pagination_list_footer($list);
			}
		}

		return $this->getPaginationLinks();
	}

	/**
	 * Creates a dropdown box for selecting how many records to show per page.
	 *
	 * @return  string  The HTML for the limit # input box.
	 *
	 * @since   1.5
	 */
	public function getLimitBox()
	{
		$app = JFactory::getApplication();
		$limits = array();

		// Make the option list.
		for ($i = 5; $i <= 30; $i += 5)
		{
			$limits[] = JHtml::_('select.option', "$i");
		}

		$limits[] = JHtml::_('select.option', '50', JText::_('J50'));
		$limits[] = JHtml::_('select.option', '100', JText::_('J100'));
		$limits[] = JHtml::_('select.option', '0', JText::_('JALL'));

		$selected = $this->viewall ? 0 : $this->limit;

		// Build the select list.
		if (T3::isAdmin())
		{
			$html = JHtml::_(
				'select.genericlist',
				$limits,
				$this->prefix . 'limit',
				'class="inputbox input-mini" size="1" onchange="Joomla.submitform();"',
				'value',
				'text',
				$selected
			);
		}
		else
		{
			$html = JHtml::_(
				'select.genericlist',
				$limits,
				$this->prefix . 'limit',
				'class="inputbox input-mini" size="1" onchange="this.form.submit()"',
				'value',
				'text',
				$selected
			);
		}

		return $html;
	}

	/**
	 * Return the icon to move an item UP.
	 *
	 * @param   integer  $i          The row index.
	 * @param   boolean  $condition  True to show the icon.
	 * @param   string   $task       The task to fire.
	 * @param   string   $alt        The image alternative text string.
	 * @param   boolean  $enabled    An optional setting for access control on the action.
	 * @param   string   $checkbox   An optional prefix for checkboxes.
	 *
	 * @return  string   Either the icon to move an item up or a space.
	 *
	 * @since   1.5
	 */
	public function orderUpIcon($i, $condition = true, $task = 'orderup', $alt = 'JLIB_HTML_MOVE_UP', $enabled = true, $checkbox = 'cb')
	{
		if (($i > 0 || ($i + $this->limitstart > 0)) && $condition)
		{
			return JHtml::_('jgrid.orderUp', $i, $task, '', $alt, $enabled, $checkbox);
		}
		else
		{
			return '&#160;';
		}
	}

	/**
	 * Return the icon to move an item DOWN.
	 *
	 * @param   integer  $i          The row index.
	 * @param   integer  $n          The number of items in the list.
	 * @param   boolean  $condition  True to show the icon.
	 * @param   string   $task       The task to fire.
	 * @param   string   $alt        The image alternative text string.
	 * @param   boolean  $enabled    An optional setting for access control on the action.
	 * @param   string   $checkbox   An optional prefix for checkboxes.
	 *
	 * @return  string   Either the icon to move an item down or a space.
	 *
	 * @since   1.5
	 */
	public function orderDownIcon($i, $n, $condition = true, $task = 'orderdown', $alt = 'JLIB_HTML_MOVE_DOWN', $enabled = true, $checkbox = 'cb')
	{
		if (($i < $n - 1 || $i + $this->limitstart < $this->total - 1) && $condition)
		{
			return JHtml::_('jgrid.orderDown', $i, $task, '', $alt, $enabled, $checkbox);
		}
		else
		{
			return '&#160;';
		}
	}

	/**
	 * Create the HTML for a list footer
	 *
	 * @param   array  $list  Pagination list data structure.
	 *
	 * @return  string  HTML for a list footer
	 *
	 * @since   1.5
	 */
	protected function _list_footer($list)
	{
		$html = "<div class=\"list-footer\">\n";

		$html .= "\n<div class=\"limit\">" . JText::_('JGLOBAL_DISPLAY_NUM') . $list['limitfield'] . "</div>";
		$html .= $list['pageslinks'];
		$html .= "\n<div class=\"counter\">" . $list['pagescounter'] . "</div>";

		$html .= "\n<input type=\"hidden\" name=\"" . $list['prefix'] . "limitstart\" value=\"" . $list['limitstart'] . "\" />";
		$html .= "\n</div>";

		return $html;
	}

	/**
	 * Create the html for a list footer
	 *
	 * @param   array  $list  Pagination list data structure.
	 *
	 * @return  string  HTML for a list start, previous, next,end
	 *
	 * @since   1.5
	 */
	protected function _list_render($list)
	{
		// Reverse output rendering for right-to-left display.
		$html = '<ul>';
		$html .= '<li class="pagination-start">' . $list['start']['data'] . '</li>';
		$html .= '<li class="pagination-prev">' . $list['previous']['data'] . '</li>';

		foreach ($list['pages'] as $page)
		{
			$html .= '<li>' . $page['data'] . '</li>';
		}

		$html .= '<li class="pagination-next">' . $list['next']['data'] . '</li>';
		$html .= '<li class="pagination-end">' . $list['end']['data'] . '</li>';
		$html .= '</ul>';

		return $html;
	}

	/**
	 * Method to create an active pagination link to the item
	 *
	 * @param   JPaginationObject  $item  The object with which to make an active link.
	 *
	 * @return  string  HTML link
	 *
	 * @since   1.5
	 */
	protected function _item_active(JPaginationObject $item)
	{
		$app = JFactory::getApplication();

		$title = '';
		$class = '';

		if (!is_numeric($item->text))
		{
			JHtml::_('bootstrap.tooltip');
			$title = ' title="' . $item->text . '"';
			$class = 'hasTooltip ';
		}

		if (T3::isAdmin())
		{
			return '<a' . $title . ' href="#" onclick="document.adminForm.' . $this->prefix
			. 'limitstart.value=' . ($item->base > 0 ? $item->base : '0') . '; Joomla.submitform();return false;">' . $item->text . '</a>';
		}
		else
		{
			return '<a' . $title . ' href="' . $item->link . '" class="' . $class . 'pagenav">' . $item->text . '</a>';
		}
	}

	/**
	 * Method to create an inactive pagination string
	 *
	 * @param   JPaginationObject  $item  The item to be processed
	 *
	 * @return  string
	 *
	 * @since   1.5
	 */
	protected function _item_inactive(JPaginationObject $item)
	{
		$app = JFactory::getApplication();

		if (T3::isAdmin())
		{
			return '<span>' . $item->text . '</span>';
		}
		else
		{
			return '<span class="pagenav">' . $item->text . '</span>';
		}
	}

	/**
	 * Create and return the pagination data object.
	 *
	 * @return  object  Pagination data object.
	 *
	 * @since   1.5
	 */
	protected function _buildDataObject()
	{
		$data = new stdClass;

		// Build the additional URL parameters string.
		$params = '';

		if (!empty($this->additionalUrlParams))
		{
			foreach ($this->additionalUrlParams as $key => $value)
			{
				$params .= '&' . $key . '=' . $value;
			}
		}

		$data->all = new JPaginationObject(JText::_('JLIB_HTML_VIEW_ALL'), $this->prefix);

		if (!$this->viewall)
		{
			$data->all->base = '0';
			$data->all->link = JRoute::_($params . '&' . $this->prefix . 'limitstart=');
		}

		// Set the start and previous data objects.
		$data->start = new JPaginationObject(JText::_('JLIB_HTML_START'), $this->prefix);
		$data->previous = new JPaginationObject(JText::_('JPREV'), $this->prefix);

		if ($this->pagesCurrent > 1)
		{
			$page = ($this->pagesCurrent - 2) * $this->limit;

			// Set the empty for removal from route
			// @todo remove code: $page = $page == 0 ? '' : $page;

			$data->start->base = '0';
			$data->start->link = JRoute::_($params . '&' . $this->prefix . 'limitstart=0' . '&limit=' . $this->limit);
			$data->previous->base = $page;
			$data->previous->link = JRoute::_($params . '&' . $this->prefix . 'limitstart=' . $page . '&limit=' . $this->limit);
		}

		// Set the next and end data objects.
		$data->next = new JPaginationObject(JText::_('JNEXT'), $this->prefix);
		$data->end = new JPaginationObject(JText::_('JLIB_HTML_END'), $this->prefix);

		if ($this->pagesCurrent < $this->pagesTotal)
		{
			$next = $this->pagesCurrent * $this->limit;
			$end = ($this->pagesTotal - 1) * $this->limit;

			$data->next->base = $next;
			$data->next->link = JRoute::_($params . '&' . $this->prefix . 'limitstart=' . $next . '&limit=' . $this->limit);
			$data->end->base = $end;
			$data->end->link = JRoute::_($params . '&' . $this->prefix . 'limitstart=' . $end . '&limit=' . $this->limit);
		}

		$data->pages = array();
		$stop = $this->pagesStop;

		for ($i = $this->pagesStart; $i <= $stop; $i++)
		{
			$offset = ($i - 1) * $this->limit;

			$data->pages[$i] = new JPaginationObject($i, $this->prefix);

			if ($i != $this->pagesCurrent || $this->viewall)
			{
				$data->pages[$i]->base = $offset;
				$data->pages[$i]->link = JRoute::_($params . '&' . $this->prefix . 'limitstart=' . $offset . '&limit=' . $this->limit);
			}
			else
			{
				$data->pages[$i]->active = true;
			}
		}

		return $data;
	}

	/**
	 * Modifies a property of the object, creating it if it does not already exist.
	 *
	 * @param   string  $property  The name of the property.
	 * @param   mixed   $value     The value of the property to set.
	 *
	 * @return  void
	 *
	 * @since   3.0
	 * @deprecated  4.0  Access the properties directly.
	 */
	public function set($property, $value = null)
	{
		JLog::add('JPagination::set() is deprecated. Access the properties directly.', JLog::WARNING, 'deprecated');

		if (strpos($property, '.'))
		{
			$prop = explode('.', $property);
			$prop[1] = ucfirst($prop[1]);
			$property = implode($prop);
		}

		$this->$property = $value;
	}

	/**
	 * Returns a property of the object or the default value if the property is not set.
	 *
	 * @param   string  $property  The name of the property.
	 * @param   mixed   $default   The default value.
	 *
	 * @return  mixed    The value of the property.
	 *
	 * @since   3.0
	 * @deprecated  4.0  Access the properties directly.
	 */
	public function get($property, $default = null)
	{
		JLog::add('JPagination::get() is deprecated. Access the properties directly.', JLog::WARNING, 'deprecated');

		if (strpos($property, '.'))
		{
			$prop = explode('.', $property);
			$prop[1] = ucfirst($prop[1]);
			$property = implode($prop);
		}

		if (isset($this->$property))
		{
			return $this->$property;
		}

		return $default;
	}
}
joomla30/layoutfile.php000060400000004336152455303040011061 0ustar00<?php
/**
 * @package     Joomla.Libraries
 * @subpackage  Layout
 *
 * @copyright   Copyright (C) 2005 - 2016 Open Source Matters, Inc. All rights reserved.
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('JPATH_PLATFORM') or die;


// Read core JLayoutFile from library
$filepath = JPATH_LIBRARIES . '/cms/layout/file.php';
$filecontent = file_get_contents($filepath);
// remove open php
$filecontent = str_replace(array('<?php', '?>', ' JLayoutFile '), array('', '', ' JLayoutFileCore '), $filecontent);
// define class JLayoutFileCore
eval ($filecontent);


// now define JLayoutFile class override method getDefaultIncludePaths
/**
 * Base class for rendering a display layout
 * loaded from from a layout file
 *
 * @see    https://docs.joomla.org/Sharing_layouts_across_views_or_extensions_with_JLayout
 * @since  3.0
 */
class JLayoutFile extends JLayoutFileCore
{

	/**
	 * Get the default array of include paths
	 *
	 * @return  array
	 *
	 * @since   3.5
	 */
	public function getDefaultIncludePaths()
	{
		// Reset includePaths
		$paths = array();

		// (1 - highest priority) Received a custom high priority path
		if ($this->basePath !== null)
		{
			$paths[] = rtrim($this->basePath, DIRECTORY_SEPARATOR);
		}

		// Component layouts & overrides if exist
		$component = $this->options->get('component', null);

		if (!empty($component))
		{
			// (2) Component template overrides path
			$paths[] = JPATH_THEMES . '/' . JFactory::getApplication()->getTemplate() . '/html/layouts/' . $component;

			// (3) Component path
			if ($this->options->get('client') == 0)
			{
				$paths[] = JPATH_SITE . '/components/' . $component . '/layouts';
			}
			else
			{
				$paths[] = JPATH_ADMINISTRATOR . '/components/' . $component . '/layouts';
			}
		}

		// T3 - (4.1) - user custom layout overridden
		if (!defined('T3_LOCAL_DISABLED')) $paths[] = T3_LOCAL_PATH . '/html/layouts';

		// (4) Standard Joomla! layouts overriden
		$paths[] = JPATH_THEMES . '/' . JFactory::getApplication()->getTemplate() . '/html/layouts';

		// T3 - (5.1) - T3 base layout overridden
		$paths[] = T3_PATH . '/html/layouts';

		// (5 - lower priority) Frontend base layouts
		$paths[] = JPATH_ROOT . '/layouts';

		return $paths;
	}

}
core/bot.php000060400000031463152455303040006775 0ustar00<?php
/** 
 *------------------------------------------------------------------------------
 * @package       T3 Framework for Joomla!
 *------------------------------------------------------------------------------
 * @copyright     Copyright (C) 2004-2013 JoomlArt.com. All Rights Reserved.
 * @license       GNU General Public License version 2 or later; see LICENSE.txt
 * @authors       JoomlArt, JoomlaBamboo, (contribute to this project at github 
 *                & Google group to become co-author)
 * @Google group: https://groups.google.com/forum/#!forum/t3fw
 * @Link:         http://t3-framework.org 
 *------------------------------------------------------------------------------
 */

use Joomla\CMS\Categories\Categories;
use Joomla\CMS\Factory;
use Joomla\CMS\Form\Form;
use Joomla\CMS\Table\Table;
use Joomla\Filesystem\File;
use Joomla\Filesystem\Folder;
use Joomla\Registry\Registry;

// No direct access
defined('_JEXEC') or die();
/**
 * T3Bot class
 * Auto trigger
 *
 * @package T3
 */
class T3Bot extends Registry
{
	// call before checking & loading T3
	public static function preload () {
		// NO NEED TO reupdate megamenu configuration
		return;
		// check if menu is alter, then turn a flag to reupdate megamenu configuration
		$input = Factory::getApplication()->input;
		if ($input->get('option') == 'com_menus' && 
			preg_match('#save|apply|trash|remove|delete|publish|order#i', $input->get('task'))) {
			
			// get all template styles
			$db = Factory::getDBO();
			$query = $db->getQuery(true);
			$query
				->select('*')
				->from('#__template_styles')
				->where('client_id=0');

			$db->setQuery($query);
			$themes = $db->loadObjectList();
			
			//update all global parameters
			foreach($themes as $theme){
				$registry = new Registry;
				$registry->loadString($theme->params);
				$mm_config = $registry->get('mm_config');
				if (!$mm_config) continue;

				// turn on flag
				$registry->set('mm_config_needupdate', 1); //overwrite with new value

				$query = $db->getQuery(true);
				$query
					->update('#__template_styles')
					->set('params =' . $db->quote($registry->toString()))
					->where('id =' . (int)$theme->id);

				$db->setQuery($query);
				$db->execute();
			}
			// force reload cache template
			$cache = Factory::getCache('com_templates', '');
			$cache->clean();
		}
	}

	// call before call T3::init
	public static function beforeInit () {
	}

	// call after call T3::init
	public static function afterInit () {
		
		$app       = Factory::getApplication();
		$input     = $app->input;
		$tplparams = $app->getTemplate(true)->params;
		
		if (!T3::isAdmin()) {
			// check if need update megamenu configuration
			if ($tplparams->get ('mm_config_needupdate')) {
				T3::import('menu/megamenu');
				T3::import('admin/megamenu');

				$currentconfig = @json_decode($tplparams->get ('mm_config', ''), true);
				if (!is_array($currentconfig)){
					$currentconfig = array();
				} else {
					$menuassoc = T3AdminMegamenu::menus();
					$menulangs = array();
					$menutypes = array();

					foreach ($menuassoc as $key => $massoc) {
						$menutypes[] = $massoc->value;
						$menulangs[$massoc->value] = $massoc->language;
					}
				}

				foreach ($currentconfig as $menukey => $mmconfig) {
					if (!is_array($mmconfig)){
						continue;
					}

					$menutype = $menukey;
					if(!in_array($menutype, $menutypes) && preg_match('@(-(\d))+$@', $menukey, $match)){
						$menutype = preg_replace('@(-(\d))+$@', '', $menutype);

						$access = explode('-', $match[0]);
						$access[] = 1;

						$access = array_filter($access);
						$access = array_unique($access);

						$mmconfig['access'] = $access;
					}

					if(!in_array($menutype, $menutypes)){
						continue;
					}

					$mmconfig['language'] = $menulangs[$menutype];
					
					$menu = new T3MenuMegamenu ($menutype, $mmconfig);

					$children = $menu->get ('children');

					//remove additional settings
					unset($mmconfig['language']);
					unset($mmconfig['access']);

					foreach ($mmconfig as $item => $setting) {

						if (is_array($setting) && isset($setting['sub'])) {
							$sub = &$setting['sub'];
							$id = (int) substr($item, 5); // remove item-
							$modify = false;

							if (!isset($children[$id]) || !count ($children[$id])){
								//check and remove any empty row
								for ($j=0; $j < count($sub['rows']); $j++) {
									$remove = true;
									for ($k=0; $k < count($sub['rows'][$j]); $k++) {
										if (isset($sub['rows'][$j][$k]['position'])) {
											$remove = false;
											break;
										}
									}

									if($remove){
										$modify = true;
										unset($sub['rows'][$j]);
									}
								}

								if($modify){
									$sub['rows'] = array_values($sub['rows']); //re-index
									$mmconfig[$item]['sub'] = $sub;
								}

								continue;
							}

							$items = array();
							foreach ($sub['rows'] as $row) {
								foreach ($row as $col) {
									if (!isset($col['position'])) {
										$items[] = $col['item'];
									}
								}
							}
							// update the order of items
							$_items = array();
							$_itemsids = array();
							$firstitem = 0;
							foreach ($children[$id] as $child) {
								$_itemsids[] = (int)$child->id;

								if (!$firstitem) $firstitem = (int)$child->id;
								if (in_array($child->id, $items)) {
									$_items [] = (int)$child->id;
								}
							}

							// $_items[0] = $firstitem;
							if (empty($_items) || $_items[0] != $firstitem) {
								if (count ($_items) == count($items)) {
									$_items[0] = $firstitem;
								} else {
									array_splice($_items, 0, 0, $firstitem);
								}
							}

							// no need update config for this item
							if ($items == $_items) continue;

							// update back to setting
							$i = 0;
							$c = count ($_items);
							for ($j=0; $j < count($sub['rows']); $j++) {
								for ($k=0; $k < count($sub['rows'][$j]); $k++) {
									if (!isset($sub['rows'][$j][$k]['position'])) {
										$sub['rows'][$j][$k]['item'] = $i < $c ? $_items[$i++] : "";
									}
								}
							}

							//update - add new rows for new items - at the first rows
							if(!empty($_items) && count($items) == 0){
								$modify = true;
								array_unshift($sub['rows'], array(array('item' => $_items[0], 'width' => 12)));
							}

							//check and remove any empty row
							for ($j=0; $j < count($sub['rows']); $j++) {
								$remove = true;
								for ($k=0; $k < count($sub['rows'][$j]); $k++) {
									if (isset($sub['rows'][$j][$k]['position']) || in_array($sub['rows'][$j][$k]['item'], $_itemsids)) {
										$remove = false;
										break;
									}
								}

								if($remove){
									$modify = true;
									unset($sub['rows'][$j]);
								}
							}

							if($modify){
								$sub['rows'] = array_values($sub['rows']); //re-index
							}

							$mmconfig[$item]['sub'] = $sub;
						}
					}

					$currentconfig[$menukey] = $mmconfig;
				}
				// update  megamenu back to other template styles parameter
				$mm_config = json_encode($currentconfig, JSON_UNESCAPED_UNICODE);

				// update megamenu back to current template style parameter
				$template = $app->getTemplate(true);
				$params = $template->params;
				$params->set ('mm_config', $mm_config);
				$template->params = $params;

				//update the cache
				T3::setTemplate(T3_TEMPLATE, $params);

				//get all other styles that have the same template
				$db = Factory::getDBO();
				$query = $db->getQuery(true);
				$query
					->select('*')
					->from('#__template_styles')
					->where('template=' . $db->quote(T3_TEMPLATE))
					->where('client_id=0');

				$db->setQuery($query);
				$themes = $db->loadObjectList();
				
				//update all global parameters
				foreach($themes as $theme){
					$registry = new Registry;
					$registry->loadString($theme->params);
					$registry->set('mm_config', $mm_config); //overwrite with new value
					$registry->set('mm_config_needupdate', ""); //overwrite with new value

					$query = $db->getQuery(true);
					$query
						->update('#__template_styles')
						->set('params =' . $db->quote($registry->toString()))
						->where('id =' . (int)$theme->id);

					$db->setQuery($query);
					$db->execute();
				}
				// force reload cache template
				$cache = Factory::getCache('com_templates', '');
				$cache->clean();
			}
		}
	}


	// call when prepare form for template parameter
	// looking in less/extras folder to render parameters for extended template style
	public static function prepareForm (&$form) {
		jimport('joomla.filesystem.folder');
		jimport('joomla.filesystem.file');

		// load add-ons setting
		$path = T3_TEMPLATE_PATH . '/less/extras';
		if (!is_dir ($path)) return ;

		$files = Folder::files($path, '.less');
		if (!$files || !count($files)){
			return ;
		}

		$extras = array();
		foreach ($files as $file) {
			$extras[] = File::stripExt($file);
		}
		if (count($extras)) {
			
			//load languages
			if(!defined('T3_TEMPLATE')){
				Factory::getLanguage()->load(T3_PLUGIN, JPATH_ADMINISTRATOR);
			}

			$_xml =
				'<?xml version="1.0"?>
				<form>
					<fields name="params">
						<fieldset name="addon_params" label="T3_ADDON_LABEL" description="T3_ADDON_DESC">
					    <field type="t3depend" name="t3_addon_theme_extra" function="@legend" label="T3_ADDON_THEME_EXTRAS_LABEL" description="T3_ADDON_THEME_EXTRAS_DESC" />
				';
							foreach ($extras as $extra) {
								$_xml .= '
							<field name="theme_extras_'.$extra.'" global="1" type="menuitem" multiple="true" default="" label="'.$extra.'" description="'.$extra.'" published="1" class="t3-extra-setting">
									<option value="-1">T3_ADDON_THEME_EXTRAS_ALL</option>
									<option value="0">T3_ADDON_THEME_EXTRAS_NONE</option>
							</field>';
							}

							$_xml .= '
						</fieldset>
					</fields>
				</form>
				';
			$xml = simplexml_load_string($_xml);
			$form->load ($xml, false);
		}
	}

	public static function extraFields(&$form, $data, $tplpath){
		
		if ($form->getName() == 'com_categories.categorycom_content' || $form->getName() == 'com_content.article') {
			
			// check for extrafields overwrite
			$path = $tplpath . '/etc/extrafields';
			if (!is_dir ($path)) return ;

			$files = Folder::files($path, '.xml');
			if (!$files || !count($files)){
				return ;
			}

			$extras = array();
			foreach ($files as $file) {
				$extras[] = File::stripExt($file);
			}
			if (count($extras)) {

				if ($form->getName() == 'com_categories.categorycom_content'){
					
					//load languages
					if(!defined('T3_TEMPLATE')){
						Factory::getLanguage()->load(T3_PLUGIN, JPATH_ADMINISTRATOR);
					}

					$_xml =
						'<?xml version="1.0"?>
						<form>
							<fields name="params">
								<fieldset name="t3_extrafields_params" label="T3_EXTRA_FIELDS_GROUP_LABEL" description="T3_EXTRA_FIELDS_GROUP_DESC">
									<field name="t3_extrafields" type="list" default="" show_none="true" label="T3_EXTRA_FIELDS_LABEL" description="T3_EXTRA_FIELDS_DESC">
										<option value="">JNONE</option>';
									
									foreach ($extras as $extra) {
										$_xml .= '<option value="' . $extra . '">' . ucfirst($extra) . '</option>';
									}

									$_xml .= '
									</field>
								</fieldset>
							</fields>
						</form>
						';
					$xml = simplexml_load_string($_xml);
					$form->load ($xml, false);

				} else {
					
					$app   = Factory::getApplication();
					$input = $app->input;
					$fdata = empty($data) ? $input->post->get('jform', array(), 'array') : (is_object($data) && method_exists($data, 'getProperties') ? $data->getProperties() : (array) $data);
					if (isset($data->attribs) && is_string($data->attribs))
			      	{
			      		$data->attribs = json_decode($data->attribs, true);
			      	}
					if(!empty($fdata['catid']) && is_array($fdata['catid'])) { // create new
						$catid = end($fdata['catid']);
					} else { // edit
						$catid = ($fdata['catid']);
					}

					if($catid){

						if(version_compare(JVERSION, '3.0', 'lt')){
							jimport('joomla.application.categories');
						}

						$categories = Categories::getInstance('Content', array('countItems' => 0 ));
						$category = $categories->get($catid);
						$params = $category->params;
						if(!$params instanceof Registry) {
							$params = new Registry;
							$params->loadString($category->params);
						}

						if($params instanceof Registry){
							$extrafile = $path . '/' . $params->get('t3_extrafields') . '.xml';
							if(is_file($extrafile)){
								Form::addFormPath($path);
								$form->loadFile($params->get('t3_extrafields'), false);
							}
						}
					}
				}
			}
		}
	}

	public static function onContentBeforeSave($context, $data, $isNew)
	{
		if(isset($data->attribs)){
			$contentTable = Table::getInstance('Content', 'JTable',array());
			$contentTable->load($data->id);
			$oldAttribs = new Registry($contentTable->attribs);
			$attribs = new Registry($data->attribs);
			$oldAttribs->merge($attribs);
			$data->attribs = $oldAttribs->toString();
		}
	}
}
core/defines.php000060400000003030152455303040007613 0ustar00<?php
/** 
 *------------------------------------------------------------------------------
 * @package       T3 Framework for Joomla!
 *------------------------------------------------------------------------------
 * @copyright     Copyright (C) 2004-2013 JoomlArt.com. All Rights Reserved.
 * @license       GNU General Public License version 2 or later; see LICENSE.txt
 * @authors       JoomlArt, JoomlaBamboo, (contribute to this project at github 
 *                & Google group to become co-author)
 * @Google group: https://groups.google.com/forum/#!forum/t3fw
 * @Link:         http://t3-framework.org 
 *------------------------------------------------------------------------------
 */

use Joomla\CMS\Uri\Uri;

// No direct access
defined('_JEXEC') or die;

define ('T3_PLUGIN', 'plg_system_t3');

//T3 base folder
define ('T3_ADMIN', 't3');
define ('T3_ADMIN_PATH', JPATH_ROOT . '/plugins/system/' . T3_ADMIN);
define ('T3_ADMIN_URL', Uri::root(true) . '/plugins/system/' . T3_ADMIN);
define ('T3_ADMIN_REL', 'plugins/system/' . T3_ADMIN);

//T3 secondary base theme folder
define ('T3_EX_BASE_PATH', JPATH_ROOT . '/media/t3/themes');
define ('T3_EX_BASE_URL', Uri::root(true) . '/media/t3/themes');
define ('T3_EX_BASE_REL', 'media/t3/themes');

//T3 core base theme
define ('T3_CORE_BASE', 'base');
define ('T3_CORE_BASE_PATH', T3_ADMIN_PATH . '/' . T3_CORE_BASE);
define ('T3_CORE_BASE_URL', T3_ADMIN_URL . '/' . T3_CORE_BASE);
define ('T3_CORE_BASE_REL', T3_ADMIN_REL . '/' . T3_CORE_BASE);

// T3 User dir
define ('T3_LOCAL_DIR', 'local');core/t3j.php000060400000005142152455303040006704 0ustar00<?php
/** 
 *------------------------------------------------------------------------------
 * @package       T3 Framework for Joomla!
 *------------------------------------------------------------------------------
 * @copyright     Copyright (C) 2004-2013 JoomlArt.com. All Rights Reserved.
 * @license       GNU General Public License version 2 or later; see LICENSE.txt
 * @authors       JoomlArt, JoomlaBamboo, (contribute to this project at github 
 *                & Google group to become co-author)
 * @Google group: https://groups.google.com/forum/#!forum/t3fw
 * @Link:         http://t3-framework.org 
 *------------------------------------------------------------------------------
 */

// no direct access
defined('_JEXEC') or die('Restricted access');

/**
 * T3J class
 * Make T3 compatible with both Joomla 3.x & 2.5
 * @package		T3
 */

class T3J {

	/**
	 * The method is available from Joomla 3.1.2 in class JHtml. Changing call JHtml::tooltipText to T3J::tooltipText to make it work on Joomla 2.5
   *
   * Converts a double colon seperated string or 2 separate strings to a string ready for bootstrap tooltips
	 *
	 * @param   string  $title      The title of the tooltip (or combined '::' separated string).
	 * @param   string  $content    The content to tooltip.
	 * @param   int     $translate  If true will pass texts through JText.
	 * @param   int     $escape     If true will pass texts through htmlspecialchars.
	 *
	 * @return  string  The tooltip string
	 *
	 * @since   3.1.2
	 */
	public static function tooltipText($title = '', $content = '', $translate = 1, $escape = 1)
	{
		// Return empty in no title or content is given.
		if ($title == '' && $content == '')
		{
			return '';
		}

		// Split title into title and content if the title contains '::' (old Mootools format).
		if ($content == '' && !(strpos($title, '::') === false))
		{
			list($title, $content) = explode('::', $title, 2);
		}

		// Pass texts through the JText.
		if ($translate)
		{
			$title = JText::_($title);
			$content = JText::_($content);
		}

		// Escape the texts.
		if ($escape)
		{
			$title = str_replace('"', '&quot;', $title);
			$content = str_replace('"', '&quot;', $content);
		}

		// Return only the content if no title is given.
		if ($title == '')
		{
			return $content;
		}

		// Return only the title if title and text are the same.
		if ($title == $content)
		{
			return '<strong>' . $title . '</strong>';
		}

		// Return the formated sting combining the title and  content.
		if ($content != '')
		{
			return '<strong>' . $title . '</strong><br />' . $content;
		}

		// Return only the title.
		return $title;
	}  
}
core/admin.php000060400000033203152455303040007273 0ustar00<?php

use Joomla\CMS\Factory;
use Joomla\Registry\Registry;

/** 
 *------------------------------------------------------------------------------
 * @package       T3 Framework for Joomla!
 *------------------------------------------------------------------------------
 * @copyright     Copyright (C) 2004-2013 JoomlArt.com. All Rights Reserved.
 * @license       GNU General Public License version 2 or later; see LICENSE.txt
 * @authors       JoomlArt, JoomlaBamboo, (contribute to this project at github 
 *                & Google group to become co-author)
 * @Google group: https://groups.google.com/forum/#!forum/t3fw
 * @Link:         http://t3-framework.org 
 *------------------------------------------------------------------------------
 */

// Define constant
class T3Admin {

	protected $langs = array();
	protected $html = array();

	/**
	 * init admin backend to edit template style
	 */
	public function init() {
		$app = Factory::getApplication();
		$input = $app->input;
		if ($input->getCmd('view') == 'style') {
			$app->set('themes.base', T3_ADMIN_PATH);
			$app->set('theme', 'admin');
		}
		if(version_compare(JVERSION, '4', 'ge')){
			$wa = Factory::getDocument()->getWebAssetManager();
			//var_dump($wa->getAssets('script'));die;
			$wa->registerAsset('script', 'bootstrap.js.bundle', T3_ADMIN_REL . '/admin/bootstrap/js/bootstrap.js', ['dependencies' => 'jquery']);
			$wa->registerAsset('script', 'jquery', T3_ADMIN_REL . '/admin/js/jquery-1.x.min.js');
			$wa->registerAsset('script', 'jquery-noconflict', T3_ADMIN_REL . '/admin/js/jquery.noconflict.js');
			//$wa->disableAsset('script', 'bootstrap.init.legacy');
			//$wa->useAsset('script', 'bootstrap.js.bundle');
		}
	}


	public function updateHead() {
	}

	/**
	 * function render
	 * render T3 administrator configuration form
	 *
	 * @return render success or not
	 */
	public function render(){
		$app = Factory::getApplication();
		$input  = $app->input;
		if ('style' != $input->getCmd('view')) return;

		$body   = $app->getBody();
		$layout = T3_ADMIN_PATH . '/admin/tpls/default.php';
		$layout = false;
		if(file_exists($layout)){
			// ob_start();
			// $this->renderAdmin();
			// $buffer = ob_get_clean();

			//this cause backtrack_limit in some server
			//$body = preg_replace('@<form\s[^>]*name="adminForm"[^>]*>(.*)</form>@msU', $buffer, $body);
			$opentags = explode('<form', $body);
			$endtags = explode('</form>', $body);
			$open = array_shift($opentags);
			$close = array_pop($endtags);

			//should not happend
			if(count($opentags) > 1) {
	
				$iopen = 0;
				$iclose = count($opentags);

				foreach ($opentags as $index => $value) {
					if($iopen !== -1 && strpos($value, 'name="adminForm"') === false){
						$iopen++;
						$open = $open . '<form' . $value;
					} else {
						$iopen = -1;
					}

					if($iclose !== -1 && strpos($endtags[--$iclose], 'name="adminForm"') === false){
						$close = $endtags[$iclose] . '</form>' . $close;
					} else {
						$iclose = -1;
					}
				}
			}

			//$body = $open . $this->html['admin'] . $close;
			//$body = $this->html['admin'];
		}

		if(!$input->getCmd('file')){
			$body = $this->replaceToolbar($body);
		}

		$body = $this->replaceDoctype($body);

		$app->setBody($body);
	}

	public function addAssets() {
		$japp   = Factory::getApplication();
		$jdoc   = Factory::getDocument();
		$db     = Factory::getDbo();
		$params = T3::getTplParams();
		$input  = $japp->input;

		if ('style' != $input->getCmd('view')) return;

		// load template language
		Factory::getLanguage()->load ('tpl_'.T3_TEMPLATE.'.sys', JPATH_ROOT, null, true);

		$langs = array(
			'unknownError' => JText::_('T3_MSG_UNKNOWN_ERROR'),

			'logoPresent' => JText::_('T3_LAYOUT_LOGO_TEXT'),
			'emptyLayoutPosition' => JText::_('T3_LAYOUT_EMPTY_POSITION'),
			'defaultLayoutPosition' => JText::_('T3_LAYOUT_DEFAULT_POSITION'),
			
			'layoutConfig' => JText::_('T3_LAYOUT_CONFIG_TITLE'),
			'layoutConfigDesc' => JText::_('T3_LAYOUT_CONFIG_DESC'),
			'layoutUnknownWidth' => JText::_('T3_LAYOUT_UNKN_WIDTH'),
			'layoutPosWidth' => JText::_('T3_LAYOUT_POS_WIDTH'),
			'layoutPosName' => JText::_('T3_LAYOUT_POS_NAME'),

			'layoutCanNotLoad' => JText::_('T3_LAYOUT_LOAD_ERROR'),

			'askCloneLayout' => JText::_('T3_LAYOUT_ASK_ADD_LAYOUT'),
			'correctLayoutName' => JText::_('T3_LAYOUT_ASK_CORRECT_NAME'),
			'askDeleteLayout' => JText::_('T3_LAYOUT_ASK_DEL_LAYOUT'),
			'askDeleteLayoutDesc' => JText::_('T3_LAYOUT_ASK_DEL_LAYOUT_DESC'),
			'askPurgeLayout' => JText::_('T3_LAYOUT_ASK_DEL_LAYOUT'),
			'askPurgeLayoutDesc' => JText::_('T3_LAYOUT_ASK_PURGE_LAYOUT_DESC'),

			'lblDeleteIt' => JText::_('T3_LAYOUT_LABEL_DELETEIT'),
			'lblCloneIt' => JText::_('T3_LAYOUT_LABEL_CLONEIT'),

			'layoutEditPosition' => JText::_('T3_LAYOUT_EDIT_POSITION'),
			'layoutShowPosition' => JText::_('T3_LAYOUT_SHOW_POSITION'),
			'layoutHidePosition' => JText::_('T3_LAYOUT_HIDE_POSITION'),
			'layoutChangeNumpos' => JText::_('T3_LAYOUT_CHANGE_NUMPOS'),
			'layoutDragResize' => JText::_('T3_LAYOUT_DRAG_RESIZE'),
			'layoutHiddenposDesc' => JText::_('T3_LAYOUT_HIDDEN_POS_DESC'),
			
			'updateFailedGetList' => JText::_('T3_OVERVIEW_FAILED_GETLIST'),
			'updateDownLatest' => JText::_('T3_OVERVIEW_GO_DOWNLOAD'),
			'updateCheckUpdate' => JText::_('T3_OVERVIEW_CHECK_UPDATE'),
			'updateChkComplete' => JText::_('T3_OVERVIEW_CHK_UPDATE_OK'),
			'updateHasNew' => JText::_('T3_OVERVIEW_TPL_NEW'),
			'updateCompare' => JText::_('T3_OVERVIEW_TPL_COMPARE'),
			'switchResponsiveMode' => JText::_('T3_MSG_SWITCH_RESPONSIVE_MODE')
		);

		//just in case
		if(!($params instanceof Registry)){
			$params = new Registry;
		}

		//get extension id of framework and template
		$query  = $db->getQuery(true);
		$query
			->select('extension_id')
			->from('#__extensions')
			->where('(element='. $db->quote(T3_TEMPLATE) . ' AND type=' . $db->quote('template') . ') 
					OR (element=' . $db->quote(T3_ADMIN) . ' AND type=' . $db->quote('plugin'). ')');

		$db->setQuery($query);
		$results = $db->loadRowList();
		$eids = array();
		foreach ($results as $eid) {
			$eids[] = $eid[0];
		}

		//check for version compatible
		if(version_compare(JVERSION, '3.0', 'ge')){
			//JHtml::_('jquery.framework');
			JHtml::_('bootstrap.framework');
		} else {
			$jdoc->addStyleSheet(T3_ADMIN_URL . '/admin/bootstrap/css/bootstrap.css');

			$jdoc->addScript(T3_ADMIN_URL . '/admin/js/jquery-1.x.min.js');
			$jdoc->addScript(T3_ADMIN_URL . '/admin/bootstrap/js/bootstrap.js');
			$jdoc->addScript(T3_ADMIN_URL . '/admin/js/jquery.noconflict.js');
		}

		if(!$this->checkAssetsLoaded('chosen.css', '_styleSheets')){
			$jdoc->addStyleSheet(T3_ADMIN_URL . '/admin/plugins/chosen/chosen.css');
		}

		$jdoc->addStyleSheet(T3_ADMIN_URL . '/includes/depend/css/depend.css');
		$jdoc->addStyleSheet(T3_URL . '/css/layout-preview.css');
		$jdoc->addStyleSheet(T3_ADMIN_URL . '/admin/layout/css/layout.css');
		if(file_exists(T3_TEMPLATE_PATH . '/admin/layout-custom.css')) {
			$jdoc->addStyleSheet(T3_TEMPLATE_URL . '/admin/layout-custom.css');
		}
		$jdoc->addStyleSheet(T3_ADMIN_URL . '/admin/css/admin.css');

		if(version_compare(JVERSION, '3.0', 'ge')){
			$jdoc->addStyleSheet(T3_ADMIN_URL . '/admin/css/admin-j30.css');

			if($input->get('file') && version_compare(JVERSION, '3.2', 'ge')){
				$jdoc->addStyleSheet(T3_ADMIN_URL . '/admin/css/file-manager.css');
			}
		} else {
			$jdoc->addStyleSheet(T3_ADMIN_URL . '/admin/css/admin-j25.css');
		}

		if(!$this->checkAssetsLoaded('chosen.jquery.min.js', '_scripts')){
			$jdoc->addScript(T3_ADMIN_URL . '/admin/plugins/chosen/chosen.jquery.min.js');	
		}

		$jdoc->addScript(T3_ADMIN_URL . '/includes/depend/js/depend.js');
		$jdoc->addScript(T3_ADMIN_URL . '/admin/js/json2.js');
		$jdoc->addScript(T3_ADMIN_URL . '/admin/js/jimgload.js');
		$jdoc->addScript(T3_ADMIN_URL . '/admin/layout/js/layout.js');
		if(version_compare(JVERSION, '4','lt')){
			$jdoc->addScript(T3_ADMIN_URL . '/admin/js/admin.js');
		}else{
			$jdoc->addScript(T3_ADMIN_URL . '/admin/js/admin_j4.js');
		}


		$jdoc->addScriptDeclaration ( '
			T3Admin = window.T3Admin || {};
			T3Admin.adminurl = \'' . JUri::getInstance()->toString() . '\';
			T3Admin.t3adminurl = \'' . T3_ADMIN_URL . '\';
			T3Admin.baseurl = \'' . JURI::base(true) . '\';
			T3Admin.rooturl = \'' . JURI::root() . '\';
			T3Admin.template = \'' . T3_TEMPLATE . '\';
			T3Admin.templateid = \'' . Factory::getApplication()->input->get('id') . '\';
			T3Admin.langs = ' . json_encode($langs) . ';
			T3Admin.devmode = ' . $params->get('devmode', 0) . ';
			T3Admin.themermode = ' . $params->get('themermode', 1) . ';
			T3Admin.eids = [' . implode(',', $eids) .'];
			T3Admin.telement = \'' . T3_TEMPLATE . '\';
			T3Admin.felement = \'' . T3_ADMIN . '\';
			T3Admin.jversion = \'' . jversion::MAJOR_VERSION . '\';
			T3Admin.themerUrl = \'' . JUri::getInstance()->toString() . '&t3action=theme&t3task=thememagic' . '\';
			T3Admin.megamenuUrl = \'' . JUri::getInstance()->toString() . '&t3action=megamenu&t3task=megamenu' . '\';
			T3Admin.t3updateurl = \'' . JURI::base() . 'index.php?option=com_installer&view=update&task=update.ajax' . '\';
			T3Admin.t3layouturl = \'' . JURI::base() . 'index.php?t3action=layout' . '\';
			T3Admin.jupdateUrl = \'' . JURI::base() . 'index.php?option=com_installer&view=update' . '\';'
		);

		// render admin
		// $this->_renderAdmin();
		$this->_renderToolbar();

	}

	public function addJSLang($key = '', $value = '', $overwrite = true){
		if($key && $value && ($overwrite || !array_key_exists($key, $this->langs))){
			$this->langs[$key] = $value ? $value : JText::_($key);
		}
	}
	
	/**
	 * function loadParam
	 * load and re-render parameters
	 *
	 * @return render success or not
	 */
	function _renderAdmin(){
		return;
		$frwXml = T3_ADMIN_PATH . '/'. T3_ADMIN . '.xml';
		$tplXml = T3_TEMPLATE_PATH . '/templateDetails.xml';
		$cusXml = T3Path::getPath('etc/assets.xml');
		$jtpl = T3_ADMIN_PATH . '/admin/tpls/default.php';
		
		if(file_exists($tplXml) && file_exists($jtpl)){
			
			T3::import('depend/t3form');

			//get the current joomla default instance
			$form = JForm::getInstance('com_templates.style', 'style', array('control' => 'jform', 'load_data' => true));

			//wrap
			$form = new T3Form($form);
			
			//remove all fields from group 'params' and reload them again in right other base on template.xml
			$form->removeGroup('params');
			//load the template
			$form->loadFile(T3_PATH . '/params/template.xml');
			//overwrite / extend with params of template
			$form->loadFile($tplXml, true, '//config');
			//overwrite / extend with custom config in custom/etc/assets.xml
			if ($cusXml && file_exists($cusXml))
				$form->loadFile($cusXml, true, '//config');
			// extend parameters
			T3Bot::prepareForm($form);

			$xml = simplexml_load_file($tplXml);
			$fxml = simplexml_load_file($frwXml);

			$db = Factory::getDbo();
			$query = $db->getQuery(true);
			$query
				->select('id, title')
				->from('#__template_styles')
				->where('template='. $db->quote(T3_TEMPLATE));
			
			$db->setQuery($query);
			$styles = $db->loadObjectList();
			foreach ($styles as $key => &$style) {
				$style->title = ucwords(str_replace('_', ' ', $style->title));
			}
			
			$session = Factory::getSession();
			$t3lock = $session->get('T3.t3lock', 'overview_params');
			$session->set('T3.t3lock', null);
			$input = Factory::getApplication()->input;

			ob_start();
			include $jtpl;
			$this->html['admin'] = ob_get_clean();
			/*
			//search for global parameters
			$japp = Factory::getApplication();
			$pglobals = array();
			foreach($form->getGroup('params') as $param){
				if($form->getFieldAttribute($param->fieldname, 'global', 0, 'params')){
					$pglobals[] = array('name' => $param->fieldname, 'value' => $form->getValue($param->fieldname, 'params')); 
				}
			}
			$japp->setUserState('oparams', $pglobals);
			*/

			return true;
		}
		
		return false;
	}

	function _renderToolbar() {
		$t3toolbar = T3_ADMIN_PATH . '/admin/tpls/toolbar.php';
		$input = Factory::getApplication()->input;

		if(file_exists($t3toolbar) && class_exists('JToolBar')){
			//get the existing toolbar html
			jimport('joomla.language.help');
			$params  = T3::getTplParams();
			$this->html['toolbar'] = JToolBar::getInstance('toolbar')->render();
			$helpurl = JHelp::createURL($input->getCmd('view') == 'template' ? 'JHELP_EXTENSIONS_TEMPLATE_MANAGER_TEMPLATES_EDIT' : 'JHELP_EXTENSIONS_TEMPLATE_MANAGER_STYLES_EDIT');
			$helpurl = htmlspecialchars($helpurl, ENT_QUOTES);

			//render our toolbar
			ob_start();
			include $t3toolbar;
			$this->html['t3toolbar'] = ob_get_clean();
		}
	}

	function replaceToolbar($body){
		/*
		$t3toolbar = T3_ADMIN_PATH . '/admin/tpls/toolbar.php';
		$input = Factory::getApplication()->input;

		if(file_exists($t3toolbar) && class_exists('JToolBar')){
			//get the existing toolbar html
			jimport('joomla.language.help');
			$params  = T3::getTplParams();
			$toolbar = JToolBar::getInstance('toolbar')->render();
			$helpurl = JHelp::createURL($input->getCmd('view') == 'template' ? 'JHELP_EXTENSIONS_TEMPLATE_MANAGER_TEMPLATES_EDIT' : 'JHELP_EXTENSIONS_TEMPLATE_MANAGER_STYLES_EDIT');
			$helpurl = htmlspecialchars($helpurl, ENT_QUOTES);

			//render our toolbar
			ob_start();
			include $t3toolbar;
			$t3toolbar = ob_get_clean();

			//replace it
			$body = str_replace($toolbar, $t3toolbar, $body);
		}
		*/

		//$body = str_replace($this->html['toolbar'], $this->html['t3toolbar'], $body);
		$body = str_replace('[[TOOLBAR]]', $this->html['t3toolbar'], $body);
		return $body;
	}

	function replaceDoctype($body){
		return preg_replace('@<!DOCTYPE\s(.*?)>@', '<!DOCTYPE html>', $body);
	}

	function checkAssetsLoaded($pattern, $hash){
		$doc = Factory::getDocument();
		$hash = $doc->$hash;

		foreach ($hash as $path => $object) {
			if(strpos($path, $pattern) !== false){
				return true;
			}
		}

		return false;
	}
}

?>core/action.php000060400000015043152455303040007462 0ustar00<?php
/** 
 *------------------------------------------------------------------------------
 * @package       T3 Framework for Joomla!
 *------------------------------------------------------------------------------
 * @copyright     Copyright (C) 2004-2013 JoomlArt.com. All Rights Reserved.
 * @license       GNU General Public License version 2 or later; see LICENSE.txt
 * @authors       JoomlArt, JoomlaBamboo, (contribute to this project at github 
 *                & Google group to become co-author)
 * @Google group: https://groups.google.com/forum/#!forum/t3fw
 * @Link:         http://t3-framework.org 
 *------------------------------------------------------------------------------
 */

// No direct access
defined('_JEXEC') or die();
/**
 * T3Action class
 *
 * @package T3
 */
class T3Action
{
	public static function run ($action) {
		if (method_exists('T3Action', $action)) {
			$option = preg_replace('/[^A-Z0-9_\.-]/i', '', JFactory::getApplication()->input->getCmd('view'));

			if(!defined('JPATH_COMPONENT')){
				define('JPATH_COMPONENT', JPATH_BASE . '/components/' . $option);
			}

			if(!defined('JPATH_COMPONENT_SITE')){
				define('JPATH_COMPONENT_SITE', JPATH_SITE . '/components/' . $option);
			}

			if(!defined('JPATH_COMPONENT_ADMINISTRATOR')){
				define('JPATH_COMPONENT_ADMINISTRATOR', JPATH_ADMINISTRATOR . '/components/' . $option);
			}

			T3Action::$action();
		}
		exit;
	}

	public static function lessc () {
		$path = JFactory::getApplication()->input->getString ('s');

		T3::import ('core/less');
		$css = T3Less::getCss($path);

		header("Content-Type: text/css");
		header("Content-length: ".strlen($css));
		echo $css;
	}

	public static function lesscall(){
		T3::import ('core/less');
		
		$input  = JFactory::getApplication()->input;
		$result = array();

		try{
			T3Less::compileAll($input->get('theme', ''));
			$result['successful'] = JText::_('T3_MSG_COMPILE_SUCCESS');
		}catch(Exception $e){
			// $result['error'] = JText::sprintf('T3_MSG_COMPILE_FAILURE', $e->__toString());
			$result['error'] = JText::sprintf('T3_MSG_COMPILE_FAILURE', $e->getMessage());
		}
		
		echo json_encode($result);
	}

	public static function theme(){
		
		JFactory::getLanguage()->load('tpl_' . T3_TEMPLATE, JPATH_SITE);

		if(!defined('T3')) {
			die(json_encode(array(
				'error' => JText::_('T3_MSG_PLUGIN_NOT_READY')
			)));
		}

		$user = JFactory::getUser();
		$action = JFactory::getApplication()->input->getCmd('t3task', '');

		if ($action != 'thememagic' && !$user->authorise('core.manage', 'com_templates')) {
		    die(json_encode(array(
				'error' => JText::_('T3_MSG_NO_PERMISSION')
			)));
		}
		
		if(empty($action)){
			die(json_encode(array(
				'error' => JText::_('T3_MSG_UNKNOW_ACTION')
			)));
		}

		T3::import('admin/theme');
		
		if(method_exists('T3AdminTheme', $action)){
			T3AdminTheme::$action(T3_TEMPLATE_PATH);
		} else {
			die(json_encode(array(
				'error' => JText::_('T3_MSG_UNKNOW_ACTION')
			)));
		}
	}

	public static function layout(){
		self::cloneParam('t3layout');

		if(!defined('T3')) {
			die(json_encode(array(
				'error' => JText::_('T3_MSG_PLUGIN_NOT_READY')
			)));
		}

		$action = JFactory::getApplication()->input->get('t3task', '');
		if(empty($action)){
			die(json_encode(array(
				'error' => JText::_('T3_MSG_UNKNOW_ACTION')
			)));
		}

		if($action != 'display'){
			$user = JFactory::getUser();
			if (!$user->authorise('core.manage', 'com_templates')) {
			    die(json_encode(array(
					'error' => JText::_('T3_MSG_NO_PERMISSION')
				)));
			}
		}

		T3::import('admin/layout');
		
		if(method_exists('T3AdminLayout', $action)){
			T3AdminLayout::$action(T3_TEMPLATE_PATH);	
		} else {
			die(json_encode(array(
				'error' => JText::_('T3_MSG_UNKNOW_ACTION')
			)));
		}
	}

	public static function megamenu() {
		self::cloneParam('t3menu');

		JFactory::getLanguage()->load('tpl_' . T3_TEMPLATE, JPATH_SITE);

		if(!defined('T3')) {
			die(json_encode(array(
				'error' => JText::_('T3_MSG_PLUGIN_NOT_READY')
			)));
		}

		$action = JFactory::getApplication()->input->get('t3task', '');
		if(empty($action)){
			die(json_encode(array(
				'error' => JText::_('T3_MSG_UNKNOW_ACTION')
			)));
		}

		if($action != 'display'){
			$user = JFactory::getUser();
			if (!$user->authorise('core.manage', 'com_templates')) {
			    die(json_encode(array(
					'error' => JText::_('T3_MSG_NO_PERMISSION')
				)));
			}
		}

		T3::import('admin/megamenu');
		
		if(method_exists('T3AdminMegamenu', $action)){
			T3AdminMegamenu::$action();	
			exit;
		} else {
			die(json_encode(array(
				'error' => JText::_('T3_MSG_UNKNOW_ACTION')
			)));
		}
	}

	public static function module () {
		$user   = JFactory::getUser();
		$input  = JFactory::getApplication()->input;
		$id     = $input->getInt('mid');
		$t3acl  = (int)$input->get('t3acl', 1);
		$groups = $user->getAuthorisedViewLevels();
		$module = null;
		$buffer = null;

		array_push($groups, $t3acl);

		if (is_array($groups) && in_array(3, $groups)) { 
			//we assume, if a user is special, they should be registered also
			$groups[] = 2;
		}

		if ($id) {
			// load module
			$db = JFactory::getDbo();
			$query = $db->getQuery(true);
			$query
				->select('m.id, m.title, m.module, m.position, m.content, m.showtitle, m.params')
				->from('#__modules AS m')
				->where('m.id = '.$id)
				->where('m.published = 1')
				->where('m.access IN ('.implode(',', array_unique($groups)).')');
			$db->setQuery($query);
			$module = $db->loadObject();
		}

		if (!empty ($module)) {
			$style  = $input->getCmd ('style', 'T3Xhtml');
			$buffer = JModuleHelper::renderModule($module, array('style'=>$style));
			
			// replace relative images url
			$base      = JURI::base(true).'/';
			$protocols = '[a-zA-Z0-9]+:'; //To check for all unknown protocals (a protocol must contain at least one alpahnumeric fillowed by :
			$regex     = '#(src)="(?!/|' . $protocols . '|\#|\')([^"]*)"#m';
			$buffer    = preg_replace($regex, "$1=\"$base\$2\"", $buffer);
		}

		if($buffer){
			//remove invisibile content, there are more ... but ...
			if ($input->get('skipjscss')) {
				$buffer = preg_replace(array( '@<style[^>]*?>.*?</style>@siu', '@<script[^>]*?.*?</script>@siu'), array('', ''), $buffer);
			}

			echo $buffer;	
		} else {
			die(json_encode(array(
				'message' => JText::_('T3_MSG_MODULE_NOT_AVAIL')
			)));
		}
		
	}

	//translate param name to new name, from jvalue => to desired param name
	public static function cloneParam($param = '', $from = 'jvalue'){
		$input = JFactory::getApplication()->input;

		if(!empty($param) && $input->getWord($param, '') == ''){
			$input->set($param, $input->getCmd($from));
		}
	}
}core/template.php000060400000106613152455303040010024 0ustar00<?php
/**
 *------------------------------------------------------------------------------
 * @package       T3 Framework for Joomla!
 *------------------------------------------------------------------------------
 * @copyright     Copyright (C) 2004-2013 JoomlArt.com. All Rights Reserved.
 * @license       GNU General Public License version 2 or later; see LICENSE.txt
 * @authors       JoomlArt, JoomlaBamboo, (contribute to this project at github
 *                & Google group to become co-author)
 * @Google group: https://groups.google.com/forum/#!forum/t3fw
 * @Link:         http://t3-framework.org
 *------------------------------------------------------------------------------
 */

use Joomla\CMS\HTML\HTMLHelper;

// No direct access
defined('_JEXEC') or die();

T3::import('extendable/extendable');

/**
 * T3Template class provides extended template tools used for T3 framework
 *
 * @package T3
 */
class T3Template extends ObjectExtendable
{
	/**
	 * Define constants
	 */
	protected $maxgrid      = 12;
	protected $widthprefix  = 'span';
	protected $nonrspprefix = 'span';
	protected $spancls      = '/(\s*)span(\d+)(\s*)/';
	protected $responcls    = false;								//indicate this will use data-[device] property or not
	protected $rowfluidcls  = 'row-fluid';
	protected $defdv        = 'default';
	protected $devices      = array('default', 'wide', 'normal', 'xtablet', 'tablet', 'mobile');
	protected $maxcol       = array('default' => 6, 'wide' => 6, 'normal' => 6, 'xtablet' => 4, 'tablet' => 3, 'mobile' => 2);
	protected $minspan      = array('default' => 2, 'wide' => 2, 'normal' => 2, 'xtablet' => 3, 'tablet' => 4, 'mobile' => 6);
	protected $prefixes     = array('span');

	/**
	 * Current template instance
	 */
	public $_tpl = null;


	/**
	 * Store layout settings if exist
	 */
	protected $_layoutsettings = null;


	/**
	 * page class
	 */
	protected $_pageclass = array();


	// after dispatch
	public function init() {

	}
	/**
	 * Class constructor
	 *
	 * @param   object $template Current template instance
	 */
	public function __construct($template = null)
	{
		// merge the base theme information
		$this->maxgrid      = T3_BASE_MAX_GRID;
		$this->widthprefix  = T3_BASE_WIDTH_PREFIX;
		$this->nonrspprefix = T3_BASE_NONRSP_WIDTH_PREFIX;
		$this->spancls      = T3_BASE_WIDTH_REGEX;
		$this->responcls    = T3_BASE_RSP_IN_CLASS;
		$this->rowfluidcls  = T3_BASE_ROW_FLUID_PREFIX;
		$this->defdv        = T3_BASE_DEFAULT_DEVICE;
		$this->devices      = json_decode(T3_BASE_DEVICES, true);
		$this->maxcol       = json_decode(T3_BASE_DV_MAXCOL, true);
		$this->minspan      = json_decode(T3_BASE_DV_MINWIDTH, true);
		$this->prefixes     = json_decode(T3_BASE_DV_PREFIX, true);

		// layout settings
		$this->_layoutsettings = new JRegistry;

		if ($template) {
			$this->_tpl = $template;
			$this->_extend(array($template));

			// merge layout setting
			$layout = JFactory::getApplication()->input->getCmd('t3layout', '');
			if (empty($layout)) {
				$layout = $template->params->get('mainlayout', 'default');
			}

			$fconfig = T3Path::getPath('etc/layout/' . $layout . '.ini');
			if (is_file($fconfig)) {
				jimport('joomla.filesystem.file');
				$this->_layoutsettings->loadString(file_get_contents($fconfig), 'INI', array('processSections' => true));
			}
		}
		JFactory::getApplication()->triggerEvent('onT3TplInit', array($this));

		//JDispatcher::getInstance()->trigger('onT3TplInit', array($this));
	}


	/**
	 * Get template parameter
	 * @param  string  $name     parameter name
	 * @param  mixed   $default  parameter default value
	 *
	 * @return  mixed  parameter value
	 */
	public function getParam($name, $default = null)
	{
		return $this->_tpl->params->get($name, $default);
	}


	/**
	 * Set template parameter. It will not store to database. This should not be used
	 * @param  string  $name   parameter name
	 * @param  mixed   $value  parameter value
	 *
	 * @return  null
	 */
	public function setParam($name, $value)
	{
		return $this->_tpl->params->set($name, $value);
	}


	/**
	 * Get current layout tpls
	 *
	 * @return string Layout name
	 */
	public function getLayout()
	{
		$input = JFactory::getApplication()->input;
		// get override layout by tmpl
		$layout = $input->getCmd('tmpl');
		if ($layout && T3Path::getPath('tpls/' . $layout . '.php')) return $layout;
		// detect if this is menu page or sub-page if set
		$menu_page = true;
		$input = JFactory::getApplication()->input;
		$active = JFactory::getApplication()->getMenu()->getActive();
		if ($active && isset($active->query)) {
			foreach ($active->query as $name => $value) {
				if ($input->get($name, null, 'raw') != $value) {
					$menu_page = false;
					break;
				}
			}
		}

		$mainlayout = $this->getParam('mainlayout', 'default');
		$sublayout = $this->getParam('sublayout', '');

		return !$menu_page && $sublayout ? $sublayout : $mainlayout;
	}


	/**
	 * Get layout settings (Layout Tab)
	 * @param  string  $name     parameter name
	 * @param  mixed   $default  parameter default value
	 *
	 * @return string Layout name
	 */
	public function getLayoutSetting($name, $default = null)
	{
		return isset($this->_layoutsettings) ? $this->_layoutsettings->get($name, $default) : $default;
	}


	/**
	 * Load block content
	 * @param  string  $block  Block name - the real block is tpls/blocks/[block].php
	 * @param  array   $vars   information of block (used in template layout)
	 *
	 * @return string Block content
	 */
	function loadBlock($block, $vars = array())
	{
		$path = T3Path::getPath('tpls/blocks/' . $block . '.php');
		if ($path) {
			if($block == 'footer'){

				ob_start();
				include $path;
				$buffer = ob_get_contents();
				ob_end_clean();
				$buffer = T3::fixT3Link($buffer);
				echo $buffer;

			} else {
				include $path;
			}
		} else {
			echo "<div class=\"error\">Block [$block] not found!</div>";
		}
		// make sure other the block is ended with a new line
		echo "\n";
	}


	/**
	 * Load block layout
	 *
	 * @param string &layout  Block name - the real block is tpls/[layout].php
	 *
	 * @return null
	 */
	function loadLayout($layout)
	{
		$path = T3Path::getPath('tpls/' . $layout . '.php', 'tpls/default.php');

		JFactory::getApplication()->triggerEvent('onT3LoadLayout', array(&$path, $layout));

		if (is_file($path)) {

			ob_start();
			include $path;
			$buffer = ob_get_contents();
			ob_end_clean();
			if($this->responcls && !$this->getParam('responsive', 1)){
				//replace
				$buffer = preg_replace_callback('@class\s?=\s?(\'|")(([^\'"]*)(' . implode('|', $this->prefixes) . ')+([^\'"]*))(\'|")@m', array($this, 'responCls'), $buffer);
			}
			// check if exist megamenu renderer, place megamenurender on the top to render megamenu before render head
			if (preg_match_all ('/(<jdoc:include type="megamenu"[^>]*>)/i', $buffer, $match)) {
				foreach ($match[1] as $m) {
					$buffer = str_replace ('type="megamenu"', 'type="megamenurender"', $m).$buffer;
					T3::import('renderer/megamenurender');
				}
			}
			//output
			echo $buffer;

		} else {
			echo "<div class=\"error\">Layout [$layout] or [Default] not found!</div>";
		}
	}

	/**
	 * Load spotlight block
	 * @param  string  $name       Name of the spotlight. Default will load positions base on this name: [name]-1, [name]-2...
	 * @param  string  $positions  The positions of spotlight, separated by comma
	 * @param  array   $info       Other information of spotlight
	 *
	 * @return null
	 */
	function spotlight($name, $positions, array $info = array())
	{
		$defdv  = $this->defdv;
		$defpos = preg_split('/\s*,\s*/', $positions);
		$vars   = is_array($info) ? $info : array();
		$cols   = count($defpos);
		$poss   = $defpos;

		$splparams = array();
		for ($i = 1; $i <= $this->maxgrid; $i++) {
			$param = $this->getLayoutSetting('block' . $i . '@' . $name);
			if (empty($param)) {
				break;
			} else {
				$splparams[] = $param;
			}
		}

		//we have configuration in setting file
		if (!empty($splparams)) {
			$poss = array();
			foreach ($splparams as $idx => $splparam) {
				$param = (object)$splparam;
				$poss[] = isset($param->position) ? $param->position : $defpos[$idx];
			}

			$cols = count($poss);
		}

		// check if there's any modules
		if (!$this->countModules(implode(' or ', $poss))) {
			return;
		}

		//empty - so we will use default configuration
		if (empty($splparams)) {
			//generate a optimize default width
			$default = $this->genWidth($defdv, $cols);

			foreach ($poss as $i => $pos) {
				//is there any configuration param
				$var = isset($vars[$pos]) ? $vars[$pos] : '';

				$param = new stdClass;
				$param->position = $pos;

				$param->$defdv = ($var && isset($var[$defdv])) ? $var[$defdv] : $this->widthprefix . $default[$i];
				if ($var) {
					foreach($this->devices as $device){
						if (isset($var[$device])) {
							$param->$device = $var[$device];
						}
					}

				}

				$splparams[$i] = $param;
			}
		}

		//build data
		$responsive = $this->getParam('responsive', 1);
		$datas      = array();
		foreach ($splparams as $splparam) {
			$param = (object)$splparam;

			$data = '';

			if($responsive){

				foreach($this->devices as $device){

					if(isset($param->$device)){
						$prefix = $this->responcls ? ' ' : ' data-' . $device . '="';
						$posfix = $this->responcls ? '' : '"';

						if(strpos(' ' . $param->$device . ' ', ' hidden ') !== false){
							$param->$device = str_replace(' hidden ', ' hidden-' . $device . ' ', ' ' . $param->$device . ' ');
						}

						$data .= $prefix . $param->$device . $posfix;
					}
				}
			} else {
				$data = isset($param->$defdv) ? ' ' . $param->$defdv : '';

				if($this->nonrspprefix && ($this->nonrspprefix != $this->widthprefix)){
					$data = str_replace($this->widthprefix, $this->nonrspprefix, $data);
				}
			}

			$datas[] = $data;
		}

		//pack to single variable
		$vars['name']      = $name;
		$vars['splparams'] = $splparams;
		$vars['datas']     = $datas;
		$vars['cols']      = $cols;

		JFactory::getApplication()->triggerEvent('onT3Spotlight', array(&$vars, $name, $positions));

		$this->loadBlock('spotlight', $vars);
	}


	/**
	 * Render megamenu markup
	 * @param  string  $menutype  The menutype to render
	 *
	 * @deprecated  Use <jdoc:include type="megamenu" name="$menutype" /> instead
	 */
	function megamenu($menutype)
	{
		echo "<jdoc:include type=\"megamenu\" name=\"{$menutype}\" />";
	}

	/**
	 * Get data property for layout - responsive layout
	 * @param  object   $layout  Layout configuration object
	 * @param  number   $col     Column number, start from 0
	 * @param  boolean  $array   Return array or string
	 *
	 * @return  mixed  Block content
	 */
	function getData($layout, $col, $array = false)
	{
		if ($array) {
			$data = array();
			foreach ($layout as $device => $width) {
				if (!isset ($width[$col]) || !$width[$col]) continue;
				$data[$device] = $width[$col];
			}

		} else {
			$data = '';
			foreach ($layout as $device => $width) {
				if (!isset ($width[$col]) || !$width[$col]) continue;
				$data .= " data-$device=\"{$width[$col]}\"";
			}
		}

		return $data;
	}


	/**
	 * Get layout column class
	 * @param  object  $layout  Layout configuration object
	 * @param  number  $col     Column number, start from 0
	 *
	 * @return string  Block content
	 */
	function getClass($layout, $col)
	{
		$defdv = $this->defdv;

		if($this->responcls){
			$result     = '';
			$responsive = $this->getParam('responsive', 1);

			if($responsive){
				foreach ($layout as $width) {
					if (!isset ($width[$col]) || !$width[$col]) {
						continue;
					}

					$result .= ' ' . $width[$col];
				}

			} else {
				//remove all width classes
				$width   = $this->maxgrid;
				$clayout = isset($layout->$defdv) ? $layout->$defdv : false;

				if($clayout && !empty($clayout[$col])){
					$defcls = $clayout[$col];
					if(preg_match($this->spancls, $defcls, $match)){
						$width = array_pop(array_filter($match, 'is_numeric'));
						$width = ($width ? $width : $this->maxgrid);
					}
				}

				$result = ' ' . $this->nonrspprefix . $width;
			}

			return $result;

		} else {

			$width = $layout->$defdv;
			if (!isset ($width[$col]) || !$width[$col]){
				return '';
			}

			return $width[$col];
		}
	}

	/**
	 * Get layout column class
	 * @param  object  $layout  Layout configuration object
	 * @param  number  $col     Column number, start from 0
	 *
	 * @return string  Block content
	 */
	function responCls($class)
	{
		$result = $class[2];
		$queue  = array();

		//remove all width classes
		foreach ($this->prefixes as $prefix) {
			if($result && preg_match_all('@' . preg_quote($prefix) . '[^\s]*@', $result, $match)){
				$result = preg_replace('@' . preg_quote($prefix) . '[^\s]*@', ' ', $result);

				foreach ($match[0] as $m) {
					$parts = preg_split('@(\d+)@', $m, -1, PREG_SPLIT_DELIM_CAPTURE);
					$parts[0] = str_replace($prefix, $this->nonrspprefix, $parts[0]);
					if(!isset($queue[$parts[0]])){
						$queue[$parts[0]] = $parts[1];
					}
				}
			}
		}

		if(!empty($queue)){
			$result = trim($result); //would be better than preg_replace ?
			foreach ($queue as $key => $value) {
				$result .= ' ' . $key . $value;
			}
		}

		return 'class="' . trim($result) . '"';
	}


	/**
	 * Add page class
	 */
	function addPageClass($class)
	{
		$this->_pageclass = array_merge($this->_pageclass, (array)($class));
	}

	/**
	 * Add page class
	 *
	 * @deprecated
	 */
	function addBodyClass($class)
	{
		$this->_pageclass = array_merge($this->_pageclass, (array)($class));
	}

	/**
	 * get page class
	 */
	function getPageClass()
	{
		return $this->_pageclass;
	}


	/**
	 * Render page class
	 *
	 * @deprecated  Use <jdoc:include type="pageclass" /> instead
	 */
	function bodyClass()
	{
		$input = JFactory::getApplication()->input;

		if ($input->getCmd('option', '')) {
			$this->_pageclass[] = $input->getCmd('option', '');
		}
		if ($input->getCmd('view', '')) {
			$this->_pageclass[] = 'view-' . $input->getCmd('view', '');
		}
		if ($input->getCmd('layout', '')) {
			$this->_pageclass[] = 'layout-' . $input->getCmd('layout', '');
		}
		if ($input->getCmd('task', '')) {
			$this->_pageclass[] = 'task-' . $input->getCmd('task', '');
		}
		if ($input->getCmd('Itemid', '')) {
			$this->_pageclass[] = 'itemid-' . $input->getCmd('Itemid', '');
		}

		$menu = JFactory::getApplication()->getMenu();
		if ($menu) {
			$active = $menu->getActive();
			$default = $menu->getDefault();

			if ($active) {
				if ($default && $active->id == $default->id) {
					$this->_pageclass[] = 'home';
				}

				if ($active->params && $active->params->get('pageclass_sfx')) {
					$this->_pageclass[] = $active->params->get('pageclass_sfx');
				}
			}
		}

		// hover trigger for megamenu
		if ($this->getParam('navigation_trigger', 'hover') == 'hover') {
			$this->_pageclass[] = 'mm-hover';
		}

		$this->_pageclass[] = 'j' . str_replace('.', '', (number_format((float)JVERSION, 1, '.', '')));
		if(version_compare(JVERSION,'4','ge')){
			$this->_pageclass[] = 'j40';
		}
		$this->_pageclass = array_unique($this->_pageclass);

		JFactory::getApplication()->triggerEvent('onT3BodyClass', array(&$this->_pageclass));

		echo implode(' ', $this->_pageclass);
	}


	/**
	 * Render snippet
	 *
	 * @return null
	 */
	function snippet()
	{
		$places   = array();
		$contents = array();

		if (($openhead = $this->getParam('snippet_open_head', ''))) {
			$places[] = '@^\s*<head>\s*$@msU';	//not sure that any attritube can be place in head open tag, profile is not support in html5
			$contents[] = "<head>\n" . $openhead;
		}
		if (($closehead = $this->getParam('snippet_close_head', ''))) {
			$places[] = '@^\s*</head>\s*$@msU';
			$contents[] = $closehead . "\n</head>";
		}
		if (($openbody = $this->getParam('snippet_open_body', ''))) {
			$places[] = '@^\s*<body[^>]*>\s*$@msU';
			$contents[] = "$0\n" . $openbody;
		}

		// append modules in debug position
		if ($this->getParam('snippet_debug', 0) && $this->countModules('debug') || ($closebody = $this->getParam('snippet_close_body', ''))) {
			$places[] = '@^\s*</body>\s*$@msU';
			$replacefooter = '';
			if ($this->getParam('snippet_debug', 0) && $this->countModules('debug')) {
				$replacefooter .= '<div class="t3-debug">' . $this->getBuffer('modules', 'debug') . "</div>\n";
			}
			if (($closebody = $this->getParam('snippet_close_body', ''))) {
				$replacefooter .= $closebody . "\n";
			}
			$replacefooter .= "</body>";
			$contents[] = $replacefooter;
		}

		if (count($places)) {			
			$body = JFactory::getApplication()->getBody();
			$body = preg_replace($places, $contents, $body);

			JFactory::getApplication()->setBody($body);
		}
	}


	/**
	 * Wrap of document countModules function, get position from configuration before calculate
	 * @param   string  $positions  Positions string
	 * @return  boolean  The position key is available or not
	 */
	function countModules($positions)
	{
		if (!$this->_tpl || !method_exists($this->_tpl, 'countModules')) return 0;

		// get real post name
		$pos = $this->getPosname($positions);

		// support only and, or - back compatibility
		if (preg_match ('/ or /i', $pos)) {
			$arr = preg_split('/ or /i', $pos);
			$result = 0;
			foreach ($arr as $p) {
				$result = $result || $this->_tpl->countModules($p);
			}		
			return $result;
		} else if (preg_match ('/ and /i', $pos)) {
			$arr = preg_split('/ and /i', $pos);
			$result = 1;
			foreach ($arr as $p) {
				$result = $result && $this->_tpl->countModules($p);
			}		
			return $result;
		} 

		return $this->_tpl->countModules($pos);
	}


	/**
	 * Wrap of document countModules function, used to detect if a spotlight is available to render or not
	 * @param  string  $name       The spotlight name
	 * @param  string  $positions  The positions name separated by comma
	 *
	 * @return  boolean  The spotlight is available or not
	 */
	function checkSpotlight($name, $positions)
	{
		if (!$this->_tpl || !method_exists($this->_tpl, 'countModules')) return 0;

		$poss = array();

		for ($i = 1; $i <= $this->maxgrid; $i++) {
			$param = $this->getLayoutSetting('block' . $i . '@' . $name);
			if (empty($param)) {
				break;
			} else {
				$param = (object)$param;
				$poss[] = isset($param->position) ? $param->position : '';
			}
		}

		if (empty($poss)) {
			$poss = preg_split('/\s*,\s*/', $positions);
		}

		// fix deprecated error: using expression in HtmlDocument::countModules()
		foreach ($poss as $pos) {
			if ($this->_tpl->countModules($pos)) return 1;
		}

		return 0;

		//return $this->_tpl && method_exists($this->_tpl, 'countModules') ? $this->_tpl->countModules(implode(' or ', $poss)) : 0;
	}


	/**
	 * Check system messages
	 *
	 * @return  boolean  The system message queue has any message or not
	 */
	function hasMessage()
	{
		// Get the message queue
		$app      = JFactory::getApplication();
		$input    =  $app->input;

		if($input->getCmd('option') == 'com_content'){
			$messages = $app->getMessageQueue();

			return !empty($messages);
		}

		return true;
	}


	/**
	 * Get mapped position name
	 * @param  string  $condition  The position key(name)
	 *
	 * @return  string  The mapped position
	 */
	function getPosname($condition)
	{
		$operators = '(,|\+|\-|\*|\/|==|\!=|\<\>|\<|\>|\<=|\>=|and|or|xor)';
		$words = preg_split('# ' . $operators . ' #', $condition, -1, PREG_SPLIT_DELIM_CAPTURE);
		for ($i = 0, $n = count($words); $i < $n; $i += 2) {
			// odd parts (modules)
			$name = strtolower($words[$i]);
			$words[$i] = $this->getLayoutSetting($name, $name);
		}

		$poss = '';
		foreach ($words as $word) {
			if (is_string($word)) {
				$poss .= ' ' . $word;
			} else {
				$poss .= ' ' . (is_array($word) ? $word['position'] : (isset($word->position) ? $word->position : $name));
			}
		}
		$poss = trim($poss);

		return $poss;
	}


	/**
	 * Render position name
	 * @param  string  $condition  The key used in block
	 *
	 * @return  null
	 */
	function posname($condition)
	{
		echo $this->getPosname($condition);
	}

	/**
	 * Alias of posname
	 * @param  string  $condition
	 * @return null
	 */
	function _p($condition)
	{
		$this->posname($condition);
	}


	/**
	 * Add position additional class (show/hide)
	 * @param  string  $name  The position name
	 * @param  array   $cls   The responsive array style for responsive layout [lg, md, ...]
	 *
	 * @return null
	 */
	function _c($name, $cls = array())
	{
		$data = '';
		$param = $this->getLayoutSetting($name, '');

		if (empty($param)) {
			if (is_string($cls)) {
				$data = ' ' . $cls;
			} else if (is_array($cls)) {
				$param = (object)$cls;
			}
		}

		if (!empty($param)) {

			foreach ($this->maxcol as $device => $span) {
				//convert hidden class
				if(!empty($param->$device) && strpos(' ' . $param->$device . ' ', ' hidden ') !== false){
					$param->$device = str_replace(' hidden ', ' hidden-' . $device . ' ', ' ' . $param->$device . ' ');
				}

				if(!empty($param->$device)){
					$prefix = $this->responcls ? ' ' : ' data-' . $device . '="';
					$posfix = $this->responcls ? '' : '"';
					$data .= $prefix . trim($param->$device) . $posfix;
				}
			}

			$defdv = $this->defdv;
			if(!$this->responcls && !empty($data)){
				$data = (isset($param->$defdv) ? ' ' . $param->$defdv : '') . ' t3respon"' . substr($data, 0, strrpos($data, '"'));
			}
		}

		echo $data;
	}

	/**
	 * Add current template css base on template setting.
	 * @param $name           string  file name, without .css
	 * @param $addresponsive  bool    add responsive part or not
	 *
	 * @return string Block content
	 */
	function addCss($name, $addresponsive = true)
	{
		$devmode    = $this->getParam('devmode', 0);
		$themermode = $this->getParam('themermode', 1);
		$responsive = $addresponsive && !$this->responcls ? $this->getParam('responsive', 1) : false;

		if (($devmode || ($themermode && defined('T3_THEMER'))) && ($url = T3Path::getUrl('less/' . $name . '.less', '', true, false))) {
			T3::import('core/less');
			T3Less::addStylesheet($url);
		} else {
			$this->addStyleSheet(T3_TEMPLATE_URL . '/css/' . $name . '.css');
		}

		if ($responsive && !$this->responcls) {
			$this->addCss($name . '-responsive', false);
		}
	}

	/**
	 * Add T3 basic head
	 *
	 * @return  null
	 */
	function addHead()
	{

		$app   = JFactory::getApplication();
		$user  = JFactory::getUser();
		$input = $app->input;

		$responsive = $this->getParam('responsive', 1);
		$navtype    = $this->getParam('navigation_type', 'joomla');
		$navtrigger = $this->getParam('navigation_trigger', 'hover');
		$offcanvas  = $this->getParam('navigation_collapse_offcanvas', 0) || $this->getParam('addon_offcanvas_enable', 0);
		$legacycss  = $this->getParam('legacy_css', 0);
		$frontedit  = in_array($input->getCmd('option'), array('com_media', 'com_config'))	//com_media or com_config
			|| in_array($input->getCmd('layout'), array('edit'))								//edit layout
			|| (version_compare(JVERSION, '3.2', 'ge') && $user->id && $app->get('frontediting', 1) &&
				($user->authorise('core.edit', 'com_modules') || $user->authorise('core.edit', 'com_menus')));	//frontediting

		// LEGACY COMPATIBLE
		if($legacycss){
			$this->addCss('legacy-grid');	//legacy grid
			$this->addStyleSheet(T3_URL . '/fonts/font-awesome/css/font-awesome' . ($this->getParam('devmode', 0) ? '' : '.min') . '.css'); //font awesome 3
		}

		if (version_compare(JVERSION, '4', 'ge')) {
			HTMLHelper::stylesheet('media/system/css/joomla-fontawesome.min.css');
		}

		// FRONTEND EDITING
		if($frontedit){
			$this->addCss('frontend-edit');
		}

		// Clear current css to put bootstrap css on top
		$_stylesheets = $this->_styleSheets;
		$this->_styleSheets = array();

		// BOOTSTRAP CSS
		$this->addCss('bootstrap', false);

		// Append current css to bootstrap
		$this->_styleSheets = array_merge($this->_styleSheets, $_stylesheets);

		// TEMPLATE CSS
		$this->addCss('template', false);

		if (!$responsive && $this->responcls) {
			// not responsive for BS3
			$this->addCss('non-responsive'); //no responsive

			$nonrespwidth = $this->getParam('non_responsive_width', '970px');
			if(preg_match('/^(-?\d*\.?\d+)(px|%|em|rem|pc|ex|in|deg|s|ms|pt|cm|mm|rad|grad|turn)?/', $nonrespwidth, $match)){
				$nonrespwidth = $match[1] . (!empty($match[2]) ? $match[2] : 'px');
			}
			$this->addStyleDeclaration('.container {width: ' . $nonrespwidth . ' !important;} .t3-wrapper, .wrap {min-width: ' . $nonrespwidth . ' !important;}');

		} else if($responsive && !$this->responcls){
			// responsive for BS2
			// BOOTSTRAP RESPONSIVE CSS
			$this->addCss('bootstrap-responsive');

			// RESPONSIVE CSS
			$this->addCss('template-responsive');
		}

		// add core megamenu.css in plugin
		// deprecated - will extend the core style into template megamenu.less & megamenu-responsive.less
		// to use variable overridden in template
		if($navtype == 'megamenu'){

			// If the template does not overwrite megamenu.less & megamenu-responsive.less
			// We check and included predefined megamenu style in base
			if(!is_file(T3_TEMPLATE_PATH . '/less/megamenu.less')){
				$this->addStyleSheet(T3_URL . '/css/megamenu.css');

				if ($responsive && !$this->responcls){
					$this->addStyleSheet(T3_URL . '/css/megamenu-responsive.css');
				}
			}

			// megamenu.css override in template
			$this->addCss('megamenu');
		}
		// JFactory::getDocument()->getWebAssetManager()->disableAsset('script','bootstrap.es5');
		
		// Add scripts
		if (version_compare(JVERSION, '3.0', 'ge')) {
			JHtml::_('jquery.framework');
		} else {
			$scripts = @$this->_scripts;
			$jqueryIncluded = 0;
			if (is_array($scripts) && count($scripts)) {
				//simple detect for jquery library. It will work for most of cases
				$pattern = '/(^|\/)jquery([-_]*\d+(\.\d+)+)?(\.min)?\.js/i';
				foreach ($scripts as $script => $opts) {
					if (preg_match($pattern, $script)) {
						$jqueryIncluded = 1;
						break;
					}
				}
			}

			if (!$jqueryIncluded) {
				$this->addScript(T3_URL . '/js/jquery-1.11.2' . ($this->getParam('devmode', 0) ? '' : '.min') . '.js');
				$this->addScript(T3_URL . '/js/jquery.noconflict.js');
			}
		}

		define('JQUERY_INCLUED', 1);


		// As joomla 3.0 bootstrap is buggy, we will not use it
		$this->addScript(T3_URL . '/bootstrap/js/bootstrap.js');
		// a jquery tap plugin
		$this->addScript(T3_URL . '/js/jquery.tap.min.js');

		// add css/js for off-canvas
		if ($offcanvas && ($this->responcls || $responsive)) {
			$this->addCss('off-canvas', false);
			$this->addScript(T3_URL . '/js/off-canvas.js');
		}

		$this->addScript(T3_URL . '/js/script.js');

		//menu control script
		if ($navtrigger == 'hover') {
			$this->addPageClass('mm-hover');
		}

		//if($navtrigger == 'hover' || $this->responcls){
			$this->addScript(T3_URL . '/js/menu.js');
		//}

		//reponsive script
		if ($responsive && !$this->responcls) {
			$this->addScript(T3_URL . '/js/responsive.js');
		}

		//some helper javascript functions for frontend edit
		if($frontedit){
			$this->addScript(T3_URL . '/js/frontend-edit.js');
		}

		//check and add additional assets
		$this->addExtraAssets();
	}

	/**
	 * Update head - detect if devmode or themermode is enabled and less file existed, use less file instead of css
	 * We also detect and update jQuery, Bootstrap to use T3 assets
	 *
	 * @return  null
	 */
	function updateHead()
	{
		//state parameters
		$devmode    = $this->getParam('devmode', 0);
		$themermode = $this->getParam('themermode', 1) && defined('T3_THEMER');
		$theme      = $this->getParam('theme', '');
		$minify     = $this->getParam('minify', 0);
		$minifyjs   = $this->getParam('minify_js', 0);
		// detect RTL
		$doc = JFactory::getDocument();
		$dir    = $doc->direction;
		$is_rtl = ($dir == 'rtl');

		// As Joomla 3.0 bootstrap is buggy, we will not use it
		// We also prevent both Joomla bootstrap and T3 bootsrap are loaded
		// And upgrade jquery as our Framework require jquery 1.7+ if we are loading jquery from google
		$scripts = array();

		if (version_compare(JVERSION, '3.0', 'ge')) {
			$t3bootstrap = false;
			$jabootstrap = false;

			foreach ($doc->_scripts as $url => $script) {
				if (strpos($url, T3_URL . '/bootstrap/js/bootstrap.js') !== false) {
					$t3bootstrap = true;
					if ($jabootstrap) { //we already have the Joomla bootstrap and we also replace to T3 bootstrap
						continue;
					}
				}

				if (preg_match('@media/jui/js/bootstrap(.min)?.js@', $url)) {
					if ($t3bootstrap) { //we have T3 bootstrap, no need to add Joomla bootstrap
						continue;
					} else {
						$scripts[T3_URL . '/bootstrap/js/bootstrap.js'] = $script;
					}

					$jabootstrap = true;
				} else {
					$scripts[$url] = $script;
				}
			}

			$doc->_scripts = $scripts;
			$scripts = array();
		}

		// VIRTUE MART / JSHOPPING compatible
		foreach ($doc->_scripts as $url => $script) {
			$replace = false;

			if ((strpos($url, '//ajax.googleapis.com/ajax/libs/jquery/') !== false &&
					preg_match_all('@/jquery/(\d+(\.\d+)*)?/@msU', $url, $jqver)) ||
				(preg_match_all('@(^|\/)jquery([-_]*(\d+(\.\d+)+))?(\.min)?\.js@i', $url, $jqver))) {

				$idx = strpos($url, '//ajax.googleapis.com/ajax/libs/jquery/') !== false ? 1 : 3;

				if (is_array($jqver) && isset($jqver[$idx]) && isset($jqver[$idx][0])) {
					$jqver = explode('.', $jqver[$idx][0]);

					if (isset($jqver[0]) && (int)$jqver[0] <= 1 && isset($jqver[1]) && (int)$jqver[1] < 7) {
						$scripts[T3_URL . '/js/jquery-1.11.2' . ($devmode ? '' : '.min') . '.js'] = $script;
						$replace = true;
					}
				}
			}

			if (!$replace) {
				$scripts[$url] = $script;
			}
		}

		$doc->_scripts = $scripts;
		// end update javascript

		//Update css/less based on devmode and themermode
		$root        = JURI::root(true);
		$current     = JURI::current();
		// $regex       = '@' . preg_quote(T3_TEMPLATE_REL) . '/css/(rtl/)?(.*)\.css((\?|\#).*)?$@i';
		$regex       = '@' . preg_quote(T3_TEMPLATE_REL) . '/(.*)\.css((\?|\#).*)?$@i';
		$stylesheets = array();
		foreach ($doc->_styleSheets as $url => $css) {
			// detect if this css in template css
			if (preg_match($regex, $url, $match)) {
				$fname = $match[1];

				// remove rtl
				$fname = preg_replace ('@(^|/)rtl/@mi', '\1', $fname);
				// remove local
				$fname = preg_replace ('@^local/@mi', '', $fname);

				// if (($devmode || $themermode) && is_file(T3_TEMPLATE_PATH . '/less/' . $fname . '.less')) {
				if (($devmode || $themermode)) {
					// less file
					$lfname = preg_replace ('@(^|/)css/@mi', '\1less/', $fname);

					if (is_file(T3_TEMPLATE_PATH . '/' . $lfname . '.less')) {
						if ($themermode) {
							$newurl = T3_TEMPLATE_URL . '/' . $lfname . '.less';
							$css['mime'] = 'text/less';
						} else {
							T3::import('core/less');
							$newurl = T3Less::buildCss(T3Path::cleanPath(T3_TEMPLATE_REL . '/' . $lfname . '.less'), true);
						}
						$stylesheets[$newurl] = $css;
						continue;
					}
				}

				$uri = null;
				// detect css available base on direction & theme
				if ($is_rtl && $theme) {
					// rtl css file
					$altfname = preg_replace ('@(^|/)css/@mi', '\1css/rtl/' . $theme . '/', $fname);
					$uri = T3Path::getUrl ($altfname . '.css');
				}

				if (!$uri && $is_rtl) {
					$altfname = preg_replace ('@(^|/)css/@mi', '\1css/rtl/', $fname);
					$uri = T3Path::getUrl ($altfname . '.css');
				}

				if (!$uri && $theme) {
					$altfname = preg_replace ('@(^|/)css/@mi', '\1css/themes/' . $theme . '/', $fname);
					$uri = T3Path::getUrl ($altfname . '.css');
				}

				if (!$uri) {
					$uri = T3Path::getUrl ($fname . '.css');
				}

				if ($uri) {
					$stylesheets[$uri] = $css;
				}
				continue;
			}

			$stylesheets[$url] = $css;
		}

		// update back
		$doc->_styleSheets = $stylesheets;

		//only check for minify if devmode is disabled
		if (!$devmode && ($minify || $minifyjs)) {
			T3::import('core/minify');
			if($minify){
				T3Minify::optimizecss($this);
			}
			if($minifyjs){
				T3Minify::optimizejs($this);
			}
		}
	}

	/**
	 * Add some other condition assets (css, javascript). Use to parse /etc/assets.xml
	 *
	 * @return  null
	 */
	function addExtraAssets()
	{
		$base = JURI::base(true);
		$regurl = '#(http|https)://([a-zA-Z0-9.]|%[0-9A-Za-z]|/|:[0-9]?)*#iu';

		$afiles = T3Path::getAllPath('etc/assets.xml');
		foreach ($afiles as $afile) {
			if (is_file($afile)) {
				//load xml
				$axml = simplexml_load_file($afile);

				//process if exist
				if ($axml) {
					foreach ($axml as $node => $nodevalue) {
						//ignore others node
						if ($node == 'stylesheets' || $node == 'scripts') {
							foreach ($nodevalue->file as $file) {
								$compatible = (string) $file['compatible'];
								if ($compatible) {
									$parts = explode(' ', $compatible);
									$operator = '='; //exact equal to
									$operand = $parts[0];
									if (count($parts) == 2) {
										$operator = $parts[0];
										$operand = $parts[1];
									}

									//compare with Joomla version
									if (!version_compare(JVERSION, $operand, $operator)) {
										continue;
									}
								}

								$url = (string)$file;
								if (substr($url, 0, 2) == '//') { //external link

								} else if ($url[0] == '/') { //absolute link from based folder
									$url = is_file(JPATH_ROOT . $url) ? $base . $url : false;
								} else if (!preg_match($regurl, $url)) { //not match a full url -> sure internal link
									$url = T3Path::getUrl($url); // so get it
								}

								if ($url) {
									$attributes = [];

									foreach ($file->attributes() as $key => $value) {
										$attributes[$key] = (string) $value;
									}

									if ($node == 'stylesheets') {
										$this->addStylesheet($url, array(), $attributes);
									} else {
										$this->addScript($url, array(), $attributes);
									}
								}
							}
						}
					}
				}
			}
		}

		// template extended styles
		$aparams = $this->_tpl->params->toArray();
		$extras = array();
		$itemid = JFactory::getApplication()->input->get ('Itemid');
		foreach ($aparams as $name => $value) {
			if (preg_match ('/^theme_extras_(.+)$/', $name, $m)) {
				$extras[$m[1]] = $value;
			}
		}
		if (count ($extras)) {
			foreach ($extras as $extra => $pages) {
				if (!is_array($pages) || !count($pages) || in_array (0, $pages)) {
					continue; // disabled
				}
				if (in_array (-1, $pages) || in_array($itemid, $pages)) {
					// load this style
					$this->addCss ('extras/'.$extra);
				}
			}
		}
	}


	/**
	 * Turn a param to DOM style value
	 * @param   string   $style  The style property
	 * @param   string   $pname  The parameter name
	 * @param   boolean  $isurl  Is url?
	 *
	 * @return  string   The css style string
	 * @deprecated   This function is no longer used in T3
	 */
	function paramToStyle($style, $pname = '', $isurl = false)
	{
		if ($pname == '') {
			$pname = $style;
		}
		$param = $this->getParam($pname);

		if (!$param) return '';

		if ($isurl) {
			return "$style:url($param);";
		} else {
			return "$style:$param" . (is_numeric($param) ? 'px;' : ';');
		}
	}

	/**
	 * Internal function, auto generate optimize width in a row fit to 12 grid
	 * @param  number  $numpos  number columns in row
	 *
	 * @return  array  The span width layout columns for a row
	 */
	function fitWidth($numpos)
	{
		$result = array();
		$avg = floor($this->maxgrid / $numpos);
		$sum = 0;

		for ($i = 0; $i < $numpos - 1; $i++) {
			$result[] = $avg;
			$sum += $avg;
		}

		$result[] = $this->maxgrid - $sum;

		return $result;
	}

	/**
	 * Internal function, generate auto calculate width
	 * @param   string   $layout  The target layout
	 * @param   number   $numpos  Number of columns (block)
	 *
	 * @return  array  The span width layout columns
	 */
	function genWidth($layout, $numpos)
	{
		$cminspan = $this->minspan[$layout];
		$total = $cminspan * $numpos;

		if ($total < $this->maxgrid) {
			return $this->fitWidth($numpos);
		} else {
			$result = array();
			$rows = ceil($total / $this->maxgrid);
			$cols = ceil($numpos / $rows);

			for ($i = 0; $i < $rows - 1; $i++) {
				$result = array_merge($result, $this->fitWidth($cols));
				$numpos -= $cols;
			}

			$result = array_merge($result, $this->fitWidth($numpos));
		}

		return $result;
	}
}
core/t3.php000060400000036450152455303040006540 0ustar00<?php
/**
 *------------------------------------------------------------------------------
 * @package       T3 Framework for Joomla!
 *------------------------------------------------------------------------------
 * @copyright     Copyright (C) 2004-2013 JoomlArt.com. All Rights Reserved.
 * @license       GNU General Public License version 2 or later; see LICENSE.txt
 * @authors       JoomlArt, JoomlaBamboo, (contribute to this project at github
 *                & Google group to become co-author)
 * @Google group: https://groups.google.com/forum/#!forum/t3fw
 * @Link:         http://t3-framework.org
 *------------------------------------------------------------------------------
 */

use Joomla\CMS\Factory;
use Joomla\CMS\Uri\Uri;
use Joomla\Filesystem\Path;
use Joomla\Registry\Registry;
use Joomla\Filesystem\Folder;

// no direct access
defined('_JEXEC') or die('Restricted access');

/**
 * T3 class
 * Singleton class for T3
 * @package		T3
 */

class T3 {

	protected static $t3app = null;

	protected static $tmpl  = null;

	protected static $serviceRegistry;
	/**
	 * Import T3 Library
	 *
	 * @param string  $package  Object path that seperate by backslash (/)
	 *
	 * @return void
	 */
	public static function import($package){
		$path = T3_ADMIN_PATH . DIRECTORY_SEPARATOR . 'includes' . DIRECTORY_SEPARATOR . strtolower($package) . '.php';
		if (file_exists($path)) {
			include_once $path;
		} else {
			trigger_error('T3::import not found object: ' . $package, E_USER_ERROR);
		}
	}

	/**
	 * Register class with Joomla Loader. Override joomla core if $import_key avaiable
	 *
	 * @return void
	 */
	public static function register ($class, $path, $import_key = null) {
		if (!empty($import_key)) jimport($import_key);
		JLoader::register ($class, $path);
	}

	public static function registerHtmlClass () {
		// register T3Html class
		JLoader::registerPrefix('T3Html', T3_ADMIN_PATH . '/includes/joomla4/html');

		$serviceRegistry = Factory::getContainer()->get(\Joomla\CMS\HTML\Registry::class);
		$serviceRegistry->register('behavior', T3HtmlBehavior::class, true);
		$serviceRegistry->register('bootstrap', T3HtmlBootstrap::class, true);
	}

	/**
	 * @param   object  $tpl  template object to initialize if needed
	 * @return  bool|null|T3Admin
	 */
	public static function getApp($tpl = null){
		if(empty(self::$t3app)){
			$japp = Factory::getApplication();
			self::$t3app = T3::isAdmin() ? self::getAdmin() : self::getSite($tpl);
		}

		return self::$t3app;
	}

	/**
	 * initialize T3
	 */
	public static function init ($xml) {
		$app       = Factory::getApplication();
		$input     = $app->input;
		// echo '<pre>';var_dump($xml->t3->base);echo '</pre>';
//		if ($xml->t3->base === null){echo '<pre>';var_dump($xml->t3->base);echo '</pre>';die('');}
		$coretheme = isset($xml->t3) && isset($xml->t3->base)
			? trim((string)$xml->t3->base) : 'base';

		// check coretheme in media/t3/themes folder
		// if not exists, use default base theme in T3
		if (!$coretheme){
			$coretheme = 'base';
		}

		foreach(array(T3_EX_BASE_PATH, T3_ADMIN_PATH) as $basedir){
			if(is_dir($basedir . '/' . $coretheme)){

				if(is_file($basedir . '/' . $coretheme . '/define.php')){
					include_once ($basedir . '/' . $coretheme . '/define.php');
				}

				break;
			}
		}

		if(!defined('T3')){
			// get ready for the t3 core base theme
			include_once (T3_CORE_BASE_PATH . '/define.php');
		}

		if(!defined('T3')){
			T3::error(JText::sprintf('T3_MSG_FAILED_INIT_BASE', $coretheme));
			exit;
		}

		define ('T3_TEMPLATE', (String)$xml->tplname);
		define ('T3_TEMPLATE_URL', Uri::root(true).'/templates/'.T3_TEMPLATE);
		define ('T3_TEMPLATE_PATH', str_replace ('\\', '/', JPATH_ROOT) . '/templates/' . T3_TEMPLATE);
		define ('T3_TEMPLATE_REL', 'templates/' . T3_TEMPLATE);

		define ('T3_LOCAL_URL', T3_TEMPLATE_URL . '/' . T3_LOCAL_DIR);
		define ('T3_LOCAL_PATH', T3_TEMPLATE_PATH . '/' . T3_LOCAL_DIR);
		define ('T3_LOCAL_REL', T3_TEMPLATE_REL . '/' . T3_LOCAL_DIR);

		if ($input->getCmd('themer', 0)){
			define ('T3_THEMER', 1);
		}

		if (!T3::isAdmin()) {
			$params = $app->getTemplate(true)->params;
			define ('T3_DEV_FOLDER', $params->get ('t3-assets', 't3-assets') . '/dev');
			define ('T3_DEV_MODE', $params->get ('devmode', 0));
		} else {
			$params = self::getTemplate()->params;
			define ('T3_DEV_FOLDER', $params->get ('t3-assets', 't3-assets') . '/dev');
		}
		if (!is_dir(JPATH_ROOT.'/'.T3_DEV_FOLDER)) {
			Folder::create(JPATH_ROOT.'/'.T3_DEV_FOLDER);
		}

		if($input->getCmd('t3lock', '')){
			Factory::getSession()->set('T3.t3lock', $input->getCmd('t3lock', ''));
			$input->set('t3lock', null);
		}

		// load core library
		T3::import ('core/path');
		T3::import ('core/t3j');

		if (1 || !T3::isAdmin()) {
			if(version_compare(JVERSION, '3.8', 'ge')){
				// override core joomla class
				// JViewLegacy
				/*
		        T3::register('JViewLegacy',   T3_ADMIN_PATH . '/includes/joomla4/HtmlView.php');
				// JModuleHelper
		        T3::register('JModuleHelper',   T3_ADMIN_PATH . '/includes/joomla4/ModuleHelper.php');
				// JPagination
		        T3::register('JPagination',   T3_ADMIN_PATH . '/includes/joomla4/Pagination.php');
		        // Register T3 Layout File to put a t3 base layer for layout files
		        T3::register('JLayoutFile',   T3_ADMIN_PATH . '/includes/joomla4/FileLayout.php');
		        */

				// overwrite original Joomla
				$loader = require JPATH_LIBRARIES . '/vendor/autoload.php';
				// update class maps
				$classMap = $loader->getClassMap();
				$classMap['Joomla\CMS\Layout\FileLayout'] = T3_ADMIN_PATH . '/includes/joomla4/FileLayout.php';
				$classMap['Joomla\CMS\Helper\ModuleHelper'] = T3_ADMIN_PATH . '/includes/joomla4/ModuleHelper.php';
				$classMap['Joomla\CMS\MVC\View\HtmlView'] = T3_ADMIN_PATH . '/includes/joomla4/HtmlView.php';
				$classMap['Joomla\CMS\Pagination\Pagination'] = T3_ADMIN_PATH . '/includes/joomla4/Pagination.php';
				$loader->addClassMap($classMap);

			} else if(version_compare(JVERSION, '3.0', 'ge')){
				// override core joomla class
				// JViewLegacy
		        T3::register('JViewLegacy',   T3_ADMIN_PATH . '/includes/joomla30/viewlegacy.php');
		        T3::register('JViewHtml',   T3_ADMIN_PATH . '/includes/joomla30/viewhtml.php');
						// JModuleHelper
		        T3::register('JModuleHelper',   T3_ADMIN_PATH . '/includes/joomla30/modulehelper.php');
						// JPagination
		        T3::register('JPagination',   T3_ADMIN_PATH . '/includes/joomla30/pagination.php');
		        // Register T3 Layout File to put a t3 base layer for layout files
		        T3::register('JLayoutFile',   T3_ADMIN_PATH . '/includes/joomla30/layoutfile.php');
			} else {
				// override core joomla class
				// JView
				T3::register('JView',       T3_ADMIN_PATH . '/includes/joomla25/view.php', 'joomla.application.component.view');
				// JModuleHelper
				T3::register('JModuleHelper',       T3_ADMIN_PATH . '/includes/joomla25/modulehelper.php', 'joomla.application.module.helper');
				// JPagination
				T3::register('JPagination',       T3_ADMIN_PATH . '/includes/joomla25/pagination.php', 'joomla.html.pagination');

				//register layout
				T3::register('JLayout',       T3_ADMIN_PATH . '/includes/joomla25/layout/layout.php');
				T3::register('JLayoutBase',   T3_ADMIN_PATH . '/includes/joomla25/layout/base.php');
				T3::register('JLayoutFile',   T3_ADMIN_PATH . '/includes/joomla25/layout/file.php');
				T3::register('JLayoutHelper', T3_ADMIN_PATH . '/includes/joomla25/layout/helper.php');
				T3::register('JHtmlBootstrap', T3_ADMIN_PATH . '/includes/joomla25/html/bootstrap.php');
				T3::register('JHtmlBehavior', T3_ADMIN_PATH . '/includes/joomla25/html/behavior.php');
		        T3::register('JHtmlString', T3_ADMIN_PATH . '/includes/joomla25/html/string.php');
		        T3::register('JHtmlJquery', T3_ADMIN_PATH . '/includes/joomla25/html/jquery.php');

		        // load j25 compat language
		        Factory::getLanguage()->load('plg_system_t3.j25.compat', JPATH_ADMINISTRATOR);
			}

			// import renderer
			T3::import('renderer/pageclass');
			T3::import('renderer/megamenu');
			T3::import('renderer/t3bootstrap');
		} else {
		}

		if(version_compare(JVERSION, '4', 'ge')) T3::registerHtmlClass();

		// capture for tm=1 => show theme magic
		if ($input->getCmd('tm') == 1) {
			$input->set('t3action', 'theme');
			$input->set('t3task', 'thememagic');
		}
	}

	public static function checkAction () {
		// excute action by T3
		if ($action = Factory::getApplication()->input->getCmd ('t3action')) {
			T3::import ('core/action');
			T3Action::run ($action);
		}
	}

	/**
	 * check for t3ajax action
	 */
	public static function checkAjax () {
		// excute action by T3
		$input = Factory::getApplication()->input;

		if ($input->getCmd ('t3ajax')) {
			T3::import('core/ajax');
			T3::import('renderer/t3ajax');

			//T3Ajax::processAjaxRule();

			Factory::getApplication()->getTemplate(true)->params->set('mainlayout', 'ajax.' . $input->getCmd('f', 'html'));
		}
	}

	/**
	 * get T3Admin object
	 * @return T3Admin
	 */
	public static function getAdmin(){
		T3::import ('core/admin');
		return new T3Admin();
	}

	/**
	 * get T3Template object for frontend
	 * @param $tpl
	 * @return bool
	 */
	public static function getSite($tpl){
		//when on site, the JDocumentHTML parameter must be pass
		if(empty($tpl)){
			return false;
		}

		$type = 'Template'. Factory::getApplication()->input->getCmd ('t3tp', '');
		T3::import ('core/' . $type);

		// create global t3 template object
		$class = 'T3' . $type;
		return new $class($tpl);
	}

	/**
	 * @param $msg
	 * @param int $code
	 * @throws Exception
	 */
	public static function error($msg, $code = 500){
		if (JError::$legacy) {
			JError::setErrorHandling(E_ERROR, 'die');
			JError::raiseError($code, $msg);

			exit;
		} else {
			throw new Exception($msg, $code);
		}
	}

	/**
	 * detect function to check a current template is T3 template
	 * @return bool|SimpleXMLElement
	 */
	public static function detect(){
		static $t3;

		if (!isset($t3)) {
			$t3 = false; // set false
			$app = Factory::getApplication();
			$input = $app->input;

			// get template name
			$tplname = '';

			if($input->getCmd ('t3action') && $input->getInt('styleid', '')) {

				$tplname = self::getTemplate(true);

			} elseif (T3::isAdmin()) {
				// if not login, do nothing
				$user = Factory::getUser();
				if (!$user->id){
					return false;
				}
				$task = $input->getCmd('task') !== null ? $input->getCmd('task') : '';
				if($input->getCmd('option') == 'com_templates' &&
					(preg_match('/style\./', $task) ||
						$input->getCmd('view') == 'style' ||
						$input->getCmd('view') == 'template')){

					$db    = Factory::getDBO();
					$query = $db->getQuery(true);
					$id    = $input->getInt('id');

					//when in POST the view parameter does not set
					if ($input->getCmd('view') == 'template') {
						$query
							->select('element')
							->from('#__extensions')
							->where('extension_id='.(int)$id . ' AND type=' . $db->quote('template'));
					} else {
						$query
							->select('template')
							->from('#__template_styles')
							->where('id='.(int)$id);
					}

					$db->setQuery($query);
					$tplname = $db->loadResult();
				}

			} else {
				$tplname = $app->getTemplate(false);
			}

			if ($tplname) {
					// parse xml
				$filePath = Path::clean(JPATH_ROOT.'/templates/'.$tplname.'/templateDetails.xml');
				if (is_file ($filePath)) {
					$xml = $xml = simplexml_load_file($filePath);
					// check t3 or group=t3 (compatible with previous definition)
					if (isset($xml->t3) || (isset($xml->group) && strtolower($xml->group) == 't3')) {
						$xml->tplname = $tplname;
						$t3 = $xml;
					}
				}
			}
		}
		return $t3;
	}

	/**
	 * get default template style
	 */
	public static function getDefaultTemplate($name = false){
		static $template;

		if (!isset($template)) {

			$db = Factory::getDbo();
			$query = $db->getQuery(true);
			$query
				->select('id, home, template, s.params')
				->from('#__template_styles as s')
				->where('s.client_id = 0')
				->where('s.home = \'1\'')
				->where('e.enabled = 1')
				->leftJoin('#__extensions as e ON e.element=s.template AND e.type='.$db->quote('template').' AND e.client_id=s.client_id');

			$db->setQuery($query);
			$result = $db->loadObject();

			$template = !empty($result) ? $result : false;
		}

		if($name && $template){
			return $template->template;
		}

		return $template;
	}

	/**
	 * get the template object or template name
	 * @param bool $name
	 * @return mixed template object or template name
	 */
	public static function getTemplate($name = false)
	{
		if(!isset(self::$tmpl) || !self::$tmpl){

			$app   = Factory::getApplication();
			$input = $app->input;
			$id    = $input->getInt('styleid', $input->getInt('id'));

			if($id){
				$db    = Factory::getDbo();
				$query = $db->getQuery(true);
				$query
					->select('template, params')
					->from('#__template_styles')
					->where('client_id = 0');

				if(T3::isAdmin() && $input->get('view') == 'template' && defined('T3_TEMPLATE')){
					$query->where('template='. $db->quote(T3_TEMPLATE));
				} else {
					$query->where('id='. $id);
				}

				$db->setQuery($query);
				$template = $db->loadObject();

				if ($template) {
					$registry = new Registry();
					$registry->loadString($template->params);
					$template->params = $registry;
				}

				self::$tmpl = $template;
			}
		}

		if($name && self::$tmpl){
			return self::$tmpl->template;
		}

		return self::$tmpl;
	}

	/**
	 * set caching template and its parameters
	 * @param string $name
	 * @param string $params
	 */
	public static function setTemplate($name = '', $params = ''){
		if(!self::$tmpl){
			self::$tmpl = new stdClass;
		}

		if($name && $params){
			self::$tmpl->template = $name;
			self::$tmpl->params = $params;
		}
	}

	/**
	 * get template parameters
	 * @return Registry()
	 */
	public static function getTplParams()
	{
		$tmpl = self::getTemplate();
		return $tmpl ? $tmpl->params : new Registry(); //empty registry ? or throw error
	}

	/**
	 * check if current page is homepage
	 */
	public static function isHome(){
		$active = Factory::getApplication()->getMenu()->getActive();
		return (!$active || $active->home);
	}

	public static function isAdmin() {
		return Factory::getApplication()->isClient('administrator');
	}
	/**
	 * fix ja back link
	 * @param $buffer
	 * @return mixed
	 */
	public static function fixJALink($buffer){

		if(!self::isHome()){
			$buffer = preg_replace_callback('@<a[^>]*>JoomlArt.com</a>@i', array('T3', 'removeBacklink'), $buffer);
		}

		return $buffer;
	}

	/**
	 * fix t3-framework.org back link
	 * @param $buffer
	 * @return mixed
	 */
	public static function fixT3Link($buffer){
		if(!self::isHome()){
			$buffer = preg_replace_callback('@<a[^>]*>([^>]*)>T3 Framework</strong></a>@mi', array('T3', 'removeBacklink'), $buffer);
		}

		return $buffer;
	}

	/**
	 * check nofollow attribute
	 * @param $match
	 * @return mixed
	 */
	public static function removeBacklink($match){

		if($match && isset($match[0]) && strpos($match[0], 'rel="nofollow"') === false){
			$match[0] = str_replace('<a ', '<a rel="nofollow" ', $match[0]);
		}

		return $match[0];
	}

	// Create alias class for original call in $filepath, then overload the class
	public static function makeAlias($filepath, $originClassName, $aliasClassName) {
		if (!is_file($filepath)) return false;
		$code = file_get_contents($filepath);
		$code = str_replace('class ' . $originClassName, 'class ' . $aliasClassName, $code);
		eval('?>'. $code);
		return true;
	}

}
core/less.php000060400000055616152455303040007165 0ustar00<?php
/**
 *------------------------------------------------------------------------------
 * @package       T3 Framework for Joomla!
 *------------------------------------------------------------------------------
 * @copyright     Copyright (C) 2004-2013 JoomlArt.com. All Rights Reserved.
 * @license       GNU General Public License version 2 or later; see LICENSE.txt
 * @authors       JoomlArt, JoomlaBamboo, (contribute to this project at github
 *                & Google group to become co-author)
 * @Google group: https://groups.google.com/forum/#!forum/t3fw
 * @Link:         http://t3-framework.org
 *------------------------------------------------------------------------------
 */

// No direct access
defined('_JEXEC') or die();

jimport('joomla.filesystem.file');
jimport('joomla.filesystem.folder');

T3::import('core/path');
T3::import('lessphp/' . T3_BASE_LESS_COMPILER);

/**
 * T3Less class compile less
 *
 * @package T3
 */
class T3Less
{
	static $kfilepath    = 'less-file-path';
	static $kvarsep      = 'less-content-separator';
	static $krtlsep      = 'rtl-less-content';
	static $rsplitbegin  = '@^\s*\#';
	static $rsplitend    = '[^\s]*?\s*{\s*[\r\n]*\s*content:\s*"([^"]*)";\s*[\r\n]*\s*}[\r\n]*@im';
	static $rswitchrtl   = '@/less/(themes/[^/]*/)?@';
	static $rcomment     = '@/\*[^*]*\*+([^/][^*]*\*+)*/@';
	static $rspace       = '@[\r?\n]{2,}@';
	static $rimport      = '@^\s*\@import\s+"([^"]*)"\s*;@im';
	static $rimportvars  = '@^\s*\@import\s+".*(variables-custom|variables|vars|mixins)\.less"\s*;@im';

	static $_path = null;

	public static function requirement(){
		static $setup;

		if(isset($setup)){

			@ini_set('pcre.backtrack_limit', '2M');

			$mem_limit = @ini_get('memory_limit');
			if (preg_match('@^(\d+)(.)$@', $mem_limit, $matches)) {
				if ($matches[2] == 'M') {
					$mem_limit = $matches[1] * 1024 * 1024;
				} else if ($matches[2] == 'K') {
					$mem_limit = $matches[1] * 1024;
				}
			}

			if((int)$mem_limit < 128 * 1024 * 1024) {
				@ini_set('memory_limit', '128M');
			}

			$setup = true;
		}
	}

	/**
	 * Compile LESS to CSS
	 * @param   $path   the file path of less file
	 * @return  string  the css compiled content
	 */
	public static function getCss($path)
	{
		//build vars once
		self::buildVarsOnce();

		// get vars last-modified
		$vars_lm = self::getState('vars_last_modified', 0);

		// less file last-modified
		$filepath = JPATH_ROOT . '/' . $path;
		$less_lm  = filemtime($filepath);

		// cache key
		$key   = md5($vars_lm . ':' . $less_lm . ':' . $path);
		$group = 't3';
		$cache = JCache::getInstance('output', array(
			'lifetime' => 1440
		));

		// get cache
		$data  = $cache->get($key, $group);
		if ($data) {
			return $data;
		}

		// not cached, build & store it
		$data = self::compileCss($path) . "\n";
		$cache->store($data, $key, $group);

		return $data;
	}

	/**
	 * Compile LESS to CSS
	 * @param   $path   the less file to compile
	 * @return  string  url to css file
	 */
	public static function buildCss ($path, $return = false) {
		$rtpl_check		= '@'.preg_quote(T3_TEMPLATE_REL, '@') . '/@i';
		$rtpl_less_check		= '@'.preg_quote(T3_TEMPLATE_REL, '@') . '/less/@i';

		$app     = JFactory::getApplication();
		$doc		 = JFactory::getDocument();
		$theme   = $app->getUserState('current_theme', '');
		$is_rtl      = ($app->getUserState('current_direction') == 'rtl');
		if(array_key_exists("HTTP_USER_AGENT", $_SERVER)){
			$_SERVER['HTTP_USER_AGENT'] = "";
		}
		$ie8 = preg_match('/MSIE 8\./', $_SERVER['HTTP_USER_AGENT']);

		// get css cached file
		$subdir  = ($is_rtl ? 'rtl/' : '') . ($theme ? $theme . '/' : '');
		$cssdir  = T3_DEV_FOLDER . ($ie8 ? '/ie8' : '') . '/' . $subdir;
		$cssfile = $cssdir . str_replace('/', '.', $path) . '.css';

		// modified time
		$less_lm = @filemtime (JPATH_ROOT . '/' . $path);
		$css_lm = @filemtime ($cssfile);
		$vars_lm = self::getState('vars_last_modified', 0);

		$list = self::parse($path);

		if (empty ($list)) return false;

		// prepare output list
		$split = !$ie8 && !$return && preg_match ($rtpl_less_check, $path) && !preg_match ('/bootstrap/', $path);
		$output_files = array();

		foreach ($list as $f => $import) {
			if ($import) {
				$css = $cssdir . str_replace('/', '.', $f) . '.css';
				if ($split) $output_files[] = $css;
				$less_lm = max ($less_lm, @filemtime(JPATH_ROOT . '/' . $f));
				$css_lm = max ($css_lm, @filemtime(JPATH_ROOT . '/' . $css));
			}
		}

		// itself
		$output_files [] = $cssfile;

		// check modified
		$rebuild = $vars_lm > $css_lm || $less_lm > $css_lm;
		if ($rebuild) {
			if ($split) {
				self::compileCss($path, $cssfile, true, $list);
			} else {
				self::compileCss($path, $cssfile, false, $list);
			}
		}

		if (!$return) {
			// add css
			foreach ($output_files as $css) {
				$doc->addStylesheet($css);
			}
		} else {
			return $cssfile;
		}
	}

	public static function relativePath($topath, $path, $default = null){
		$rel = T3Path::relativePath($topath, $path);
		return $rel ? $rel . '/' : './';
	}

	/**
	 * @param   string  $path    file path of less file to compile
	 * @param   string  $topath  file path of output css file
	 * @return  bool|mixed       compile result or the css compiled content
	 */
	public static function compileCss($path, $topath = '', $split = false, $list = null) {
		$fromdir = dirname($path);
		$app     = JFactory::getApplication();
		$is_rtl      = ($app->getUserState('current_direction') == 'rtl');

		if (empty ($list)) $list = self::parse($path);
		if (empty ($list)) {
			return false;
		}
		// join $list
		$content = '';
		$importdirs = array();
		$todir = $topath ? dirname($topath) : $fromdir;

		if (!is_dir(JPATH_ROOT . '/' . $todir)) {
			JFolder::create(JPATH_ROOT . '/' . $todir);
		}
		$importdirs[JPATH_ROOT . '/' . $fromdir] = './';
		foreach ($list as $f => $import) {
			if ($import) {
				$importdirs[JPATH_ROOT . '/' . dirname($f)] = self::relativePath($fromdir, dirname($f));
				$content .= "\n#".self::$kfilepath."{content: \"{$f}\";}\n";
				// $content .= "@import \"$import\";\n\n";
				if (is_file(JPATH_ROOT . '/' . $f)) {
					$less_content = file_get_contents(JPATH_ROOT . '/' . $f);
					// remove vars/mixins for template & t3 less
					if (preg_match ('@'.preg_quote(T3_TEMPLATE_REL, '@') . '/@i', $f) || preg_match ('@'.preg_quote(T3_REL, '@') . '/@i', $f)) {
						$less_content = preg_replace(self::$rimportvars, '', $less_content);
					}
					self::$_path = T3Path::relativePath($fromdir, dirname($f)) . '/';
					$less_content = preg_replace_callback(self::$rimport, array('T3Less', 'cb_import_path'), $less_content);
					$content .= $less_content;
				}
			} else {
				$content .= "\n#".self::$kfilepath."{content: \"{$path}\";}\n";
				$content .= $f . "\n\n";
			}
		}

		// get vars
		$vars_files = explode('|', self::getVars('urls'));

		// build source
		$source = '';
		// build import vars
		foreach ($vars_files as $var) {
			$var_file = T3Path::relativePath($fromdir, $var);
			$source .= "@import \"" . $var_file . "\";\n";
		}
		
		// less content
		$source .= "\n#" . self::$kvarsep . "{content: \"separator\";}\n" . $content;

		// call Less to compile,
		// temporary compile into source path, then update url to destination later
		try {
			$output = T3LessCompiler::compile($source, $importdirs);
		} catch (Exception $e) {	
			// echo 'Caught exception: ',  $e->getMessage(), "\n";
			throw new Exception($path . "<br />\n" . $e->getMessage());
		}

		// process content
		//use cssjanus to transform the content
		if ($is_rtl) {
			$output = preg_split(self::$rsplitbegin . self::$krtlsep . self::$rsplitend, $output, -1, PREG_SPLIT_DELIM_CAPTURE);
			$rtlcontent = isset($output[2]) ? $output[2] : false;
			$output = $output[0];

			T3::import('jacssjanus/ja.cssjanus');
			$output = JACSSJanus::transform($output, true);

			// join with rtl content
			if($rtlcontent){
				$output = $output . "\n" . $rtlcontent;
			}
		}
		// skip duplicate clearfix
		$arr = preg_split(self::$rsplitbegin . self::$kvarsep . self::$rsplitend, $output, 2);
		if (preg_match ('/bootstrap.less/', $path)) {
			$output = implode ("\n", $arr);
		} else {
			$output = count($arr) > 1 ? $arr[1] : $arr[0];
		}

		//remove comments and clean up
		$output = preg_replace(self::$rcomment, '', $output);
		$output = preg_replace(self::$rspace, "\n\n", $output);

		// update url for output
		$file_contents = self::updateUrl ($output, $path, $todir, $split);

		// split if needed
		if ($split) {
			if(!empty($file_contents)){
				//output the file to content and add to document
				foreach ($file_contents as $file => $content) {
					if ($file) {
						$content = trim($content);
						$filename = str_replace('/', '.', $file) . '.css';
						JFile::write(JPATH_ROOT . '/' . $todir . '/' . $filename, $content);
					}
				}
			}
		} else {
			if ($topath) {
				JFile::write(JPATH_ROOT . '/' . $topath, $file_contents);
			} else {
				return $output;
			}
		}
		// write to path
		return true;
	}

	/**
	 * Update url for background, import according to output path
	 *
	 * @param $css the compiled css
	 * @param $path the source less path
	 * @param $output_dir destination of css file
	 * @param $split split into small files or not
	 * @return if $split then return an array of sub file, else return the whole css
	 */
	public static function updateUrl ($css, $path, $output_dir, $split) {
		//update path and store to files
		$split_contents = preg_split(self::$rsplitbegin . self::$kfilepath . self::$rsplitend, $css, -1, PREG_SPLIT_DELIM_CAPTURE);
		$file_contents  = array();
		$file       		= $path;
		$isfile         = false;
		$output         = '';

		// split
		foreach ($split_contents as $chunk) {
			if ($isfile) {
				$isfile  = false;
				$file = $chunk;
			} else {
				$content = T3Path::updateUrl (trim($chunk), T3Path::relativePath($output_dir, dirname($file)));
				$file_contents[$file] = (isset($file_contents[$file]) ? $file_contents[$file] : '') . "\n" . $content . "\n\n";
				$output .= $content . "\n";
				$isfile = true;
			}
		}

		return $split ? $file_contents : trim($output);
	}

	/**
	 * Get less variables
	 * @return mixed
	 */
	public static function getVars($name = '')
	{
		return self::getState('vars_' . ($name ? $name.'_' : '') . 'content');
	}

	/**
	 * get value from cache
	 */
	public static function getState ($key, $default = null) {
		$app = JFactory::getApplication();
		$keysfx = $app->getUserState('current_key_sufix');
		// cache key
		$ckey   = $key.$keysfx;
		$group = 't3';
		$cache = JCache::getInstance('output', array(
			'lifetime' => 25200,
			'caching'	=> true,
			'cachebase' => JPATH_ROOT.'/'.T3_DEV_FOLDER
		));

		// get cache
		$data  = $cache->get($ckey, $group);
		return $data===false ? $app->getUserState($ckey, $default) : $data;
	}

	/**
	 * store value to cache
	 */
	public static function setState ($key, $value) {
		$app = JFactory::getApplication();
		$keysfx = $app->getUserState('current_key_sufix');
		// cache key
		$ckey   = $key.$keysfx;
		$group = 't3';
		$cache = JCache::getInstance('output', array(
			'lifetime' => 25200,
			'caching'	=> true,
			'cachebase' => JPATH_ROOT.'/'.T3_DEV_FOLDER
		));
		if (!$cache->store($value, $ckey, $group)) {
			$app->setUserState($ckey, $value);
		}
	}

	/**
	 * @param  string  $theme  template theme
	 * @param  string  $dir    direction (ltr or rtl)
	 * @return mixed
	 */
	public static function buildVars($theme = null, $dir = null)
	{
		$app  = JFactory::getApplication();
		$params = null;
		if (T3::isAdmin()) {
			$params = $app->getUserState ('current_template_params');
		} else {
			$tpl   =  $app->getTemplate(true);
			$params = $tpl->params;
		}
		if (!$params) {
			T3::error(JText::_('T3_MSG_CANNOT_DETECT_TEMPLATE'));
			exit;
		}

		$responsive = $params->get('responsive', 1);
		// theme style
		if ($theme === null) {
			$theme = $params->get('theme');
		}
		// detect RTL
		if ($dir === null) {
			$doc = JFactory::getDocument();
			$dir = $doc->direction;
		}
		$app->setUserState('current_theme', $theme);
		$app->setUserState('current_direction', $dir);
		$app->setUserState('current_key_sufix', "_{$theme}_{$dir}");

		$path = T3_TEMPLATE_PATH . '/less/vars.less';
		if(!is_file($path)){
			T3::error(JText::_('T3_MSG_LESS_NOT_VALID'));
			exit;
		}

		// force re-build less if switch responsive mode and get last modified time
		if ($responsive !== self::getState('current_responsive')) {
			self::setState('current_responsive', $responsive);
			$last_modified = time();
			touch($path, $last_modified);
		} else {
			$last_modified = filemtime($path);
		}

		$vars_content          = file_get_contents($path);
		$vars_urls = array();

		preg_match_all('#^\s*@import\s+"([^"]*)"#im', $vars_content, $matches);
		if (count($matches[0])) {
			foreach ($matches[1] as $url) {
				$path = T3Path::cleanPath(T3_TEMPLATE_PATH . '/less/' . $url);
				if (file_exists($path)) {
					$last_modified = max($last_modified, filemtime($path));
					$vars_urls[] = T3Path::cleanPath(T3_TEMPLATE_REL . '/less/' . $url);
				}
			}
		}

		// add override variables
		$paths = array();
		if ($theme) {
			$paths[] = T3_TEMPLATE_REL . "/less/themes/{$theme}/variables.less";
			$paths[] = T3_TEMPLATE_REL . "/less/themes/{$theme}/variables-custom.less";
		}
		if ($dir == 'rtl') {
			$paths[] = T3_TEMPLATE_REL . "/less/rtl/variables.less";
			if ($theme) $paths[] = T3_TEMPLATE_REL . "/less/rtl/themes/{$theme}/variables.less";
		}
		if (!defined('T3_LOCAL_DISABLED')) {
			$paths[] = T3_LOCAL_REL . "/less/variables.less";
			if ($theme) {
				$paths[] = T3_LOCAL_REL . "/less/themes/{$theme}/variables.less";
				$paths[] = T3_LOCAL_REL . "/less/themes/{$theme}/variables-custom.less";
			}
			if ($dir == 'rtl') {
				$paths[] = T3_LOCAL_REL . "/less/rtl/variables.less";
				if ($theme) $paths[] = T3_LOCAL_REL . "/less/rtl/themes/{$theme}/variables.less";
			}
		}
		if (!$responsive) {
			$paths[] = T3_REL . '/less/non-responsive-variables.less';
			$paths[] = T3_TEMPLATE_REL . '/less/non-responsive-variables.less';
		}

		foreach ($paths as $file) {
			if (is_file(JPATH_ROOT . '/' . $file)) {
				$last_modified = max($last_modified, filemtime(JPATH_ROOT . '/' . $file));
				$vars_urls[] = $file;
			}
		}

		if (self::getState('vars_last_modified') != $last_modified) {
			self::setState('vars_last_modified', $last_modified);
		}
		self::setState('vars_urls_content', implode('|', $vars_urls));
	}

	/**
	 * Build vars only one per request
	 */
	public static function buildVarsOnce(){
		// build less vars, once only
		static $vars_built = false;
		if (!$vars_built) {
			self::buildVars();
			$vars_built = true;
		}
	}

	/**
	 * Wrapper function to add a stylesheet to html document
	 * @param  string  $lesspath  the less file to add
	 */
	public static function addStylesheet($lesspath)
	{
		//build vars once
		self::buildVarsOnce();

		$app   = JFactory::getApplication();
		$doc   = JFactory::getDocument();
		$tpl   = $app->getTemplate(true);
		$theme = $tpl->params->get('theme');

		if (defined('T3_THEMER') && $tpl->params->get('themermode', 1)) {
			// in Themer mode, using js to parse less, so we will use 'text/less' content type
			$doc->addStylesheet(JURI::base(true) . '/' . T3Path::cleanPath($lesspath), 'text/less');

			// just to make sure this function is call once
			if(!defined('T3_LESS_JS')){
				// Add lessjs to process lesscss
				$doc->addScript(T3_URL . '/js/less.js?v=2');

				if($doc->direction == 'rtl'){
					$doc->addScript(T3_URL . '/js/cssjanus.js');
				}

				define('T3_LESS_JS', 1);
			}
		} else {
			self::buildCss(T3Path::cleanPath($lesspath));
		}
	}


	public static function getOutputCssPath ($lessPath, $theme = '', $is_rtl = false) {
		$cssPath = '';
		$extraPath = '';
		$extraPath .= $is_rtl ? 'rtl/' : '';
		$extraPath .= $theme ? ($is_rtl ? '' : 'themes/') . $theme . '/' : '';

		if (preg_match ('/(^|\/)less\//i', $lessPath)) {
			$cssPath = preg_replace ('/(^|\/)less\//i', '\1css/' . $extraPath, $lessPath);
		} else {
			$cssPath = dirname ($lessPath) . '/' . $extraPath . basename($lessPath);
		}
		$cssPath = str_replace('.less', '.css', $cssPath);
		return $cssPath;
	}


	/**
	 * Compile LESS to CSS for a specific theme or all themes
	 * @param  string  $theme  the specific theme
	 */
	public static function compileAll($theme = null)
	{
		$params   = T3::getTplParams();
		JFactory::getApplication()->setUserState ('current_template_params', $params);

		// get files need to compile
		$files = array();
		$toPath  = T3Path::getLocalPath('', true);

		// t3 core plugin files
		$t3files  = array('less/frontend-edit.less', 'less/legacy-grid.less', 'less/legacy-navigation.less', 'less/megamenu.less', 'less/off-canvas.less');

		// all less file in the template folder
		$lessFiles    = JFolder::files(T3_TEMPLATE_PATH, '.less', true, true, array('rtl', 'themes', '.svn', 'CVS', '.DS_Store', '__MACOSX'));

		$relLessFiles = array();

		$importedFiles = array();

		foreach ($lessFiles as $file) {
			$file = str_replace('\\', '/', $file);
			$lessContent = file_get_contents($file);
			$rel = ltrim(str_replace(T3_TEMPLATE_PATH, '', $file), '/');
			$reldir = dirname ($rel);
			$ignore = true;
			if (preg_match_all('#^\s*@import\s+"([^"]*)"#im', $lessContent, $matches)) {
				foreach ($matches[1] as $if) {
					$if = T3Path::cleanPath($reldir . '/' . $if);
					if (!in_array($if, $importedFiles)) $importedFiles[] = $if;
					// check if this file import anything in main less folder. if yes, put it in the compile list
					if (preg_match ('@^less/@', $if)) $ignore = false;
				}
			}
			if (!$ignore) $relLessFiles[] = $rel;
		}

		$lessFiles = $relLessFiles;

		// ignore files which are imported in other file
		foreach ($lessFiles as $f) {
			if (!in_array($f, $importedFiles) && !preg_match ('@^less/(themes|rtl)/@i', $f)) {
				$files[] = $f;
			}
		}

		//build t3files
		foreach ($t3files as $key => $file) {
			if(in_array($file, $files)){
				unset($t3files[$key]);
			}
		}

		// build default
		if (!$theme || $theme == 'default') {
			self::buildVars('', 'ltr');

			// compile all less files in template "less" folder
			foreach ($files as $lessPath) {
				$cssPath = self::getOutputCssPath($lessPath);
				self::compileCss(T3_TEMPLATE_REL . '/' . $lessPath, $toPath . $cssPath);
			}

			// if the template not overwrite the t3 core, we will compile those missing files
			if(!empty($t3files)){
				foreach ($t3files as $lessPath) {
					$cssPath = self::getOutputCssPath($lessPath);
					self::compileCss(T3_REL . '/' . $lessPath, $toPath . $cssPath);
				}
			}
		}

		// build themes
		if (!$theme) {
			// get themes
			$themes = JFolder::folders(T3_TEMPLATE_PATH . '/less/themes');
		} else {
			$themes = $theme != 'default' ? (array)($theme) : array();
		}

		if (is_array($themes)) {
			foreach ($themes as $t) {
				self::buildVars($t, 'ltr');

				// compile
				foreach ($files as $lessPath) {
					$cssPath = self::getOutputCssPath($lessPath, $t);
					self::compileCss(T3_TEMPLATE_REL . '/' . $lessPath, $toPath . $cssPath);
				}

				if(!empty($t3files)){
					foreach ($t3files as $lessPath) {
						$cssPath = self::getOutputCssPath($lessPath, $t);
						self::compileCss(T3_REL . '/' . $lessPath, $toPath . $cssPath);
					}
				}
			}
		}

		// compile rtl css
		if($params && $params->get('build_rtl', 0)){
			// compile default
			if (!$theme || $theme == 'default') {
				self::buildVars('', 'rtl');

				// compile
				foreach ($files as $lessPath) {
					$cssPath = self::getOutputCssPath($lessPath, '', true);
					self::compileCss(T3_TEMPLATE_REL . '/' . $lessPath, $toPath . $cssPath);
				}

				if(!empty($t3files)){
					foreach ($t3files as $lessPath) {
						$cssPath = self::getOutputCssPath($lessPath, '', true);
						self::compileCss(T3_REL . '/' . $lessPath, $toPath . $cssPath);
					}
				}
			}

			if (is_array($themes)) {
				// rtl for themes
				foreach ($themes as $t) {
					self::buildVars($t, 'rtl');

					// compile
					foreach ($files as $lessPath) {
						$cssPath = self::getOutputCssPath($lessPath, $t, true);
						self::compileCss(T3_TEMPLATE_REL . '/' . $lessPath, $toPath . $cssPath);
					}

					if(!empty($t3files)){
						foreach ($t3files as $lessPath) {
							$cssPath = self::getOutputCssPath($lessPath, $t, true);
							self::compileCss(T3_REL . '/' . $lessPath, $toPath . $cssPath);
						}
					}
				}
			}
		}
	}

	/**
	 * Parse a less file to get all its overrides before compile
	 * @param  string  $path the less file
	 */
	public static function parse($path) {
		$rtpl_check		= '@'.preg_quote(T3_TEMPLATE_REL, '@') . '/@i';
		$rtpl_less_check		= '@'.preg_quote(T3_TEMPLATE_REL, '@') . '/less/@i';

		$app    = JFactory::getApplication();
		$theme  = $app->getUserState('current_theme');
		$dir  = $app->getUserState('current_direction');
		$is_rtl = ($dir == 'rtl');

		$rel_path = preg_replace($rtpl_check, '', $path);
		$rel_dir = dirname($rel_path);
		// check path
		$realpath = realpath(JPATH_ROOT . '/' . $path);
		if (!is_file($realpath)) {
			return false;
		}

		// get file content
		$content = file_get_contents($realpath);

		//remove vars.less
		$content = preg_replace(self::$rimportvars, '', $content);

		// split into array, separated by the import
		$arr = preg_split(self::$rimport, $content, -1, PREG_SPLIT_DELIM_CAPTURE);
		$arr[] = basename($rel_path);
		$arr[] = '';

		$list = array();
		$rtl_list = array();
		$list[$path] = '';
		$import = false;

		foreach ($arr as $chunk) {
			if ($import) {
				$import = false;
				$import_url = T3Path::cleanPath(T3_TEMPLATE_REL . '/' . $rel_dir . '/' .$chunk);
				// if $url in less folder, get all its overrides
				if (preg_match ($rtpl_less_check, $import_url)) {
					$less_rel_url = preg_replace($rtpl_less_check, '', $import_url);
					$array = T3Path::getAllPath('less/' . $less_rel_url, true);
					if ($theme) {
						$array = array_merge($array, T3Path::getAllPath('less/themes/'.$theme.'/'.$less_rel_url, true));
					}

					foreach ($array as $f) {
						// add file in template only
						if (preg_match ($rtpl_check, $f)) {
							$list [$f] = T3Path::relativePath(dirname($path), $f);
						}
					}

					// rtl overrides
					if ($is_rtl) {
						$array = T3Path::getAllPath('less/rtl/'.$less_rel_url, true);
						if ($theme) {
							$array = array_merge($array, T3Path::getAllPath('less/rtl/themes/'.$theme.'/'.$less_rel_url, true));
						}

						foreach ($array as $f) {
							// add file in template only
							if (preg_match ($rtpl_check, $f)) {
								$rtl_list [$f] = T3Path::relativePath(dirname($path), $f);
							}
						}
					}
				} else {
					$list [$import_url] = T3Path::cleanPath($chunk);
					// rtl override
					if ($is_rtl) {
						$rtl_url = preg_replace ('/\/less\//', '/less/rtl/', $import_url);
						if (is_file(JPATH_ROOT.'/'.$rtl_url)) {
							$rtl_list [$rtl_url] = T3Path::relativePath(dirname($path), $rtl_url);
						}
					}
				}
			} else {
				$import = true;
				$list [$chunk] = false;
			}
		}

		// remove itself
		unset($list[$path]);

		// join rtl
		if ($is_rtl) {
			$list ["\n\n#" . self::$krtlsep . "{content: \"separator\";}\n\n"] = false;
			$list = array_merge($list, $rtl_list);
		}

		return $list;
	}

	public static	function cb_import_path ($match) {
		$f = $match[1];
		$newf = T3Path::cleanPath(self::$_path . $f);
		return str_replace($f, $newf, $match[0]);
	}
}
core/minify.php000060400000036062152455303040007504 0ustar00<?php
/** 
 *------------------------------------------------------------------------------
 * @package       T3 Framework for Joomla!
 *------------------------------------------------------------------------------
 * @copyright     Copyright (C) 2004-2013 JoomlArt.com. All Rights Reserved.
 * @license       GNU General Public License version 2 or later; see LICENSE.txt
 * @authors       JoomlArt, JoomlaBamboo, (contribute to this project at github 
 *                & Google group to become co-author)
 * @Google group: https://groups.google.com/forum/#!forum/t3fw
 * @Link:         http://t3-framework.org 
 *------------------------------------------------------------------------------
 */

// No direct access
defined('_JEXEC') or die();

jimport('joomla.filesystem.file');
jimport('joomla.filesystem.folder');

T3::import('core/path');

/**
 * T3Minify class provides extended template tools used for T3 framework
 *
 * @package T3
 */
class T3Minify
{
	/**
	 * Known Valid CSS Extension Types
	 * @var array
	 */
	public static $cssexts = array('.css', '.css1', '.css2', '.css3');

	/**
	 * Known valid js extension
	 * @var array
	 */
	public static $jsexts = array('.js');

	public static $jstools = array(
		'jsmin' => 'JSMin',
		'closurecompiler' => 'Minify_JS_ClosureCompiler'
		);

	public static $jstool = 'jsmin';

	public static $exclude = '';

	public static function prepare($tpl){
		//set the compress tool
		self::$exclude = $tpl->getParam('minify_exclude', '');
		self::$jstool  = $tpl->getParam('minify_js_tool', 'jsmin');

		if(self::$exclude){
			self::$exclude = '@' . preg_replace('@[,]+@', '|', preg_quote(self::$exclude)) . '@';
		}
	}

	/**
	 * @param $css
	 * @return string
	 */
	public static function minifyCss( $css ) {
		//T3::import('minify/csscompressor');

		$css = preg_replace( '#\s+#', ' ', $css );
		$css = preg_replace( '#/\*.*?\*/#s', '', $css );
		$css = str_replace( '; ', ';', $css );
		$css = str_replace( ': ', ':', $css );
		$css = str_replace( ' {', '{', $css );
		$css = str_replace( '{ ', '{', $css );
		$css = str_replace( ', ', ',', $css );
		$css = str_replace( '} ', '}', $css );
		$css = str_replace( ';}', '}', $css );

		return trim( $css );
	}

	/**
	 * @param $js
	 * @return string
	 */
	public static function minifyJs( $js ){

		T3::import('minify/' . self::$jstool);
		return call_user_func_array(array(self::$jstools[self::$jstool], 'minify'), array($js));
	}

	/**
	 * 
	 * Check and convert to css real path
	 * @param  string  $url  url to check
	 * @return  mixed  the css file path or false if not exist in server
	 */
	public static function cssPath($url = '') {
		
		//exclude
		if(self::$exclude && preg_match(self::$exclude, $url)){
			return false;
		}

		$url = preg_replace('#[?\#]+.*$#', '', $url);
		$base = JURI::base();
		$root = JURI::root(true);
		$ret = false;

		if(substr($url, 0, 2) === '//'){ //check and append if url is omit http
			$url = JURI::getInstance()->getScheme() . ':' . $url; 
		}

		//check for css file extensions
		foreach ( self::$cssexts as $ext ) {
			if (strlen($ext) <= strlen($url) && substr_compare($url, $ext, -strlen($ext), strlen($ext)) === 0) {
				$ret = true;
				break;
			}
		}

		if($ret){
			if (preg_match('/^https?\:/', $url)) { //is full link
				if (strpos($url, $base) === false){
					// external css
					return false;
				}

				$path = JPath::clean(JPATH_ROOT . '/' . substr($url, strlen($base)));
			} else {
				$path = JPath::clean(JPATH_ROOT . '/' . ($root && strpos($url, $root) === 0 ? substr($url, strlen($root)) : $url));
			}

			return is_file($path) ? $path : false;
		}

		return false;
	}

	/**
	 * 
	 * Check and convert to css real path
	 * @param  string  $url  url to check
	 * @return  mixed  the css file path or false if not exist in server
	 */
	public static function jsPath($url = '') {

		//leave any javascript file that have parameter (K2 is an example)
		if(preg_match('@[?#]+.*$@', $url)){
			return false;
		}

		//exclude
		if(self::$exclude && preg_match(self::$exclude, $url)){
			return false;
		}

		//clean
		$url = preg_replace('@[?#]+.*$@', '', $url);
		$base = JURI::base();
		$root = JURI::root(true);
		$ret = false;

		if(substr($url, 0, 2) === '//'){ //check and append if url is omit http
			$url = JURI::getInstance()->getScheme() . ':' . $url; 
		}

		//check for css file extensions
		foreach ( self::$jsexts as $ext ) {
			if (strlen($ext) <= strlen($url) && substr_compare($url, $ext, -strlen($ext), strlen($ext)) === 0) {
				$ret = true;
				break;
			}
		}

		if($ret){
			if (preg_match('/^https?\:/', $url)) { //is full link
				if (strpos($url, $base) === false){
					// external css
					return false;
				}

				$path = JPath::clean(JPATH_ROOT . '/' . substr($url, strlen($base)));
			} else {
				$path = JPath::clean(JPATH_ROOT . '/' . ($root && strpos($url, $root) === 0 ? substr($url, strlen($root)) : $url));
			}

			return is_file($path) ? $path : false;
		}

		return false;
	}

	/**
	 * @param   string  $url  url to refine
	 * @return  string  the refined url
	 */
	public static function fixUrl($url = ''){
		return ($url[0] === '/' || strpos($url, '://') !== false) ? $url : JURI::base(true) . '/' . $url;
	}

	/**
	 * Check if need re-minify the group
	 */
	public static function checkRebuild ($group, $type, $path) {
		$grouptime = $group['grouptime'];
		$name = substr(md5($group['groupname']), 0, 5);
		$groupname = $type . '-' . $name . '-' . substr($grouptime, -5) . '.' . $type;
		$groupfile = $path . '/' . $groupname;

		// check need rebuild
		$result['filename'] = $groupname;
		$result['rebuild'] = false;
		if (!is_file($groupfile)) {
			$result['rebuild'] = true;
			// clean old files
			$files = JFolder::files($path, $type . '-' . $name . '-*.' . $type);
			foreach ($files as $file) {
				JFile::delete($file);
			}
		}
		return $result;
	}

	/**
	 * @param   $tpl  template object
	 * @return  bool  optimize success or not
	 */
	public static function optimizecss($tpl)
	{
		$outputpath = JPATH_ROOT . '/' . $tpl->getParam('t3-assets', 't3-assets') . '/css';
		$outputurl = JURI::root(true) . '/' . $tpl->getParam('t3-assets', 't3-assets') . '/css';
		
		if (!JFile::exists($outputpath)){
			JFolder::create($outputpath);
			@chmod($outputpath, 0755);
		}

		if (!is_writeable($outputpath)) {
			return false;
		}
		
		//prepare config
		self::prepare($tpl);

		$doc = JFactory::getDocument();

		//======================= Group css ================= //
		$mediagroup = array();
		$cssgroups = array();
		$stylesheets = array();
		$ielimit = 4095;
		$selcounts = 0;
		$regex = '/\{.+?\}|,/s'; //selector counter
		$csspath = '';

		// group css into media
		$mediagroup['all'] = array();
		$mediagroup['screen'] = array();
		foreach ($doc->_styleSheets as $url => $stylesheet) {
			$media = !empty($stylesheet['media']) ? $stylesheet['media'] : 'all';
			if (empty($mediagroup[$media])) {
				$mediagroup[$media] = array();
			}
			$mediagroup[$media][$url] = $stylesheet;
		}

		foreach ($mediagroup as $media => $group) {
			$stylesheets = array(); // empty - begin a new group
			foreach ($group as $url => $stylesheet) {
				$url = self::fixUrl($url);

				if (((!empty($stylesheet['mime']) && $stylesheet['mime'] == 'text/css') || (!empty($stylesheet['type']) && $stylesheet['type'] == 'text/css')) && ($csspath = self::cssPath($url))) {
					$stylesheet['path'] = $csspath;
					$stylesheet['data'] = file_get_contents($csspath);

					$selcount = preg_match_all($regex, $stylesheet['data'], $matched);
					if(!$selcount) {
						$selcount = 1; //just for sure
					}

					//if we found an @import rule or reach IE limit css selector count, break into the new group
					if (preg_match('#@import\s+.+#', $stylesheet['data']) || $selcounts + $selcount >= $ielimit) {
						if(count($stylesheets)){
							$cssgroup = array();
							$groupname = array();
							$grouptime = 0;
							foreach ( $stylesheets as $gurl => $gsheet ) {
								$cssgroup[$gurl] = $gsheet;
								$groupname[] = $gurl;
								$ftime = @filemtime($gsheet['path']);
								if ($ftime > $grouptime) $grouptime = $ftime;
							}

							$cssgroup['groupname'] = implode('', $groupname);
							$cssgroup['grouptime'] = $grouptime;
							$cssgroup['media'] = $media;
							$cssgroups[] = $cssgroup;
						}

						$stylesheets = array($url => $stylesheet); // empty - begin a new group
						$selcounts = $selcount;
					} else {

						$stylesheets[$url] = $stylesheet;
						$selcounts += $selcount;
					}

				} else {
					// first get all the stylsheets up to this point, and get them into
					// the items array
					if(count($stylesheets)){
						$cssgroup = array();
						$groupname = array();
						$grouptime = 0;
						foreach ( $stylesheets as $gurl => $gsheet ) {
							$cssgroup[$gurl] = $gsheet;
							$groupname[] = $gurl;
							$ftime = @filemtime($gsheet['path']);
							if ($ftime > $grouptime) $grouptime = $ftime;
						}

						$cssgroup['groupname'] = implode('', $groupname);
						$cssgroup['grouptime'] = $grouptime;
            			$cssgroup['media'] = $media;
						$cssgroups[] = $cssgroup;
					}

					//mark ignore current stylesheet
					$cssgroup = array($url => $stylesheet, 'ignore' => true);
					$cssgroups[] = $cssgroup;

					$stylesheets = array(); // empty - begin a new group
				}
			}

			if(count($stylesheets)){
				$cssgroup = array();
				$groupname = array();
				$grouptime = 0;
				foreach ( $stylesheets as $gurl => $gsheet ) {
					$cssgroup[$gurl] = $gsheet;
					$groupname[] = $gurl;
					$ftime = @filemtime($gsheet['path']);
					if ($ftime > $grouptime) $grouptime = $ftime;
				}

				$cssgroup['groupname'] = implode('', $groupname);
				$cssgroup['grouptime'] = $grouptime;
				$cssgroup['media'] = $media;
				$cssgroups[] = $cssgroup;
			}
		}

		//======================= Group css ================= //

		$output = array();
		foreach ($cssgroups as $cssgroup) {
			if(isset($cssgroup['ignore'])){
				unset($cssgroup['ignore']);
				unset($cssgroup['groupname']);
				unset($cssgroup['media']);
				foreach ($cssgroup as $furl => $fsheet) {
					$output[$furl] = $fsheet;
				}
			} else {
				$rebuildCheck = self::checkRebuild($cssgroup, 'css', $outputpath);

				$media = $cssgroup['media'];
				unset($cssgroup['groupname']);
				unset($cssgroup['grouptime']);
				unset($cssgroup['media']);

				$groupname = $rebuildCheck['filename'];
				if($rebuildCheck['rebuild']){
					$groupfile = $outputpath . '/' . $groupname;
					$cssdata = array();
					foreach ($cssgroup as $furl => $fsheet) {
						$cssdata[] = "\n\n/*===============================";
						$cssdata[] = $furl;
						$cssdata[] = "================================================================================*/";

						$cssmin = self::minifyCss($fsheet['data']);
						$cssmin = T3Path::updateUrl($cssmin, T3Path::relativePath($outputurl, dirname($furl)));

						$cssdata[] = $cssmin;
					}

					$cssdata = implode("\n", $cssdata);
					if (!JFile::write($groupfile, $cssdata)) {
						// cannot write file, ignore minify
						return false;
					}
					$grouptime = @filemtime($groupfile);
					@chmod($groupfile, 0644);
				}

				$output[$outputurl . '/' . $groupname] = array(
					'mime' => 'text/css',
					'media' => $media
					);
				// back compatible with old version
				if(version_compare(JVERSION, '3.5', 'lt')) {
					$output[$outputurl . '/' . $groupname]['attribs'] = [];
				}
			}
		}

		//apply the change make change
		$doc->_styleSheets = $output;
	}

	/**
	 * Optimize javascript
	 * @param $tpl
	 * @return bool
	 */
	public static function optimizejs($tpl){
		$outputpath = JPATH_ROOT . '/' . $tpl->getParam('t3-assets', 't3-assets') . '/js';
		$outputurl = JURI::root(true) . '/' . $tpl->getParam('t3-assets', 't3-assets') . '/js';

		if (!JFile::exists($outputpath)){
			JFolder::create($outputpath);
			@chmod($outputpath, 0755);
		}

		if (!is_writeable($outputpath)) {
			return false;
		}

		//prepare config
		self::prepare($tpl);

		$doc = JFactory::getDocument();

		//======================= Group css ================= //
		$jsgroups = array();
		$scripts = array();
		
		foreach ($doc->_scripts as $url => $script) {

			$url = self::fixUrl($url);

			if (((!empty($script['mime']) && $script['mime'] == 'text/javascript') || (!empty($script['type']) && $script['type'] == 'text/javascript')) && !preg_match('/tinymce/', $url) && ($jspath = self::jsPath($url))) {
				
				$script['path'] = $jspath;
				$script['data'] = file_get_contents($jspath);

				$scripts[$url] = $script;

			} else {
				// first get all the stylsheets up to this point, and get them into
				// the items array
				if(count($scripts)){
					$jsgroup = array();
					$groupname = array();
					$grouptime = 0;
					foreach ( $scripts as $gurl => $gsheet ) {
						$jsgroup[$gurl] = $gsheet;
						$groupname[] = $gurl;
						$ftime = @filemtime($gsheet['path']);
						if ($ftime > $grouptime) $grouptime = $ftime;
					}

					$jsgroup['groupname'] = implode('', $groupname);
					$jsgroup['grouptime'] = $grouptime;
					$jsgroups[] = $jsgroup;
				}

				//mark ignore current script
				$jsgroup = array($url => $script, 'ignore' => true);
				$jsgroups[] = $jsgroup;

				$scripts = array(); // empty - begin a new group
			}
		}

		if(count($scripts)){
			$jsgroup = array();
			$groupname = array();
			$grouptime = 0;
			foreach ( $scripts as $gurl => $gsheet ) {
				$jsgroup[$gurl] = $gsheet;
				$groupname[] = $gurl;
				$ftime = @filemtime($gsheet['path']);
				if ($ftime > $grouptime) $grouptime = $ftime;
			}

			$jsgroup['groupname'] = implode('', $groupname);
			$jsgroup['grouptime'] = $grouptime;
			$jsgroups[] = $jsgroup;
		}

		//======================= Group js ================= //

		$output = array();
		foreach ($jsgroups as $jsgroup) {
			if(isset($jsgroup['ignore'])){

				unset($jsgroup['ignore']);
				foreach ($jsgroup as $furl => $fsheet) {
					$output[$furl] = $fsheet;
				}

			} else {
				$rebuildCheck = self::checkRebuild($jsgroup, 'js', $outputpath);

				unset($jsgroup['groupname']);
				unset($jsgroup['grouptime']);
				
				$groupname = $rebuildCheck['filename'];
				if($rebuildCheck['rebuild']){
					$groupfile = $outputpath . '/' . $groupname;
					$jsdata = array();
					foreach ($jsgroup as $furl => $fsheet) {
						$jsdata[] = "\n\n/*===============================";
						$jsdata[] = $furl;
						$jsdata[] = "================================================================================*/;";

						$jsmin    = $fsheet['data'];

						//already minify?
						if(!preg_match('@.*\.min\.js.*@', $furl)){
							try {
								$jsmin = self::minifyJs($fsheet['data']);
							} catch (Exception $e) {
								// error - ignore minify
								$jsmin = $fsheet['data'];
							}
							//$jsmin = T3Path::updateUrl($jsmin, T3Path::relativePath($outputurl, dirname($furl)));
						}

						$jsdata[] = $jsmin;
					}

					$jsdata = implode("\n", $jsdata);
					if (!JFile::write($groupfile, $jsdata)) {
						// cannot write file, ignore optimize
						return false;
					}
					$grouptime = @filemtime($groupfile);
					@chmod($groupfile, 0644);
				}

				$output[$outputurl . '/' . $groupname] = array(
					'mime' => 'text/javascript',
					'defer' => false,
					'async' => false
				);
			}
		}

		//apply the change make change
		$doc->_scripts = $output;
	}
}
?>
core/templatelayout.php000060400000041137152455303040011261 0ustar00<?php
/**
 *------------------------------------------------------------------------------
 * @package       T3 Framework for Joomla!
 *------------------------------------------------------------------------------
 * @copyright     Copyright (C) 2004-2013 JoomlArt.com. All Rights Reserved.
 * @license       GNU General Public License version 2 or later; see LICENSE.txt
 * @authors       JoomlArt, JoomlaBamboo, (contribute to this project at github
 *                & Google group to become co-author)
 * @Google group: https://groups.google.com/forum/#!forum/t3fw
 * @Link:         http://t3-framework.org
 *------------------------------------------------------------------------------
 */

// No direct access
defined('_JEXEC') or die();
T3::import('core/template');
jimport('joomla.utilities.utility');

/**
 * T3Template class provides extended template tools used for T3 framework
 *
 * @package T3
 */
class T3TemplateLayout extends T3Template
{
	protected $_block = null;

	/**
	 * Class constructor
	 * @param  object  $template  Current template instance
	 */
	public function __construct($template = null)
	{
		parent::__construct($template);
		if(!$this->responcls){
			$this->setParam('responsive', 0);
		}
		$this->setParam('devmode', 0);
		// disable option skip component content when loading layout for admin
		$this->setParam('skip_component_content', null);
	}

	/**
	 * Get current layout tpls
	 *
	 * @return  string  Layout name
	 */
	public function getLayout()
	{
		return JFactory::getApplication()->input->getCmd('t3layout', $this->_tpl->params->get('mainlayout'));
	}

	/**
	 * Check a module condition is true or not
	 * @param string $positions
	 * @return  true  always return true
	 */
	function countModules($positions)
	{
		return 1;
	}

	/**
	 * Check for a spotlight if it can be render or not
	 * @param   string  $name       spotlight name
	 * @param   string  $positions  default position values
	 *
	 * @return  true    always return true
	 */
	function checkSpotlight($name, $positions)
	{
		return 1;
	}

	
	/**
	 * Check for the message queue
	 *
	 * @return  true    always return true
	 */
	function hasMessage(){
		return 1;
	}

	/**
	 * Load block content
	 *
	 * @param $block string block name - the real block is tpls/blocks/[blockname].php
	 * @param $vars  array  information of block (used in template layout)
	 *
	 * @return string Block content
	 */
	function loadBlock($block, $vars = array())
	{
		if (!$this->_block) {
			$this->_block = $block;
		}

		$path = T3Path::getPath('tpls/system/' . $block . '.php');
		if (!$path) {
			$path = T3Path::getPath('tpls/blocks/' . $block . '.php');
		}

		ob_start();
		if ($path) {
			include $path;
		} else {
			echo "<div class=\"error\">Block [$block] not found!</div>";
		}
		$content = ob_get_contents();
		ob_end_clean();

		if (isset($vars['spl'])) {
			$content = preg_replace('#(<[A-Za-z]+[^>^\/]*)>#', '\1 data-original="' . $block . '"' . (isset($vars['spl']) ? ' data-spotlight="' . $vars['name'] . '"' : '') . '>', $content, 1);
			$this->_block = null;
		}

		echo isset($vars['spl']) ? $content : ('<div class="t3-admin-layout-section">' . $content . '</div>');
	}

	/**
	 * Load layout content
	 * @param $layout string  Block name - the real block is tpls/blocks/[blockname].php
	 *
	 * @return none
	 */
	function loadLayout($layout)
	{
		$path = T3Path::getPath('tpls/' . $layout . '.php', 'tpls/default.php');
    
		if ($path) {
			// include $path;
			$html = $this->loadFile($path);

			// parse and replace jdoc
			$html = $this->_parse($html);
			echo $html;
		} else {
			echo "<div class=\"error\">Layout [$layout] or [Default] not found!</div>";
		}
	}

	/**
	 * Generate a spotlight block
	 *
	 * @param  $name  string  Name of spotlight - identity, ex: 'spotlight-1'
	 * @param  $positions string default positions, ex: 'positon-1, position-2'
	 * @param  $info array
	 *            options for spotlight and for every position
	 *            ex: array(
	 *                'row-fluid' => 1,
	 *                'position-1' => array(
	 *                    '[dv1]' => 'span3 special',
	 *                    '[dv2]' => 'span3 hidden'
	 *                    ),
	 *                'position-2' => array(...)
	 *            )
	 * @return  none  render spotlight block
	 */
	function spotlight($name, $positions, array $info = array())
	{
		$vars = is_array($info) ? $info : array();
		$defpos = $poss = preg_split('/\s*,\s*/', $positions);
		$defnumpos = count($defpos);

		$splparams = array();
		for ($i = 1; $i <= $this->maxgrid; $i++) {
			$param = $this->getLayoutSetting('block' . $i . '@' . $name);
			if (empty($param)) {
				break;
			} else {
				$splparams[] = $param;
			}
		}

		//we have data - configuration saved
		if (!empty($splparams)) {
			$poss = array();
			$optgroup = array();
			foreach ($splparams as $i => $splparam) {
				$param = (object)$splparam;
				$poss[] = isset($param->position) ? $param->position : $defpos[$i];
				$optgroup[] = isset($param->optgroup) ? $param->optgroup : '';
			}

		} else {
			foreach ($poss as $i => $pos) {
				$splparams[$i] = '';
			}
		}

		$original = implode(',', $defpos);

		$inits = array();
		foreach ($defpos as $i => $dpos) {
			$inits[$i] = $this->parseInfo(isset($vars[$dpos]) ? $vars[$dpos] : '');
		}

		$infos = array();
		foreach ($splparams as $i => $splparam) {
			$infos[$i] = !empty($splparam) ? $this->parseInfo($splparam) : $inits[$i];
		}

		$defwidths = $this->extractKey($inits, 'width');
		$deffirsts = $this->extractKey($inits, 'first');

		$widths = $this->extractKey($infos, 'width');
		$firsts = $this->extractKey($infos, 'first');
		$others = $this->extractKey($infos, 'others');

		//optimize default width if needed
		$this->optimizeWidth($defwidths, $defnumpos);
		$this->optimizeWidth($widths, $defnumpos);

		$visibility = array(
			'name' => $name,
			'vals' => $this->extractKey($infos, 'hidden'),
			'deft' => $this->extractKey($inits, 'hidden'),
		);

		$spldata = array(
			' data-original="', $original, '"',
			' data-vis="', $this->htmlattr($visibility), '"',
			' data-owidths="', $this->htmlattr($defwidths), '"',
			' data-widths="', $this->htmlattr($widths), '"',
			' data-ofirsts="', $this->htmlattr($deffirsts), '"',
			' data-firsts="', $this->htmlattr($firsts), '"',
			' data-others="', $this->htmlattr($others), '"'
		);

		$default = $widths[$this->defdv];
		//
		$vars['name'] = $name;
		$vars['poss'] = $poss;
		$vars['optgroup'] = $optgroup;
		$vars['spldata'] = implode('', $spldata);
		$vars['default'] = $default;
		$vars['spl'] = 1;

		//normal
		$this->loadBlock('spotlight', $vars);
	}

	/**
	 * Render mainnav block (joomla default navigation)
	 */
	function mainnav()
	{
		echo '<jdoc:include type="modules" name="mainnav" style="raw" />';
	}

	/**
	 * Render position name
	 * @param   string  $condition
	 * @return  string  the position value
	 */
	function getPosname($condition)
	{
		return parent::getPosname($condition) . '" data-original="' . $condition;
	}


	/**
	 * Add additional class and parse for visibility of block
	 * @param   string  $name
	 * @param   array   $cls
	 * @return  null|void
	 */
	function _c($name, $cls = array())
	{
		$params = $this->getLayoutSetting($name, '');

		$cinfo = $oinfo = $this->parseVisibility(is_string($cls) ? array($this->defdv => $cls) : (is_array($cls) ? $cls : array()));
		if (!empty($params)) {
			$cinfo = $this->parseVisibility($params);
		}

		$data = '';
		$visible = array(
			'name' => $name,
			'vals' => $this->extractKey(array($cinfo), 'hidden'),
			'deft' => $this->extractKey(array($oinfo), 'hidden')
		);

		if (empty($params)) {
			if (is_string($cls)) {
				$data = ' ' . $cls;
			} else if (is_array($cls)) {
				$params = (object)$cls;
			}
		}

		if(!empty($params)){
			foreach ($this->maxcol as $device => $span) {
				if(!empty($params->$device)){
					$prefix = $this->responcls ? ' ' : ' data-' . $device . '="';
					$posfix = $this->responcls ? '' : '"';
					$data .= $prefix . trim($params->$device) . $posfix;
				}
			}
			
			$defdv = $this->defdv;
			if(!$this->responcls && !empty($data)){
				$data = (isset($params->$defdv) ? ' ' . $params->$defdv : '') . ' t3respon"' . substr($data, 0, strrpos($data, '"'));
			}
		}

		//remove hidden class
		$data = preg_replace('@("|\s)?'. preg_quote(T3_BASE_HIDDEN_PATTERN) .'(\s|")?@iU', '$1$2', $data);

		echo $data . '" data-vis="' . $this->htmlattr($visible) . '" data-others="' . $this->htmlattr($this->extractKey(array($oinfo), 'others'));
	}

	/**
	 * Internal function, use to parse layout blocks
	 * @param   string  $html  html markup string
	 * @return  string  mixed  layout markup
	 */
	protected function _parse($html)
	{
		$html = preg_replace_callback('#<jdoc:include\ type="([^"]+)" (.*)\/>#iU', array($this, '_parseJDoc'), $html);
		return $html;
	}

	/**
	 * Parse each <jdoc /> and return the corresponding content
	 * @param   $matches  <jdoc /> infomation
	 * @return  string    block markup
	 */
	protected function _parseJDoc($matches)
	{
		$type = $matches[1];
		if ($type == 'head') {
			return $matches[0];
		}
		$attribs = empty($matches[2]) ? array() : JUtility::parseAttributes($matches[2]);
		$attribs['type'] = $type;
		if (!isset($attribs['name'])) {
			$attribs['name'] = $attribs['type'];
		}

		if (!empty($attribs['data-original'])) {
			$optgroup = $this->_layoutsettings->get($attribs['data-original'], false);
			if (!empty($optgroup->optgroup))
				$attribs['data-optgroup'] = $optgroup->optgroup;
		}

		$tp = 'tpls/system/tp.php';
		$path = '';
		if (is_file(T3_TEMPLATE_PATH . '/' . $tp)) {
			$path = T3_TEMPLATE_PATH . '/' . $tp;
		} else if (is_file(T3_PATH . '/' . $tp)) {
			$path = T3_PATH . '/' . $tp;
		}

		return $this->loadFile($path, $attribs);
	}

	/**
	 * Render a file in memory
	 * @param   string  $path  file path to render
	 * @param   array   $vars  additional information
	 * @return  string  the renderred content
	 */
	function loadFile($path, $vars = array())
	{
		ob_start();
		include $path;
		$content = ob_get_contents();
		ob_end_clean();
		return $content;
	}

	/**
	 * Add T3 basic head
	 */
	function addHead()
	{
		//TODO: should we return null here
		//we do not really need a header here

		// BOOTSTRAP CSS
		//$this->addCss ('bootstrap', false); 
		//$this->addCss ('t3-admin-layout-preview', false); 

		// Add scripts
		//$this->addScript (T3_URL.'/bootstrap/js/jquery.js');
		//$this->addScript (T3_URL.'/bootstrap/js/bootstrap.js');
	}

	/**
	 * Render dummy megamenu block in layout
	 * @param string $menutype
	 */
	function megamenu($menutype)
	{
		echo "<div class='t3-admin-layout-pos block-nav t3-admin-layout-uneditable'> <h3>Megamenu [$menutype]</h3></div>";
	}

	/**
	 * Parse information
	 * @param  $posinfo  array  should be an object in setting file
	 *         $posinfo = array(
	 *            '[dv1]' => 'col-lg-3',
	 *            '[dv2]' => 'col-md-4',
	 *            '[dv3]' => 'col-xs-6 hidden'
	 *         )
	 * @return  array  positions information
	 */
	function parseInfo($posinfo = array())
	{
		//convert to array
		if (empty($posinfo)) {
			$posinfo = array();
		} else {
			$posinfo = is_array($posinfo) ? $posinfo : get_object_vars($posinfo);
		}

		// init empty result
		$result = array();
		foreach ($this->devices as $device) {
			$result[$device] = array();
		}

		$defcls = !$this->responcls && isset($posinfo[$this->defdv]) ? $posinfo[$this->defdv] : '';

		foreach ($result as $device => &$info) {
			//class presentation string
			$cls = isset($posinfo[$device]) ? $posinfo[$device] : '';

			//extend other device
			if (!empty($defcls) && $device != $this->defdv) {
				$cls = $this->addclass($cls, $defcls);
			}
			//if isset
			if (!empty($cls)) {
				//check if this position is hidden
				$hidden = T3_BASE_HIDDEN_PATTERN && $this->hasclass($cls, T3_BASE_HIDDEN_PATTERN);
				if ($hidden) {
					$cls = $this->removeclass($cls, T3_BASE_HIDDEN_PATTERN);
				}

				//check if this position is first position
				$first = T3_BASE_FIRST_PATTERN && $this->hasclass($cls, T3_BASE_FIRST_PATTERN);
				if ($first) {
					$cls = $this->removeclass($cls, T3_BASE_FIRST_PATTERN);
				}

				//check for width of this position
				$width = $this->maxgrid;
				if(preg_match($this->spancls, $cls, $match)){
					$match = array_filter($match, 'is_numeric');
					$width = array_pop($match);
					$width = is_numeric($width) ? $width : $this->maxgrid;
				}

				if (!$this->responcls && intval($width) > 0) {
					$width = $this->convertWidth($width, $device);
				}

				//other class
				$others = trim(preg_replace($this->spancls, ' ', $cls));
			} else {
				$hidden = 0;
				$first = 0;
				$width = 0;
				$others = '';
			}

			$info['hidden'] = $hidden;
			$info['first'] = $first;
			$info['width'] = $width;
			$info['others'] = $others;
		}

		return $result;
	}

	/**
	 *  Parse visibility information
	 *  @param  $posinfo  array  should be an object in setting file
	 *          $posinfo = array(
	 *            '[dv1]' => 'col-lg-3',
	 *            '[dv2]' => 'col-md-4',
	 *            '[dv3]' => 'col-xs-6 hidden'
	 *          )
	 *
	 *  We focus on visibility value only, other information will be placed in others
	 *  @return  array  visibility information
	 **/
	function parseVisibility($posinfo = array())
	{

		//convert to array
		if (empty($posinfo)) {
			$posinfo = array();
		} else {
			$posinfo = is_array($posinfo) ? $posinfo : get_object_vars($posinfo);
		}

		// init empty result
		$result = array();
		foreach ($this->devices as $device) {
			$result[$device] = array();
		}

		foreach ($result as $device => &$info) {
			//class presentation string
			$cls = isset($posinfo[$device]) ? $posinfo[$device] : '';

			//if isset
			if (!empty($cls)) {
				//check if this position is hidden
				$hidden = T3_BASE_HIDDEN_PATTERN && $this->hasclass($cls, T3_BASE_HIDDEN_PATTERN);
				if ($hidden) {
					$cls = $this->removeclass($cls, T3_BASE_HIDDEN_PATTERN);
				}

				//other class
				$others = trim($cls);
			} else {
				$hidden = 0;
				$others = '';
			}

			$info['hidden'] = $hidden;
			$info['others'] = $others;
		}

		return $result;
	}

	/**
	 *  Extract a value key from object
	 **/
	function extractKey($infos, $key)
	{
		//$info = array(
		//	[0] => array(
		//		'[dv1]' => array(
		//			'hidden' => 0
		//			'first' => 0
		//			'width' => 2
		//			'others' => ''
		//			),
		//		'[dv2]' => array(
		//			'hidden' => 0
		//			'width' => 2
		//			'others' => ''
		//			),
		//		...
		//		),
		//
		//	[1] => array(
		//		'[dv1]' => array(
		//			'hidden' => 0
		//			'width' => 2
		//			'others' => ''
		//			)
		//		)
		//	),
		//  ...

		// init empty result
		$result = array();
		foreach ($this->devices as $device) {
			$result[$device] = array();
		}

		foreach ($infos as $i => $devices) {
			foreach ($devices as $device => $info) {
				$result[$device][$i] = $info[$key];
			}
		}

		return $result;
	}


	/**
	 *  Optimize width of a spotlight
	 *   - we try to fit all position of a spotlight to one row
	 *    $widths = array(
	 *        '[dv1]' => array(3,3,3,3),
	 *        '[dv2]' => array(1,2,3,4)
	 *    )
	 **/
	function optimizeWidth(&$widths, $newcols = false)
	{
		foreach ($widths as $device => &$width) {
			if (array_sum($width) < $this->maxgrid || $width[0] == 0) { //test if default empty width
				$widths[$device] = $this->genWidth($device, $newcols ? $newcols : count($width));
			}
		}
	}

	/**
	 *  Convert width of mobile - mobile have special width number
	 **/
	function convertWidth($width, $device)
	{
		//convert back - width of mobile should be [33%,] 50% and 100%
		//there might be some case when we enter the width of other device ( < 12) => return 100% (12)
		return $device == 'mobile' ? ($width <= 12 ? 12 : floor($width / 100 * 12)) : $width;
	}

	/**
	 *  Utility function - check if a HTML class is exist in a HTML class list
	 **/
	function hasclass($clsname, $cls)
	{
		return intval(strpos(' ' . $clsname . ' ', ' ' . $cls . ' ') !== false);
	}

	/**
	 *  Utility function - remove a HTML class in a HTML class list
	 **/
	function removeclass($clsname, $cls)
	{
		return preg_replace('/(^|\s)' . $cls . '(?:\s|$)/', '$1', $clsname);
	}

	/**
	 *  Utility function - remove a HTML class in a HTML class list
	 *  The result will contains only 1 width class (col-xx-yy)
	 **/
	function addclass($clsname, $cls)
	{
		$haswidth = preg_match($this->spancls, $clsname);
		if ($haswidth) {
			$cls = trim(preg_replace($this->spancls, ' ', $cls));
		}

		$cls = explode(' ', $cls);

		foreach ($cls as $cl) {
			if (!$this->hasclass($clsname, $cl)) {
				$clsname .= ' ' . $cl;
			}
		}

		return implode(' ', array_unique(explode(' ', $clsname)));
	}

	/**
	 * Utility function - embed json to HTML attribute
	 * @param   mixed $obj  Object to encode
	 * @return  string  The escape html string
	 **/
	function htmlattr($obj)
	{
		return htmlentities(json_encode($obj), ENT_QUOTES);
	}
}

?>core/path.php000060400000016200152455303040007135 0ustar00<?php
/**
 *------------------------------------------------------------------------------
 * @package       T3 Framework for Joomla!
 *------------------------------------------------------------------------------
 * @copyright     Copyright (C) 2004-2013 JoomlArt.com. All Rights Reserved.
 * @license       GNU General Public License version 2 or later; see LICENSE.txt
 * @authors       JoomlArt, JoomlaBamboo, (contribute to this project at github
 *                & Google group to become co-author)
 * @Google group: https://groups.google.com/forum/#!forum/t3fw
 * @Link:         http://t3-framework.org
 *------------------------------------------------------------------------------
 */

use Joomla\Registry\Registry;

// No direct access
defined('_JEXEC') or die();

/**
 * T3Path class
 */
class T3Path extends Registry
{

	/**
	 * Store current source value for updateUrl function
	 */
	protected static $srcurl = '';

	/**
	 * Get path in tpls folder. If found in template, use the path, else try in plugin t3
	 */
	public static function getPath($file, $default = '', $relative = false, $include_local = true)
	{
		if (!defined('T3_LOCAL_DISABLED') && $include_local && file_exists (T3_LOCAL_PATH . '/' . $file)) return ($relative ? T3_LOCAL_REL : T3_LOCAL_PATH) . '/' . $file;
		if (file_exists (T3_TEMPLATE_PATH . '/' . $file)) return ($relative ? T3_TEMPLATE_REL : T3_TEMPLATE_PATH) . '/' . $file;
		if (file_exists (T3_PATH . '/' . $file)) return ($relative ? T3_REL : T3_PATH) . '/' . $file;
		if ($default) return self::getPath($default);
		return '';
	}

	/**
	 * Get path in tpls folder. If found in template, use the path, else try in plugin t3
	 */
	public static function getUrl($file, $default = '', $relative = false, $include_local = true)
	{
		if (!defined('T3_LOCAL_DISABLED') && $include_local && file_exists (T3_LOCAL_PATH . '/' . $file)) return ($relative ? T3_LOCAL_REL : T3_LOCAL_URL) . '/' . $file;
		if (file_exists (T3_TEMPLATE_PATH . '/' . $file)) return ($relative ? T3_TEMPLATE_REL : T3_TEMPLATE_URL) . '/' . $file;
		if (file_exists (T3_PATH . '/' . $file)) return ($relative ? T3_REL : T3_URL) . '/' . $file;
		if ($default) return self::getUrl($default);
		return '';
	}

	/**
	 * Get path in tpls folder. If found in template, use the path, else try in plugin t3
	 */
	public static function getAllPath($file, $relative = false, $include_local = true)
	{
		$return = array();
		if (file_exists (T3_PATH . '/' . $file)) $return[] = ($relative ? T3_REL : T3_PATH) . '/' . $file;
		if (file_exists (T3_TEMPLATE_PATH . '/' . $file)) $return[] = ($relative ? T3_TEMPLATE_REL : T3_TEMPLATE_PATH) . '/' . $file;
		if (!defined('T3_LOCAL_DISABLED') && $include_local && file_exists (T3_LOCAL_PATH . '/' . $file)) $return[] = ($relative ? T3_LOCAL_REL : T3_LOCAL_PATH) . '/' . $file;
		return $return;
	}

	/**
	 * Get path in tpls folder. If found in template, use the path, else try in plugin t3
	 */
	public static function getAllUrl($file, $relative = false, $include_local = true)
	{
		$return = array();
		if (file_exists (T3_PATH . '/' . $file)) $return[] = ($relative ? T3_REL : T3_URL) . '/' . $file;
		if (file_exists (T3_TEMPLATE_PATH . '/' . $file)) $return[] = ($relative ? T3_TEMPLATE_REL : T3_TEMPLATE_URL) . '/' . $file;
		if (!defined('T3_LOCAL_DISABLED') && $include_local && file_exists (T3_LOCAL_PATH . '/' . $file)) $return[] = ($relative ? T3_LOCAL_REL : T3_LOCAL_URL) . '/' . $file;
		return $return;
	}

	/**
	 * Get local path. If const T3_LOCAL_DISABLED defined, use template path; other use local path
	 */
	public static function getLocalPath($file, $relative = false)
	{
		if (!defined('T3_LOCAL_DISABLED')) return ($relative ? T3_LOCAL_REL : T3_LOCAL_PATH) . '/' . $file;
		return ($relative ? T3_TEMPLATE_REL : T3_TEMPLATE_PATH) . '/' . $file;
	}

	/**
	 * Get local path. If const T3_LOCAL_DISABLED defined, use template path; other use local path
	 */
	public static function getLocalUrl($file, $relative = false)
	{
		if (!defined('T3_LOCAL_DISABLED')) return ($relative ? T3_LOCAL_REL : T3_LOCAL_URL) . '/' . $file;
		return ($relative ? T3_TEMPLATE_REL : T3_TEMPLATE_URL) . '/' . $file;
	}

	/**
	 * Asbjorn Grandt
	 * Clean file name paths removing redundant elements
	 */
	public static function cleanPath($path)
	{

		$dirs = explode('/', rtrim(preg_replace('#^(\./)+#', '', $path), '/'));

		$offset = 0;
		$sub = 0;
		$subOffset = 0;
		$root = '';

		if (empty($dirs[0])) {
			$root = '/';
			$dirs = array_splice($dirs, 1);
		}

		$newDirs = array();
		foreach ($dirs as $dir) {
			if ($dir !== '..') {
				$subOffset--;
				$newDirs[++$offset] = $dir;
			} else {
				$subOffset++;
				if (--$offset < 0) {
					$offset = 0;
					if ($subOffset > $sub) {
						$sub++;
					}
				}
			}
		}

		if (empty($root)) {
			$root = str_repeat('../', $sub);
		}

		return $root . implode('/', array_slice($newDirs, 0, $offset));
	}

	public static function relativePath($path1, $path2 = '')
	{
		// config params
		if ($path2 == '') {
			$path2 = $path1;
			$path1 = getcwd();
		}

		// absolute path 		//has protocol						//data protocol
		if ($path2[0] === '/' || strpos($path2, '://') !== false || strpos($path2, 'data:') === 0) {
			return $path2;
		}

		//Remove starting, ending, and double / in paths
		$path1 = trim($path1, '/');
		$path2 = trim($path2, '/');
		while (substr_count($path1, '//')) $path1 = str_replace('//', '/', $path1);
		while (substr_count($path2, '//')) $path2 = str_replace('//', '/', $path2);

		//create arrays
		$arr1 = explode('/', $path1);
		if ($arr1 == array('')) $arr1 = array();
		$arr2 = explode('/', $path2);
		if ($arr2 == array('')) $arr2 = array();
		$size1 = count($arr1);
		$size2 = count($arr2);

		//now the hard part :-p
		$path = '';
		for ($i = 0; $i < min($size1, $size2); $i++) {
			if ($arr1[$i] == $arr2[$i]) continue;
			else break;
		}
		for ($j=$i; $j<min($size1, $size2); $j++) {
			$path = '../' . $path . $arr2[$j] . '/';
		}
		if ($size1 > $size2)
			for ($i = $size2; $i < $size1; $i++)
				$path = '../' . $path;
		else if ($size2 > $size1)
			for ($i = $size1; $i < $size2; $i++)
				$path .= $arr2[$i] . '/';

		return rtrim($path, '/');
	}

	public static function updateUrl($css, $src)
	{
		self::$srcurl = rtrim($src, '/');

		$css = preg_replace_callback('/@import\\s+([\'"])(.*?)[\'"]/', array('T3Path', 'replaceurl'), $css);
		$css = preg_replace_callback('/url\\(\\s*([^\\)\\s]+)\\s*\\)/', array('T3Path', 'replaceurl'), $css);

		return $css;
	}

	public static function replaceurl($matches)
	{
		$isImport = ($matches[0][0] === '@');
		// determine URI and the quote character (if any)
		if ($isImport) {
			$quoteChar = $matches[1];
			$uri = $matches[2];
		} else {
			// $matches[1] is either quoted or not
			$quoteChar = ($matches[1][0] === "'" || $matches[1][0] === '"')
				? $matches[1][0]
				: '';
			$uri = ($quoteChar === '')
				? $matches[1]
				: substr($matches[1], 1, strlen($matches[1]) - 2);
		}

		// root-relative       protocol (non-data)             data protocol
		if ($uri[0] !== '/' && strpos($uri, '://') === false && strpos($uri, 'data:') !== 0) {
			$uri = self::cleanPath(self::$srcurl . '/' . $uri);
		}

		return $isImport
			? "@import {$quoteChar}{$uri}{$quoteChar}"
			: "url({$quoteChar}{$uri}{$quoteChar})";
	}
}core/ajax.php000060400000003046152455303040007130 0ustar00<?php
/** 
 *------------------------------------------------------------------------------
 * @package       T3 Framework for Joomla!
 *------------------------------------------------------------------------------
 * @copyright     Copyright (C) 2004-2013 JoomlArt.com. All Rights Reserved.
 * @license       GNU General Public License version 2 or later; see LICENSE.txt
 * @authors       JoomlArt, JoomlaBamboo, (contribute to this project at github 
 *                & Google group to become co-author)
 * @Google group: https://groups.google.com/forum/#!forum/t3fw
 * @Link:         http://t3-framework.org 
 *------------------------------------------------------------------------------
 */

/**
 *
 * Admin helper module class
 * @author JoomlArt
 *
 */
class T3Ajax {

	protected static $signature;
	protected static $modesef;

	public static function render() {
		// excute action by T3
		$input = JFactory::getApplication()->input;

		if ($input->getCmd ('t3ajax')) {
			JFactory::getDocument()->getBuffer('t3ajax');
		}
	}

	public static function processAjaxRule () {
		$app = JFactory::getApplication();
		$router = $app->getRouter();
		
		if ($app->isClient('site')) {
			//self::$signature = 't3ajax';
			//self::$modesef = ($router->getMode() == JROUTER_MODE_SEF) ? true : false;
			
			$router->attachBuildRule(array('T3Ajax', 'buildRule'));
			//$router->attachParseRule(array('T3Ajax', 'parseRule'));
		}
	}

	public static function buildRule (&$router, &$uri) {
		$uri->delVar('t3ajax');
	}

	public static function parseRule (&$router, &$uri) {

	}
}admin/theme.php000060400000036556152455303040007463 0ustar00<?php
/**
 *------------------------------------------------------------------------------
 * @package       T3 Framework for Joomla!
 *------------------------------------------------------------------------------
 * @copyright     Copyright (C) 2004-2013 JoomlArt.com. All Rights Reserved.
 * @license       GNU General Public License version 2 or later; see LICENSE.txt
 * @authors       JoomlArt, JoomlaBamboo, (contribute to this project at github
 *                & Google group to become co-author)
 * @Google group: https://groups.google.com/forum/#!forum/t3fw
 * @Link:         http://t3-framework.org
 *------------------------------------------------------------------------------
 */

jimport('joomla.filesystem.file');
jimport('joomla.filesystem.folder');
// add new Less format class to work with joomla 3.3
if (version_compare(JVERSION, '3.3.0') >= 0) {
	T3::import('format/less3.3');
}

/**
 *
 * Admin helper module class
 * @author JoomlArt
 *
 */
class T3AdminTheme
{
	/**
	 *
	 * save Profile
	 */

	public static function response($data){
		die(json_encode($data));
	}

	public static function error($msg){
		return self::response(array('error' => $msg));
	}

	public static function save($path)
	{
		$result = array();

		if(empty($path)){
			return self::error(JText::_('T3_TM_UNKNOWN_THEME'));
		}

		$theme = JFactory::getApplication()->input->getCmd('theme');
		$from = JFactory::getApplication()->input->getCmd('from');
		if (!$theme) {
			return self::error(JText::_('T3_TM_INVALID_DATA_TO_SAVE'));
		}

		//incase empty from
		if(!$from){
			$from = 'base';
		}

		// $file = $path . '/less/themes/' . $theme . '/variables-custom.less';
		$file =T3Path::getLocalPath('less/themes/' . $theme . '/variables-custom.less');

		if(!class_exists('JRegistryFormatLESS')){
			T3::import('format/less');
		}
		$variables = new JRegistry();
		$variables->loadObject($_POST);

		$data = $variables->toString('LESS');
		$type = 'new';
		if (JFile::exists($file)) {
			$type = 'overwrite';
		} else {
			if($theme != $from && JFolder::exists($path . '/less/themes/' . $from)){
				$source = $path . '/less/themes/' . $from;
				if (!JFolder::exists($source)) {
					// try to find the source in local
					$source = T3Path::getPath('less/themes/' . $from);
					if (!$source) {
						return self::error(JText::sprintf('T3_TM_NOT_FOUND', $from));
					}
				}
				$desc = T3Path::getLocalPath('less/themes/' . $theme);
				if(@JFolder::copy($source, $desc) != true){
					return self::error(JText::_('T3_TM_NOT_FOUND'));
				}
				
				// detect & copy rtl
				$rtlsource = $path . '/less/rtl/' . $from;
				if (!JFolder::exists($rtlsource)) {
					// try to find the source in local
					$rtlsource = T3Path::getPath('less/rtl/' . $from);
				}
				
				if ($rtlsource) {
					$rtldest = T3Path::getLocalPath('less/rtl/' . $theme);
					// copy $from to $theme
					@JFolder::copy($rtlsource, $rtldest);
				}
			}
		}

		$return = @JFile::write($file, $data);

		if (!$return) {
			return self::error(JText::_('T3_TM_OPERATION_FAILED'));
		} else {
			$result['success'] = JText::sprintf('T3_TM_SAVE_SUCCESSFULLY', $theme);
			$result['theme'] = $theme;
			$result['type'] = $type;
		}

		//LessHelper::compileForTemplate(T3_TEMPLATE_PATH, $theme);
		T3::import ('core/less');
		T3Less::compileAll($theme);
		return self::response($result);
	}

	/**
	 *
	 * Clone Profile
	 */
	public static function duplicate($path)
	{
		$theme = JFactory::getApplication()->input->getCmd('theme');
		$from = JFactory::getApplication()->input->getCmd('from');
		$result = array();

		if (empty($theme) || empty($from)) {
			return self::error(JText::_('T3_TM_INVALID_DATA_TO_SAVE'));
		}

		$source = $path . '/less/themes/' . $from;
		if (!JFolder::exists($source)) {
			// try to find the source in local
			$source = T3Path::getPath('less/themes/' . $from);
			if (!$source) {
				return self::error(JText::sprintf('T3_TM_NOT_FOUND', $from));
			}
		}

		// $dest = $path . '/less/themes/' . $theme;
		// clone to local
		$dest = T3Path::getLocalPath('less/themes/' . $theme);
		if (JFolder::exists($dest)) {
			return self::error(JText::sprintf('T3_TM_EXISTED', $theme));
		}
		
		// copy $from to $theme
		$status = @JFolder::copy($source, $dest);
		
		$rtlsource = $path . '/less/rtl/' . $from;
		if (!JFolder::exists($rtlsource)) {
			// try to find the source in local
			$rtlsource = T3Path::getPath('less/rtl/' . $from);
		}
		
		if ($rtlsource) {
			$rtldest = T3Path::getLocalPath('less/rtl/' . $theme);
			// copy $from to $theme
			@JFolder::copy($rtlsource, $rtldest);
		}
		
		$result = array();
		if ($status) {
			$result['success'] = JText::_('T3_TM_CLONE_SUCCESSFULLY');
			$result['theme'] = $theme;
			$result['reset'] = true;
			$result['type'] = 'duplicate';
		} else {
			return self::error(JText::_('T3_TM_OPERATION_FAILED'));
		}

		//LessHelper::compileForTemplate(T3_TEMPLATE_PATH , $theme);
		T3::import ('core/less');
		T3Less::compileAll($theme);
		return self::response($result);
	}

	/**
	 *
	 * Delete a profile
	 */
	public static function delete($path)
	{
		// Initialize some variables
		$theme = JFactory::getApplication()->input->getCmd('theme');
		$result = array();

		if (!$theme) {
			return self::error(JText::_('T3_TM_UNKNOWN_THEME'));
		}

		// delete custom theme
		$paths = array();
		$paths = array_merge($paths, T3Path::getAllPath('less/themes/' . $theme));
		$paths = array_merge($paths, T3Path::getAllPath('css/themes/' . $theme));
		$paths = array_merge($paths, T3Path::getAllPath('less/rtl/' . $theme));
		$paths = array_merge($paths, T3Path::getAllPath('css/rtl/' . $theme));

		$errors = array();
		foreach ($paths as $path) {
			if (is_dir ($path) && !@JFolder::delete($path)) {
				$errors[] = $path;
			}
		}

		if (count($errors)) {
			return self::error(JText::sprintf('T3_TM_DELETE_FAIL', implode(' - ', $errors)));
		} else {
			$result['template'] = '0';
			$result['success'] = JText::sprintf('T3_TM_DELETE_SUCCESSFULLY', $theme);
			$result['theme'] = $theme;
			$result['type'] = 'delete';
		}

		return self::response($result);
	}

	/**
	 *
	 * Show thememagic form
	 */
	public static function thememagic($path)
	{
		$app       = JFactory::getApplication();
		$input     = $app->input;
		$isadmin   = T3::isAdmin();

		if($isadmin){
			$tplparams = T3::getTplParams();
		} else {
			$tplparams = $app->getTemplate(true)->params;
		}

		$url = $isadmin ? JUri::root(true).'/index.php' : JUri::current();
		$url .= (preg_match('/\?/', $url) ? '&' : '?') . 'themer=1';
		$url .= ($tplparams->get('theme', -1) != -1 ? ('&t3style=' . $tplparams->get('theme')) : '');
		if($isadmin){
			$url .= '&t3tmid=' . $input->getCmd('id');
		}

		$assetspath = T3_TEMPLATE_PATH;
		$themepath = $assetspath . '/less/themes';
		if(!class_exists('JRegistryFormatLESS')){
			include_once T3_ADMIN_PATH . '/includes/format/less.php';
		}

		$themes   = array();
		$jsondata = array();

		//push a default theme
		$tobj = new stdClass();
		$tobj->id    = 'base';
		$tobj->title = JText::_('JDEFAULT');

		$themes['base'] = $tobj;

		$varfile = $assetspath . '/less/variables.less';
		if(file_exists($varfile)){
			$params = new JRegistry;
			$params->loadString(file_get_contents($varfile), 'LESS');
			$jsondata['base'] = $params->toArray();
		}

		// if (JFolder::exists($themepath)) {
		foreach (T3Path::getAllPath('/less/themes') as $themepath) {
			$listthemes = JFolder::folders($themepath);
			if (count($listthemes)) {
				foreach ($listthemes as $theme) {
					//$varsfile = $themepath . '/' . $theme . '/variables-custom.less';
					//if(file_exists($varsfile)){

						$tobj = new stdClass();
						$tobj->id    = $theme;
						$tobj->title = $theme;

						//check for all less file in theme folder
						$params = false;
						$others = JFolder::files($themepath . '/' . $theme, '.less', false, true);
						foreach($others as $other){
							$otherrel = T3Path::relativePath('less/', str_replace (T3_TEMPLATE_PATH . '/', '', $other));

							//get those developer custom values
							if($other == 'variables.less'){
								$params = new JRegistry;
								$params->loadString(file_get_contents($themepath . '/' . $theme . '/variables.less'), 'LESS');
							}

							if($other != 'variables-custom.less'){
								$tobj->$other = $otherrel;
							}
						}

						$cparams = new JRegistry;
						$varsfile = $themepath . '/' . $theme . '/variables.less';
						if(file_exists($varsfile)) $cparams->loadString(file_get_contents($varsfile), 'LESS');
						$varsfile = $themepath . '/' . $theme . '/variables-custom.less';
						if(file_exists($varsfile)) $cparams->loadString(file_get_contents($varsfile), 'LESS');
						if($params){
							foreach ($cparams->toArray() as $key => $value) {
								$params->set($key, $value);
							}
						} else {
							$params = $cparams;
						}

						$themes[$theme] = $tobj;
						$jsondata[$theme] = $params->toArray();
					//}
				}
			}
		}

		// get active theme
		$active_theme = $tplparams->get('theme', 'base');
		if (!isset($themes[$active_theme])) $active_theme = 'base';

		$langs = array (
			'addTheme'       => JText::_('T3_TM_ASK_ADD_THEME'),
			'delTheme'       => JText::_('T3_TM_ASK_DEL_THEME'),
			'overwriteTheme' => JText::_('T3_TM_ASK_OVERWRITE_THEME'),
			'correctName'    => JText::_('T3_TM_ASK_CORRECT_NAME'),
			'themeExist'     => JText::_('T3_TM_EXISTED'),
			'saveChange'     => JText::_('T3_TM_ASK_SAVE_CHANGED'),
			'previewError'   => JText::_('T3_TM_PREVIEW_ERROR'),
			'unknownError'   => JText::_('T3_MSG_UNKNOWN_ERROR'),
			'lblCancel'      => JText::_('JCANCEL'),
			'lblOk'          => JText::_('T3_TM_LABEL_OK'),
			'lblNo'          => JText::_('JNO'),
			'lblYes'         => JText::_('JYES'),
			'lblDefault'     => JText::_('JDEFAULT')
		);

		//Keepalive
		$config      = JFactory::getConfig();
		$lifetime    = ($config->get('lifetime') * 60000);
		$refreshTime = ($lifetime <= 60000) ? 30000 : $lifetime - 60000;

		// Refresh time is 1 minute less than the liftime assined in the configuration.php file.
		// The longest refresh period is one hour to prevent integer overflow.
		if ($refreshTime > 3600000 || $refreshTime <= 0){
			$refreshTime = 3600000;
		}

		$backurl = JUri::getInstance();
		$backurl->delVar('t3action');
		$backurl->delVar('t3task');

		if(!$isadmin){
			$backurl->delVar('tm');
			$backurl->delVar('themer');
		}

		T3::import('depend/t3form');

		$form = new T3Form('thememagic.themer', array('control' => 't3form'));
		$form->load(file_get_contents(JFile::exists(T3_TEMPLATE_PATH . '/thememagic.xml') ? T3_TEMPLATE_PATH . '/thememagic.xml' : T3_PATH . '/params/thememagic.xml'));
		$form->loadFile(T3_TEMPLATE_PATH . '/templateDetails.xml', true, '//config');

		$tplform = new T3Form('thememagic.overwrite', array('control' => 't3form'));
		$tplform->loadFile(T3_TEMPLATE_PATH . '/templateDetails.xml', true, '//config');

		$fieldSets = $form->getFieldsets('thememagic');
		$tplFieldSets = $tplform->getFieldsets('thememagic');

		$disabledFieldSets = array();
		foreach ($tplFieldSets as $name => $fieldSet){
			if(isset($fieldSet->disabled)){
				$disabledFieldSets[] = $name;
			}
		}

		include T3_ADMIN_PATH.'/admin/thememagic/thememagic.tpl.php';

		exit();
	}

	public static function addAssets(){
		$japp = JFactory::getApplication();
		$user = JFactory::getUser();

		//do nothing when site is offline and user has not login (the offline page is only show login form)
		if ($japp->getCfg('offline') && !$user->authorise('core.login.offline')) {
			return;
		}

		$jdoc = JFactory::getDocument();
		$params = $japp->getTemplate(true)->params;
		$devmode = $params->get('devmode', 0);

		if(defined('T3_THEMER') && $params->get('themermode', 1)){

			$jdoc->addStyleSheet(T3_URL.'/css/thememagic.css');
			$jdoc->addScript(T3_URL.'/js/thememagic.js');

			$theme     = $params->get('theme');
			$params    = new JRegistry;
			$themeinfo = new stdClass;

			if($theme){
				foreach (T3Path::getAllPath('less/themes/' . $theme) as $themepath) {
					//$themepath = T3_TEMPLATE_PATH . '/less/themes/' . $theme;

					if(file_exists($themepath . '/variables-custom.less')){
						if(!class_exists('JRegistryFormatLESS')){
							include_once T3_ADMIN_PATH . '/includes/format/less.php';
						}

						//default variables
						$varfile = T3_TEMPLATE_PATH . '/less/variables.less';
						if(file_exists($varfile)){
							$params->loadString(file_get_contents($varfile), 'LESS');

							//get all less files in "theme" folder
							$others = JFolder::files($themepath, '.less');
							foreach($others as $other){
								//get those developer custom values
								if($other == 'variables.less'){
									$devparams = new JRegistry;
									$devparams->loadString(file_get_contents($themepath . '/variables.less'), 'LESS');

									//overwrite the default variables
									foreach ($devparams->toArray() as $key => $value) {
										$params->set($key, $value);
									}
								}

								//ok, we will import it later
								if($other != 'variables-custom.less' && $other != 'variables.less'){
									$themeinfo->$other = true;
								}
							}

							//load custom variables
							if (file_exists($themepath . '/variables-custom.less')) {
								$cparams = new JRegistry;
								$cparams->loadString(file_get_contents($themepath . '/variables-custom.less'), 'LESS');

								//and overwrite those defaults variables
								foreach ($cparams->toArray() as $key => $value) {
									$params->set($key, $value);
								}
							}
						}
					}
				}
			}

			$cache = array();

			// a little security
			if($user->authorise('core.manage', 'com_templates') || (isset($_SERVER['HTTP_REFERER']) && strpos($_SERVER['HTTP_REFERER'], JUri::base() . 'administrator') !== false)){
				T3::import('core/path');
				$baseurl = JUri::base();

				//should we provide a list of less path
				foreach (array(T3_TEMPLATE_PATH . '/less', T3_PATH . '/bootstrap/less', T3_PATH . '/less') as $lesspath) {
					if(is_dir($lesspath)){
						$lessfiles = JFolder::files($lesspath, '.less', true, true);
						if(is_array($lessfiles)){
							foreach ($lessfiles as $less) {
								$path            = ltrim(str_replace(array(JPATH_ROOT, '\\'), array('', '/'), $less), '/');
								$path            = T3Path::cleanPath($path);
								$fullurl         = $baseurl . preg_replace('@(\\+)|(/+)@', '/', $path);
								$cache[$fullurl] = file_get_contents($less);
							}
						}
					}
				}
			}

			//workaround for bootstrap icon path
			$sparams = new JRegistry;
			if(defined('T3_BASE_RSP_IN_CLASS') && T3_BASE_RSP_IN_CLASS){
				$sparams->set('icon-font-path', '"' . JUri::base() . 'plugins/system/t3/base-bs3/bootstrap/fonts/"');
			}

			// enable development mode for less.js
			if ($devmode) {
				$jdoc->addScriptDeclaration('
					var less = window.less || {};
					less.env = \'development\';
				');
			}

			$jdoc->addScriptDeclaration('
				var T3Theme = window.T3Theme || {};
				T3Theme.vars = ' . json_encode($params->toArray()) . ';
				T3Theme.svars = ' . json_encode($sparams->toArray()) . ';
				T3Theme.others = ' . json_encode($themeinfo) . ';
				T3Theme.theme = \'' . $theme . '\';
				T3Theme.template = \'' . T3_TEMPLATE . '\';
				T3Theme.base = \'' . JURI::base() . '\';
				T3Theme.cache = ' . json_encode($cache) . ';
				if(typeof less != \'undefined\'){
					
					//we need to build one - cause the js will have unexpected behavior
					try{
						if(window.parent != window && 
							window.parent.T3Theme && 
							window.parent.T3Theme.applyLess){
							
							window.parent.T3Theme.applyLess(true);
						} else {
							less.refresh();
						}
					} catch(e){

					}
				}'
			);
		}
	}
}admin/layout.php000060400000033750152455303040007667 0ustar00<?php
/** 
 *------------------------------------------------------------------------------
 * @package       T3 Framework for Joomla!
 *------------------------------------------------------------------------------
 * @copyright     Copyright (C) 2004-2013 JoomlArt.com. All Rights Reserved.
 * @license       GNU General Public License version 2 or later; see LICENSE.txt
 * @authors       JoomlArt, JoomlaBamboo, (contribute to this project at github 
 *                & Google group to become co-author)
 * @Google group: https://groups.google.com/forum/#!forum/t3fw
 * @Link:         http://t3-framework.org 
 *------------------------------------------------------------------------------
 */

jimport('joomla.filesystem.file');
jimport('joomla.filesystem.folder');

/**
 * Layout helper module class
 */
class T3AdminLayout
{
	public static function response($result = array())
	{
		die(json_encode($result));
	}
	
	public static function error($msg = '')
	{
		return self::response(array(
			'error' => $msg
		));
	}
	
	public static function display()
	{
		
		$app   = JFactory::getApplication();
		$input = $app->input;
		
		if (!T3::isAdmin()) {
			
			$tpl = $app->getTemplate(true);
			
			// get template name
			if ($input->getCmd('t3action') && ($styleid = $input->getInt('styleid', '')) && $tpl->id != $styleid) {
				$db    = JFactory::getDbo();
				$query = $db->getQuery(true);
				$query->select('template, params');
				$query->from('#__template_styles');
				$query->where('client_id = 0');
				$query->where('id = ' . $styleid);
				
				$db->setQuery($query);
				$tpl = $db->loadObject();
				
				if ($tpl) {
					$registry = new JRegistry;
					$registry->loadString($tpl->params);
					$tpl->params = $registry;
				}
				
				if (!$tpl) {
					die(json_encode(array(
						'error' => JText::_('T3_MSG_UNKNOW_ACTION')
					)));
				}
			}
			
		} else {
			
			$tplid = $input->getCmd('view') == 'style' ? $input->getCmd('id', 0) : false;
			if (!$tplid) {
				die(json_encode(array(
					'error' => JText::_('T3_MSG_UNKNOW_ACTION')
				)));
			}
			
			$cache = JFactory::getCache('com_templates', '');
			if (!$templates = $cache->get('t3tpl')) {
				// Load styles
				$db    = JFactory::getDbo();
				$query = $db->getQuery(true);
				$query->select('id, home, template, s.params');
				$query->from('#__template_styles as s');
				$query->where('s.client_id = 0');
				$query->where('e.enabled = 1');
				$query->leftJoin('#__extensions as e ON e.element=s.template AND e.type=' . $db->quote('template') . ' AND e.client_id=s.client_id');
				
				$db->setQuery($query);
				$templates = $db->loadObjectList('id');
				foreach ($templates as &$template) {
					$registry = new JRegistry;
					$registry->loadString($template->params);
					$template->params = $registry;
				}
				$cache->store($templates, 't3tpl');
			}
			
			if (isset($templates[$tplid])) {
				$tpl = $templates[$tplid];
			} else {
				$tpl = $templates[0];
			}
		}
		
		//load language for template
		JFactory::getLanguage()->load('tpl_' . T3_TEMPLATE, JPATH_SITE);
		
		//clean all unnecessary datas
		if(ob_get_length()){
			@ob_end_clean();
		}
		$t3app  = T3::getSite($tpl);
		$layout = $t3app->getLayout();
		$t3app->loadLayout($layout);
		$lbuffer = ob_get_clean();
		die($lbuffer);
	}
	
	public static function save()
	{
		// Initialize some variables
		$input    = JFactory::getApplication()->input;
		$template = $input->getCmd('template');
		$layout   = $input->getCmd('layout');
		if (!$template || !$layout) {
			return self::error(JText::_('T3_LAYOUT_INVALID_DATA_TO_SAVE'));
		}

		// store layout configuration into custom directory
    $file = T3Path::getLocalPath ('etc/layout/' . $layout . '.ini');

		if (!is_dir(dirname($file))) {
			JFolder::create(dirname($file));
		}
		
		$params = new JRegistry();
		$params->loadObject($_POST);
		
		$data = $params->toString('INI');
		if (!@JFile::write($file, $data)) {
			return self::error(JText::_('T3_LAYOUT_OPERATION_FAILED'));
		}
		
		return self::response(array(
			'successful' => JText::sprintf('T3_LAYOUT_SAVE_SUCCESSFULLY', $layout),
			'layout' => $layout,
			'type' => 'new'
		));
	}
	
	public static function copy()
	{
		// Initialize some variables
		$input    = JFactory::getApplication()->input;
		$template = $input->getCmd('template');
		$original = $input->getCmd('original');
		$layout   = $input->getCmd('layout');
		
		//safe name
		$layout = JApplicationHelper::stringURLSafe($layout);
		
		if (!$template || !$original || !$layout) {
			return self::error(JText::_('T3_LAYOUT_INVALID_DATA_TO_SAVE'));
		}


		// clone to CUSTOM dir
		$source = T3Path::getPath('tpls/' . $original . '.php');
    $dest   = T3Path::getLocalPath('tpls/' . $layout . '.php');
		$confsource = T3Path::getPath('etc/layout/'. $layout . '.ini');
    $confdest   = T3Path::getLocalPath('etc/layout/'. $layout . '.ini');

		$params = new JRegistry();
		$params->loadObject($_POST);
		
		$data = $params->toString('INI');
		
		if (!is_dir(dirname($confdest))) {
			JFolder::create(dirname($confdest));
		}

		if (!is_dir(dirname($dest))) {
			JFolder::create(dirname($dest));
		}
		
		if ($data && !@JFile::write($confdest, $data)) {
			return self::error(JText::_('T3_LAYOUT_OPERATION_FAILED'));
		}
		
		// Check if original file exists
		if (JFile::exists($source)) {
			// Check if the desired file already exists
			if (!JFile::exists($dest)) {
				if (!JFile::copy($source, $dest)) {
					return self::error(JText::_('T3_LAYOUT_OPERATION_FAILED'));
				}
				//clone configuration file, we only copy if the target file does not exist
				if (!JFile::exists($confdest) && JFile::exists($confsource)) {
					JFile::copy($confsource, $confdest);
				}
			} else {
				return self::error(JText::_('T3_LAYOUT_EXISTED'));
			}
		} else {
			return self::error(JText::_('T3_LAYOUT_NOT_FOUND'));
		}
		
		return self::response(array(
			'successful' => JText::_('T3_LAYOUT_SAVE_SUCCESSFULLY'),
			'original' => $original,
			'layout' => $layout,
			'type' => 'clone'
		));
	}
	
	public static function delete()
	{
		// Initialize some variables
		$input    = JFactory::getApplication()->input;
		$layout   = $input->getCmd('layout');
		$template = $input->getCmd('template');
		
		if (!$layout) {
			return self::error(JText::_('T3_LAYOUT_UNKNOW_ACTION'));
		}
		
		// delete custom layout    
		$layoutfile = T3Path::getLocalPath('tpls/' . $layout . '.php');
		$initfile   = T3Path::getLocalPath('etc/layout/' . $layout . '.ini');

		if (!@JFile::delete($layoutfile) || !@JFile::delete($initfile)) {
			return self::error(JText::_('T3_LAYOUT_DELETE_FAIL'));
		} else {
			return self::response(array(
				'successful' => JText::_('T3_LAYOUT_DELETE_SUCCESSFULLY'),
				'layout' => $layout,
				'type' => 'delete'
			));
		}
	}

	public static function purge()
	{
		// Initialize some variables
		$input    = JFactory::getApplication()->input;
		$layout   = $input->getCmd('layout');
		$template = $input->getCmd('template');

		if (!$layout) {
			return self::error(JText::_('T3_LAYOUT_UNKNOW_ACTION'));
		}

		// delete custom layout
		$layoutfile = T3Path::getLocalPath('tpls/' . $layout . '.php');
		$initfile   = T3Path::getLocalPath('etc/layout/' . $layout . '.ini');

		// delete default layout
		$defaultlayoutfile = T3_TEMPLATE_PATH . '/tpls/' . $layout . '.php';
		$defaultinitfile   = T3_TEMPLATE_PATH . '/etc/layout/' . $layout . '.ini';

		if (!@JFile::delete($layoutfile) || !@JFile::delete($defaultlayoutfile)
        || !@JFile::delete($initfile) || !@JFile::delete($defaultinitfile)
      ) {
			return self::error(JText::_('T3_LAYOUT_DELETE_FAIL'));
		} else {
			return self::response(array(
				'successful' => JText::_('T3_LAYOUT_DELETE_SUCCESSFULLY'),
				'layout' => $layout,
				'type' => 'delete'
			));
		}
	}
	
	public static function getTplPositions($clientId = 0, $template = '')
	{
		$positions = array();
		
		$templateBaseDir = $clientId ? JPATH_ADMINISTRATOR : JPATH_SITE;
		$filePath        = JPath::clean($templateBaseDir . '/templates/' . $template . '/templateDetails.xml');
		
		if (is_file($filePath)) {
			// Read the file to see if it's a valid component XML file
			$xml = simplexml_load_file($filePath);
			if (!$xml) {
				return false;
			}
			
			// Check for a valid XML root tag.
			
			// Extensions use 'extension' as the root tag.  Languages use 'metafile' instead
			
			if ($xml->getName() != 'extension' && $xml->getName() != 'metafile') {
				unset($xml);
				return false;
			}
			
			$positions = (array) $xml->positions;
			
			if (isset($positions['position'])) {
				$positions = $positions['position'];
			} else {
				$positions = array();
			}
		}
		
		return $positions;
	}
	
	public static function getPositions()
	{
		
		$template = T3_TEMPLATE;
		$path     = JPATH_SITE;
		$lang     = JFactory::getLanguage();
		
		$clientId = 0;
		$state    = 1;
		
		$templates      = array_keys(self::getTemplates($clientId, $state));
		$templateGroups = array();
		
		// Add positions from templates
		foreach ($templates as $template) {
			$options = array();
			
			$positions = self::getTplPositions($clientId, $template);
			if (is_array($positions))
				foreach ($positions as $position) {
					$text      = self::getTranslatedModulePosition($clientId, $template, $position) . ' [' . $position . ']';
					$options[] = self::createOption($position, $text);
				}
			
			$templateGroups[$template] = self::createOptionGroup(ucfirst($template), $options);
		}
		
		// Add custom position to options
		$customGroupText                  = JText::_('T3_LAYOUT_CUSTOM_POSITION');
		$customPositions                  = self::getDbPositions($clientId);
		$templateGroups[$customGroupText] = self::createOptionGroup($customGroupText, $customPositions);
		
		return JHtml::_('select.groupedlist', $templateGroups, '', array(
			'id' => 'tpl-positions-list',
			'list.select' => ''
		));
		
	}
	
	public static function getDbPositions($clientId)
	{
		$db    = JFactory::getDbo();
		$query = $db->getQuery(true)
			->select('DISTINCT(position)')
			->from('#__modules')
			->where($db->quoteName('client_id') . ' = ' . (int) $clientId)->order('position');
		
		$db->setQuery($query);
		
		try {
			$positions = $db->loadColumn();
			$positions = is_array($positions) ? $positions : array();
		}
		catch (RuntimeException $e) {
			JError::raiseWarning(500, $e->getMessage());
			return;
		}
		
		// Build the list
		$options = array();
		foreach ($positions as $position) {
			if ($position) {
				$options[] = JHtml::_('select.option', $position, $position);
			}
		}
		return $options;
	}
	
	/**
	 * Create and return a new Option
	 *
	 * @param   string  $value  The option value [optional]
	 * @param   string  $text   The option text [optional]
	 *
	 * @return  object  The option as an object (stdClass instance)
	 *
	 * @since   3.0
	 */
	public static function createOption($value = '', $text = '')
	{
		if (empty($text)) {
			$text = $value;
		}
		
		$option        = new stdClass;
		$option->value = $value;
		$option->text  = $text;
		
		return $option;
	}
	
	/**
	 * Create and return a new Option Group
	 *
	 * @param   string  $label    Value and label for group [optional]
	 * @param   array   $options  Array of options to insert into group [optional]
	 *
	 * @return  array  Return the new group as an array
	 *
	 * @since   3.0
	 */
	public static function createOptionGroup($label = '', $options = array())
	{
		$group          = array();
		$group['value'] = $label;
		$group['text']  = $label;
		$group['items'] = $options;
		
		return $group;
	}
	
	/**
	 * Check if the string was translated
	 *
	 * @param   string  $langKey  Language file text key
	 * @param   string  $text     The "translated" text to be checked
	 *
	 * @return  boolean  Return true for translated text
	 *
	 * @since   3.0
	 */
	public static function isTranslatedText($langKey, $text)
	{
		return $text !== $langKey;
	}
	
	/**
	 * Return a translated module position name
	 *
	 * @param   string  $template  Template name
	 * @param   string  $position  Position name
	 *
	 * @return  string  Return a translated position name
	 *
	 * @since   3.0
	 */
	public static function getTranslatedModulePosition($clientId, $template, $position)
	{
		// Template translation
		$lang = JFactory::getLanguage();
		$path = $clientId ? JPATH_ADMINISTRATOR : JPATH_SITE;
		
		$lang->load('tpl_' . $template . '.sys', $path, null, false, false) 
			|| $lang->load('tpl_' . $template . '.sys', $path . '/templates/' . $template, null, false, false) 
			|| $lang->load('tpl_' . $template . '.sys', $path, $lang->getDefault(), false, false) 
			|| $lang->load('tpl_' . $template . '.sys', $path . '/templates/' . $template, $lang->getDefault(), false, false);
		
		$langKey = strtoupper('TPL_' . $template . '_POSITION_' . $position);
		$text    = JText::_($langKey);
		
		// Avoid untranslated strings
		if (!self::isTranslatedText($langKey, $text)) {
			// Modules component translation
			$langKey = strtoupper('COM_MODULES_POSITION_' . $position);
			$text    = JText::_($langKey);
			
			// Avoid untranslated strings
			if (!self::isTranslatedText($langKey, $text)) {
				// Try to humanize the position name
				$text = ucfirst(preg_replace('/^' . $template . '\-/', '', $position));
				$text = ucwords(str_replace(array(
					'-',
					'_'
				), ' ', $text));
			}
		}
		
		return $text;
	}
	
	/**
	 * Return a list of templates
	 *
	 * @param   integer  $clientId  Client ID
	 * @param   string   $state     State
	 * @param   string   $template  Template name
	 *
	 * @return  array  List of templates
	 */
	public static function getTemplates($clientId = 0, $state = '', $template = '')
	{
		$db = JFactory::getDbo();
		
		// Get the database object and a new query object.
		$query = $db->getQuery(true);
		
		// Build the query.
		$query
			->select('element, name, enabled')
			->from('#__extensions')
			->where('client_id = ' . (int) $clientId)
			->where('type = ' . $db->quote('template'));

		if ($state != '') {
			$query->where('enabled = ' . $db->quote($state));
		}
		
		if ($template != '') {
			$query->where('element = ' . $db->quote($template));
		}
		
		// Set the query and load the templates.
		$db->setQuery($query);
		$templates = $db->loadObjectList('element');
		return $templates;
	}
}admin/megamenu.php000060400000024242152455303040010144 0ustar00<?php

use Joomla\Registry\Registry;

/** 
 *------------------------------------------------------------------------------
 * @package       T3 Framework for Joomla!
 *------------------------------------------------------------------------------
 * @copyright     Copyright (C) 2004-2013 JoomlArt.com. All Rights Reserved.
 * @license       GNU General Public License version 2 or later; see LICENSE.txt
 * @authors       JoomlArt, JoomlaBamboo, (contribute to this project at github 
 *                & Google group to become co-author)
 * @Google group: https://groups.google.com/forum/#!forum/t3fw
 * @Link:         http://t3-framework.org 
 *------------------------------------------------------------------------------
 */

class T3AdminMegamenu
{
	public static function display()
	{
		T3::import('menu/megamenu');
		$input = JFactory::getApplication()->input;
		
		//params
		$tplparams = T3::getTplParams();
		
		//menu type
		$menutype = $input->get('t3menu', 'mainmenu');
		
		//accessLevel
		$t3acl       = (int) $input->get('t3acl', 1);
		$accessLevel = array(1, $t3acl);
		if(in_array(3, $accessLevel)){
			$accessLevel[] = 2;
		}
		$accessLevel = array_unique($accessLevel);
		sort($accessLevel);
		
		//languages
		$languages = array(trim($input->get('t3lang', '*')));
		if($languages[0] != '*'){
			$languages[] = '*';
		}

		//check config
		$currentconfig = $tplparams instanceof Registry ? json_decode($tplparams->get('mm_config', ''), true) : null;
		$mmkey         = $menutype . (($t3acl == 1) ? '' : '-' . $t3acl);
		$mmconfig      = array();

		if($currentconfig){
			for ($i = $t3acl; $i >= 1; $i--) {
				$tmmkey = $menutype . (($i == 1) ? '' : '-' . $i);
				if(isset($currentconfig[$tmmkey])){
					$mmconfig = $currentconfig[$tmmkey];
					break;
				}
			}
		}

		if(!is_array($mmconfig)){
			$mmconfig = array();
		}

		$mmconfig['editmode'] = true;
		$mmconfig['access']   = $accessLevel;
		$mmconfig['language'] = $languages;

		//build the menu
		$menu   = new T3MenuMegamenu($menutype, $mmconfig);
		$buffer = $menu->render(true);
		
		// replace image path
		$base      = JURI::base(true) . '/';
		$protocols = '[a-zA-Z0-9]+:'; //To check for all unknown protocals (a protocol must contain at least one alpahnumeric fillowed by :
		$regex     = '#(src)="(?!/|' . $protocols . '|\#|\')([^"]*)"#m';
		$buffer    = preg_replace($regex, "$1=\"$base\$2\"", $buffer);
		
		//remove invisibile content	
		$buffer = preg_replace(array(
			'@<style[^>]*?>.*?</style>@siu',
			'@<script[^>]*?.*?</script>@siu'
		), array(
			'',
			''
		), $buffer);

		//output the megamenu key to save
		echo $buffer . '<input id="megamenu-key" type="hidden" name="mmkey" value="' . $mmkey . '"/>';
	}

	public static function delete(){
		$input         = JFactory::getApplication()->input;
		$template      = $input->get('template');
		$mmkey         = $input->get('mmkey', $input->get('menutype', 'mainmenu'));
		$tplparams     = T3::getTplParams();
		
		$currentconfig = $tplparams instanceof Registry ? json_decode($tplparams->get('mm_config', ''), true) : null;

		if (!is_array($currentconfig)) {
			$currentconfig = array();
		}

		//delete it
		if(isset($currentconfig[$mmkey])){
			unset($currentconfig[$mmkey]);
		}
		$currentconfig = json_encode($currentconfig, JSON_UNESCAPED_UNICODE);
		
		//get all other styles that have the same template
		$db    = JFactory::getDBO();
		$query = $db->getQuery(true);
		$query
			->select('*')
			->from('#__template_styles')
			->where('template=' . $db->quote($template));

		$db->setQuery($query);
		$themes = $db->loadObjectList();
		$return = true;
		
		foreach($themes as $theme){
			$registry = new Registry;
			$registry->loadString($theme->params);

			//overwrite with new value
			$registry->set('mm_config', $currentconfig);

			$query = $db->getQuery(true);
			$query
				->update('#__template_styles')
				->set('params =' . $db->quote($registry->toString()))
				->where('id =' . (int)$theme->id);

			$db->setQuery($query);
			$return = $db->execute() && $return;
		}

		die(json_encode(array(
					'status' => $return,
					'message' => JText::_($return ? 'T3_NAVIGATION_DELETE_SUCCESSFULLY' : 'T3_NAVIGATION_DELETE_FAILED')
				)
			)
		);
	}
	
	public static function save()
	{
		$input         = JFactory::getApplication()->input;
		$template      = $input->get('template');
		$mmconfig      = $input->getString('config');
		$mmkey         = $input->get('mmkey', $input->get('menutype', 'mainmenu'));
		$tplparams     = T3::getTplParams();

		if(!is_null($mmconfig)){
			$mmconfig  = stripslashes($mmconfig);
		} 
		
		$currentconfig = $tplparams instanceof Registry ? $tplparams->get('mm_config', '') : null;
		$_reg = new Registry;
		if(getType(json_decode($currentconfig, true)) == "array"){
			$_reg->loadArray(json_decode($currentconfig, true));
		}
		$_reg->set($mmkey, json_decode($mmconfig, true));

		$mm_config = $_reg->toString();

		//get all other styles that have the same template
		$db    = JFactory::getDBO();
		$query = $db->getQuery(true);
		$query
			->select('*')
			->from('#__template_styles')
			->where('template=' . $db->quote($template));

		$db->setQuery($query);
		$themes = $db->loadObjectList();
		$return = true;
		
		foreach($themes as $theme){
			$registry = new Registry;
			$registry->loadString($theme->params);

			//overwrite with new value
			$registry->set('mm_config', $mm_config);

			$query = $db->getQuery(true);
			$query
				->update('#__template_styles')
				->set('params =' . $db->quote($registry->toString()))
				->where('id =' . (int)$theme->id);

			$db->setQuery($query);
			$return = $db->execute() && $return;
		}

		die(json_encode(array(
					'status' => $return,
					'message' => JText::_($return ? 'T3_NAVIGATION_SAVE_SUCCESSFULLY' : 'T3_NAVIGATION_SAVE_FAILED')
				)
			)
		);
	}

	/**
	 *
	 * Ge all available modules
	 */
	public static function menus()
	{
		$db = JFactory::getDbo();
		$query = $db->getQuery(true)
			->select('menutype AS value, title AS text')
			->from($db->quoteName('#__menu_types'))
			->order('title');
		$db->setQuery($query);
		$menus = $db->loadObjectList();

		$query = $db->getQuery(true)
			->select('menutype, language')
			->from($db->quoteName('#__menu'))
			->where('published = 1')
			->group('menutype');
		$db->setQuery($query);
		$menulangs = $db->loadAssocList('menutype');

		$query = $db->getQuery(true)
			->select('menutype, language')
			->from($db->quoteName('#__menu'))
			->where('home = 1 and published = 1');
		$db->setQuery($query);
		$homelangs = $db->loadAssocList('menutype');

		if(is_array($menulangs) && is_array($homelangs)){
			$menulangs = array_merge($menulangs, $homelangs);
		}

		if(is_array($menus) && is_array($menulangs)){
			foreach ($menus as $menu) {
				$menu->text = $menu->text . ' [' . $menu->value . ']';
				$menu->language = isset($menulangs[$menu->value]) ? $menulangs[$menu->value]['language'] : '*';
			}
		}
		
		return is_array($menus) ? $menus : array();
	}

	/**
	 *
	 * Ge all support access levels
	 */
	public static function access()
	{
		$db = JFactory::getDbo();
		$query = $db->getQuery(true);

		$query->select('a.id AS value, a.title AS text');
		$query->from('#__viewlevels AS a');
		$query->group('a.id, a.title, a.ordering');
		$query->order('a.ordering ASC');
		$query->order($query->qn('title') . ' ASC');
		$query->where('a.id in (1,2,3) or a.title = ' . $db->quote('Guest')); //we only support Public, Registered, Special, Guest
		
		// Get the options.
		$db->setQuery($query);
		$options = $db->loadObjectList();
		
		return is_array($options) ? $options : array();
	}

	/**
	 *
	 * Ge all available modules
	 */
	public static function modules()
	{
		$db    = JFactory::getDbo();
		$query = $db->getQuery(true);
		$query
			->select('id, title, module, position')
			->from('#__modules')
			->where('published = 1')
			->where('client_id = 0')
			->order('title');
		$db->setQuery($query);
		$modules = $db->loadObjectList();
		
		return is_array($modules) ? $modules : array();
	}
	
	/**
	 *
	 * Show thememagic form
	 */
	public static function megamenu()
	{
		$tplparams = T3::getTplParams();
		
		//$url = JFactory::getURI();
		$url = JUri::getInstance();
		$url->delVar('t3action');
		$url->delVar('t3task');
		$referer  = $url->toString();
		$template = T3_TEMPLATE;
		$styleid  = JFactory::getApplication()->input->getCmd('id');

		$mm_type  = ($tplparams && $tplparams instanceof Registry) ? $tplparams->get('mm_type', '') : null;

		//Keepalive
		$config      = JFactory::getConfig();
		$lifetime    = ($config->get('lifetime') * 60000);
		$refreshTime = ($lifetime <= 60000) ? 30000 : $lifetime - 60000;
		
		// Refresh time is 1 minute less than the liftime assined in the configuration.php file.
		// The longest refresh period is one hour to prevent integer overflow.
		if ($refreshTime > 3600000 || $refreshTime <= 0) {
			$refreshTime = 3600000;
		}

		//check config
		$currentconfig = ($tplparams && $tplparams instanceof Registry) ? $tplparams->get('mm_config', '') : null;
		if(!$currentconfig){
			$currentconfig = '"{}"';
		}
		
		include T3_ADMIN_PATH . '/admin/megamenu/megamenu.tpl.php';
		
		exit;
	}

	/**
	 * Copy from Joomla 3.x
	 */
	public static function tooltipText($title = '', $content = '', $translate = 1, $escape = 1)
	{
	  // Return empty in no title or content is given.
	  if ($title == '' && $content == '')
	  {
	    return '';
	  }

	  // Split title into title and content if the title contains '::' (old Mootools format).
	  if ($content == '' && !(strpos($title, '::') === false))
	  {
	    list($title, $content) = explode('::', $title, 2);
	  }

	  // Pass texts through the JText.
	  if ($translate)
	  {
	    $title = JText::_($title);
	    $content = JText::_($content);
	  }

	  // Escape the texts.
	  if ($escape)
	  {
	    $title = str_replace('"', '&quot;', $title);
	    $content = str_replace('"', '&quot;', $content);
	  }

	  // Return only the content if no title is given.
	  if ($title == '')
	  {
	    return $content;
	  }

	  // Return only the title if title and text are the same.
	  if ($title == $content)
	  {
	    return '<strong>' . $title . '</strong>';
	  }

	  // Return the formated sting combining the title and  content.
	  if ($content != '')
	  {
	    return '<strong>' . $title . '</strong><br />' . $content;
	  }

	  // Return only the title.
	  return $title;
	}
}
gfont/T3GFont.php000060400000011201152455303040007606 0ustar00<?php
/** 
 *------------------------------------------------------------------------------
 * @package       T3 Framework for Joomla!
 *------------------------------------------------------------------------------
 * @copyright     Copyright (C) 2004-2013 JoomlArt.com. All Rights Reserved.
 * @license       GNU General Public License version 2 or later; see LICENSE.txt
 * @authors       JoomlArt, JoomlaBamboo, (contribute to this project at github 
 *                & Google group to become co-author)
 * @Google group: https://groups.google.com/forum/#!forum/t3fw
 * @Link:         http://t3-framework.org 
 *------------------------------------------------------------------------------
 */

// no direct access
defined('_JEXEC') or die('Restricted access');

/**
 * T3 Google Service utility class
 *
 * @package     T3
 * @subpackage  Google service
 */

class T3GService
{
	
	protected static $gfontcache = 'gfont.dat';

	/**
	 * Get font properties by name
	 *
	 * @return void
	 */
	public static function getFontProperties()
	{
		$input = JFactory::getApplication()->input;

		$template = $input->getCmd('template');
		$fontname = $input->getCmd('fontname');
		
		// Get gfont path
		$fontpath = self::getFontPath($template);
		// Get font data
		if ($fontpath !== false) {
			$data = @file_get_contents($fontpath);
			// Check to update font
			$idx  = strpos($data, '#');
			if ($idx !== false) {
				// Seperate time & json font list
				$time = (int) substr($data, 0, $idx);
				$data = substr($data, $idx + 1);
				// Check if not update 3 days => update
				if (time() - $time > 3 * 86400) {
					// Get local font path
					$fontpath = self::getFontPath($template, self::$gfontcache, true);
					// Update font list
					$status   = self::updateFontList($fontpath);
					// If success, re-get font list
					if ($status) {
						$data = @file_get_contents($fontpath);
						$idx  = strpos($data, '#');
						if ($idx !== false) {
							$data = substr($data, $idx + 1);
						}
					}
				}
			}

			$result = '';

			if($data){
				// Parse fonts information
				$font   = json_decode($data);
				$items  = $font->items;
				// Find suitable font by fontname
				foreach ($items as $item) {
					if (strcasecmp($fontname, $item->family) == 0) {
						$result = $item;
						break;
					}
				}
			}

		} else {
			$result = '';
		}
		
		echo json_encode($result);
		exit;
	}
	
	
	/**
	 * Get font list
	 *
	 * @return void
	 */
	function getFontList()
	{
		$input = JFactory::getApplication()->input;

		$template = $input->getCmd('template');
		$fontname = $input->getCmd('fontname');

		// Get gfont path
		$fontpath = self::getFontPath($template);
		if ($fontpath !== false) {
			// Get font list
			$data = @file_get_contents($fontpath);
			// Remove time before json data
			$idx  = strpos($data, '#');
			if ($idx !== false) {
				$data = substr($data, $idx + 1);
			}
			// Parse data
			$font    = json_decode($data);
			$items   = $font->items;
			$result  = array();
			$pattern = '/^' . $fontname . '.*/i';
			// Find suitable font by fontname
			foreach ($items as $item) {
				if (preg_match($pattern, $item->family)) {
					$result[] = $item->family;
				}
			}
		} else {
			$result = array();
		}

		echo json_encode($result);
		exit;
	}
	
	/**
	 * Get gfont path
	 *
	 * @param string $template  Template name
	 * @param string $filename  Filename include extension
	 * @param bool   $local     Indicate get local path or not
	 *
	 * @return mixed  Gfont file path if found, otherwise FALSE
	 */
	function getFontPath($template, $filename = false)
	{
		if(!$filename){
			$filename = self::$gfontcache;
		}

		// Check to sure that template is using new folder structure
		// If etc folder exists, considered as template is using new folder structure
		$filepath = JPATH_SITE . '/templates/' . $template . '/etc';
		if (@is_dir($filepath)) {
			$filepath .= '/' . $filename;
		}

		// Check file exists or not
		if (@is_file($filepath)) {
			return $filepath;
		}

		// Check file in base
		$filepath = T3_PATH . '/etc/' . $filename;
		if (@is_file($filepath)) {
			return $filepath;
		}
		
		// Can not find google font file
		return false;
	}
	
	/**
	 * Update font list from google web font page
	 *
	 * @param string $path  File path store font list
	 *
	 * @return bool  TRUE if update success, otherwise FALSE
	 */
	function updateFontList($path)
	{
		$key     = 'AIzaSyA6_mK8ERGaR4_dhK6tJVEdvJPQEdwULWg';
		$url     = 'https://www.googleapis.com/webfonts/v1/webfonts?key=' . $key;
		$content = @file_get_contents($url);
		if (!empty($content)) {
			$content = time() . '#' . $content;
			$result  = file_put_contents($path, $content);
			return ($result !== false);
		}
		return false;
	}
}helper.php000060400000001737152455311230006541 0ustar00<?php
/**
 * @package    Joomla.Administrator
 *
 * @copyright  (C) 2007 Open Source Matters, Inc. <https://www.joomla.org>
 * @license    GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Joomla! Administrator Application helper class.
 * Provide many supporting API functions.
 *
 * @since       1.5
 *
 * @deprecated  4.0 Deprecated without replacement
 */
class JAdministratorHelper
{
	/**
	 * Return the application option string [main component].
	 *
	 * @return  string  The component to access.
	 *
	 * @since   1.5
	 */
	public static function findOption()
	{
		$app = JFactory::getApplication();
		$option = strtolower($app->input->get('option'));

		$app->loadIdentity();
		$user = $app->getIdentity();

		if ($user->get('guest') || !$user->authorise('core.login.admin'))
		{
			$option = 'com_login';
		}

		if (empty($option))
		{
			$option = 'com_cpanel';
		}

		$app->input->set('option', $option);

		return $option;
	}
}
subtoolbar.php000060400000010423152455311230007426 0ustar00<?php
/**
 * @package    Joomla.Administrator
 *
 * @copyright  (C) 2014 Open Source Matters, Inc. <https://www.joomla.org>
 * @license    GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Utility class for the submenu.
 *
 * @package     Joomla.Administrator
 * @since       1.5
 * @deprecated  4.0  Use JHtmlSidebar instead.
 */
abstract class JSubMenuHelper
{
	/**
	 * Menu entries
	 *
	 * @var    array
	 * @since  3.0
	 * @deprecated  4.0
	 */
	protected static $entries = array();

	/**
	 * Filters
	 *
	 * @var    array
	 * @since  3.0
	 * @deprecated  4.0
	 */
	protected static $filters = array();

	/**
	 * Value for the action attribute of the form.
	 *
	 * @var    string
	 * @since  3.0
	 * @deprecated  4.0
	 */
	protected static $action = '';

	/**
	 * Method to add a menu item to submenu.
	 *
	 * @param   string   $name    Name of the menu item.
	 * @param   string   $link    URL of the menu item.
	 * @param   boolean  $active  True if the item is active, false otherwise.
	 *
	 * @return  void
	 *
	 * @since   1.5
	 * @deprecated  4.0  Use JHtmlSidebar::addEntry() instead.
	 */
	public static function addEntry($name, $link = '', $active = false)
	{
		try
		{
			JLog::add(
				sprintf('%s() is deprecated. Use JHtmlSidebar::addEntry() instead.', __METHOD__),
				JLog::WARNING,
				'deprecated'
			);
		}
		catch (RuntimeException $exception)
		{
			// Informational log only
		}

		self::$entries[] = array($name, $link, $active);
	}

	/**
	 * Returns an array of all submenu entries
	 *
	 * @return  array
	 *
	 * @since   3.0
	 * @deprecated  4.0  Use JHtmlSidebar::getEntries() instead.
	 */
	public static function getEntries()
	{
		try
		{
			JLog::add(
				sprintf('%s() is deprecated. Use JHtmlSidebar::getEntries() instead.', __METHOD__),
				JLog::WARNING,
				'deprecated'
			);
		}
		catch (RuntimeException $exception)
		{
			// Informational log only
		}

		return self::$entries;
	}

	/**
	 * Method to add a filter to the submenu
	 *
	 * @param   string   $label      Label for the menu item.
	 * @param   string   $name       name for the filter. Also used as id.
	 * @param   string   $options    options for the select field.
	 * @param   boolean  $noDefault  Don't show the label as the empty option
	 *
	 * @return  void
	 *
	 * @since   3.0
	 * @deprecated  4.0  Use JHtmlSidebar::addFilter() instead.
	 */
	public static function addFilter($label, $name, $options, $noDefault = false)
	{
		try
		{
			JLog::add(
				sprintf('%s() is deprecated. Use JHtmlSidebar::addFilter() instead.', __METHOD__),
				JLog::WARNING,
				'deprecated'
			);
		}
		catch (RuntimeException $exception)
		{
			// Informational log only
		}

		self::$filters[] = array('label' => $label, 'name' => $name, 'options' => $options, 'noDefault' => $noDefault);
	}

	/**
	 * Returns an array of all filters
	 *
	 * @return  array
	 *
	 * @since   3.0
	 * @deprecated  4.0  Use JHtmlSidebar::getFilters() instead.
	 */
	public static function getFilters()
	{
		try
		{
			JLog::add(
				sprintf('%s() is deprecated. Use JHtmlSidebar::getFilters() instead.', __METHOD__),
				JLog::WARNING,
				'deprecated'
			);
		}
		catch (RuntimeException $exception)
		{
			// Informational log only
		}

		return self::$filters;
	}

	/**
	 * Set value for the action attribute of the filter form
	 *
	 * @param   string  $action  Value for the action attribute of the form
	 *
	 * @return  void
	 *
	 * @since   3.0
	 * @deprecated  4.0  Use JHtmlSidebar::setAction() instead.
	 */
	public static function setAction($action)
	{
		try
		{
			JLog::add(
				sprintf('%s() is deprecated. Use JHtmlSidebar::setAction() instead.', __METHOD__),
				JLog::WARNING,
				'deprecated'
			);
		}
		catch (RuntimeException $exception)
		{
			// Informational log only
		}

		self::$action = $action;
	}

	/**
	 * Get value for the action attribute of the filter form
	 *
	 * @return  string  Value for the action attribute of the form
	 *
	 * @since   3.0
	 * @deprecated  4.0  Use JHtmlSidebar::getAction() instead.
	 */
	public static function getAction()
	{
		try
		{
			JLog::add(
				sprintf('%s() is deprecated. Use JHtmlSidebar::getAction() instead.', __METHOD__),
				JLog::WARNING,
				'deprecated'
			);
		}
		catch (RuntimeException $exception)
		{
			// Informational log only
		}

		return self::$action;
	}
}
jquery-2.1.3.min.js000060400000244540152455615060007660 0ustar00/*! jQuery v2.1.3 | (c) 2005, 2014 jQuery Foundation, Inc. | jquery.org/license */
!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k={},l=a.document,m="2.1.3",n=function(a,b){return new n.fn.init(a,b)},o=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,p=/^-ms-/,q=/-([\da-z])/gi,r=function(a,b){return b.toUpperCase()};n.fn=n.prototype={jquery:m,constructor:n,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=n.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return n.each(this,a,b)},map:function(a){return this.pushStack(n.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},n.extend=n.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||n.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(a=arguments[h]))for(b in a)c=g[b],d=a[b],g!==d&&(j&&d&&(n.isPlainObject(d)||(e=n.isArray(d)))?(e?(e=!1,f=c&&n.isArray(c)?c:[]):f=c&&n.isPlainObject(c)?c:{},g[b]=n.extend(j,f,d)):void 0!==d&&(g[b]=d));return g},n.extend({expando:"jQuery"+(m+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===n.type(a)},isArray:Array.isArray,isWindow:function(a){return null!=a&&a===a.window},isNumeric:function(a){return!n.isArray(a)&&a-parseFloat(a)+1>=0},isPlainObject:function(a){return"object"!==n.type(a)||a.nodeType||n.isWindow(a)?!1:a.constructor&&!j.call(a.constructor.prototype,"isPrototypeOf")?!1:!0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(a){var b,c=eval;a=n.trim(a),a&&(1===a.indexOf("use strict")?(b=l.createElement("script"),b.text=a,l.head.appendChild(b).parentNode.removeChild(b)):c(a))},camelCase:function(a){return a.replace(p,"ms-").replace(q,r)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=s(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(o,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(s(Object(a))?n.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){return null==b?-1:g.call(b,a,c)},merge:function(a,b){for(var c=+b.length,d=0,e=a.length;c>d;d++)a[e++]=b[d];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=s(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(c=a[b],b=a,a=c),n.isFunction(a)?(e=d.call(arguments,2),f=function(){return a.apply(b||this,e.concat(d.call(arguments)))},f.guid=a.guid=a.guid||n.guid++,f):void 0},now:Date.now,support:k}),n.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function s(a){var b=a.length,c=n.type(a);return"function"===c||n.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var t=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+1*new Date,v=a.document,w=0,x=0,y=hb(),z=hb(),A=hb(),B=function(a,b){return a===b&&(l=!0),0},C=1<<31,D={}.hasOwnProperty,E=[],F=E.pop,G=E.push,H=E.push,I=E.slice,J=function(a,b){for(var c=0,d=a.length;d>c;c++)if(a[c]===b)return c;return-1},K="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",L="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",N=M.replace("w","w#"),O="\\["+L+"*("+M+")(?:"+L+"*([*^$|!~]?=)"+L+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+N+"))|)"+L+"*\\]",P=":("+M+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+O+")*)|.*)\\)|)",Q=new RegExp(L+"+","g"),R=new RegExp("^"+L+"+|((?:^|[^\\\\])(?:\\\\.)*)"+L+"+$","g"),S=new RegExp("^"+L+"*,"+L+"*"),T=new RegExp("^"+L+"*([>+~]|"+L+")"+L+"*"),U=new RegExp("="+L+"*([^\\]'\"]*?)"+L+"*\\]","g"),V=new RegExp(P),W=new RegExp("^"+N+"$"),X={ID:new RegExp("^#("+M+")"),CLASS:new RegExp("^\\.("+M+")"),TAG:new RegExp("^("+M.replace("w","w*")+")"),ATTR:new RegExp("^"+O),PSEUDO:new RegExp("^"+P),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+L+"*(even|odd|(([+-]|)(\\d*)n|)"+L+"*(?:([+-]|)"+L+"*(\\d+)|))"+L+"*\\)|)","i"),bool:new RegExp("^(?:"+K+")$","i"),needsContext:new RegExp("^"+L+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+L+"*((?:-\\d)?\\d*)"+L+"*\\)|)(?=[^-]|$)","i")},Y=/^(?:input|select|textarea|button)$/i,Z=/^h\d$/i,$=/^[^{]+\{\s*\[native \w/,_=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ab=/[+~]/,bb=/'|\\/g,cb=new RegExp("\\\\([\\da-f]{1,6}"+L+"?|("+L+")|.)","ig"),db=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)},eb=function(){m()};try{H.apply(E=I.call(v.childNodes),v.childNodes),E[v.childNodes.length].nodeType}catch(fb){H={apply:E.length?function(a,b){G.apply(a,I.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function gb(a,b,d,e){var f,h,j,k,l,o,r,s,w,x;if((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,d=d||[],k=b.nodeType,"string"!=typeof a||!a||1!==k&&9!==k&&11!==k)return d;if(!e&&p){if(11!==k&&(f=_.exec(a)))if(j=f[1]){if(9===k){if(h=b.getElementById(j),!h||!h.parentNode)return d;if(h.id===j)return d.push(h),d}else if(b.ownerDocument&&(h=b.ownerDocument.getElementById(j))&&t(b,h)&&h.id===j)return d.push(h),d}else{if(f[2])return H.apply(d,b.getElementsByTagName(a)),d;if((j=f[3])&&c.getElementsByClassName)return H.apply(d,b.getElementsByClassName(j)),d}if(c.qsa&&(!q||!q.test(a))){if(s=r=u,w=b,x=1!==k&&a,1===k&&"object"!==b.nodeName.toLowerCase()){o=g(a),(r=b.getAttribute("id"))?s=r.replace(bb,"\\$&"):b.setAttribute("id",s),s="[id='"+s+"'] ",l=o.length;while(l--)o[l]=s+rb(o[l]);w=ab.test(a)&&pb(b.parentNode)||b,x=o.join(",")}if(x)try{return H.apply(d,w.querySelectorAll(x)),d}catch(y){}finally{r||b.removeAttribute("id")}}}return i(a.replace(R,"$1"),b,d,e)}function hb(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function ib(a){return a[u]=!0,a}function jb(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function kb(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function lb(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||C)-(~a.sourceIndex||C);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function mb(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function nb(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function ob(a){return ib(function(b){return b=+b,ib(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function pb(a){return a&&"undefined"!=typeof a.getElementsByTagName&&a}c=gb.support={},f=gb.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=gb.setDocument=function(a){var b,e,g=a?a.ownerDocument||a:v;return g!==n&&9===g.nodeType&&g.documentElement?(n=g,o=g.documentElement,e=g.defaultView,e&&e!==e.top&&(e.addEventListener?e.addEventListener("unload",eb,!1):e.attachEvent&&e.attachEvent("onunload",eb)),p=!f(g),c.attributes=jb(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=jb(function(a){return a.appendChild(g.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=$.test(g.getElementsByClassName),c.getById=jb(function(a){return o.appendChild(a).id=u,!g.getElementsByName||!g.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){var c="undefined"!=typeof a.getAttributeNode&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return"undefined"!=typeof b.getElementsByTagName?b.getElementsByTagName(a):c.qsa?b.querySelectorAll(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=$.test(g.querySelectorAll))&&(jb(function(a){o.appendChild(a).innerHTML="<a id='"+u+"'></a><select id='"+u+"-\f]' msallowcapture=''><option selected=''></option></select>",a.querySelectorAll("[msallowcapture^='']").length&&q.push("[*^$]="+L+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+L+"*(?:value|"+K+")"),a.querySelectorAll("[id~="+u+"-]").length||q.push("~="),a.querySelectorAll(":checked").length||q.push(":checked"),a.querySelectorAll("a#"+u+"+*").length||q.push(".#.+[+~]")}),jb(function(a){var b=g.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+L+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=$.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&jb(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",P)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=$.test(o.compareDocumentPosition),t=b||$.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===g||a.ownerDocument===v&&t(v,a)?-1:b===g||b.ownerDocument===v&&t(v,b)?1:k?J(k,a)-J(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,e=a.parentNode,f=b.parentNode,h=[a],i=[b];if(!e||!f)return a===g?-1:b===g?1:e?-1:f?1:k?J(k,a)-J(k,b):0;if(e===f)return lb(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)i.unshift(c);while(h[d]===i[d])d++;return d?lb(h[d],i[d]):h[d]===v?-1:i[d]===v?1:0},g):n},gb.matches=function(a,b){return gb(a,null,null,b)},gb.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(U,"='$1']"),!(!c.matchesSelector||!p||r&&r.test(b)||q&&q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return gb(b,n,null,[a]).length>0},gb.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},gb.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&D.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},gb.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},gb.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=gb.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=gb.selectors={cacheLength:50,createPseudo:ib,match:X,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(cb,db),a[3]=(a[3]||a[4]||a[5]||"").replace(cb,db),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||gb.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&gb.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return X.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&V.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(cb,db).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+L+")"+a+"("+L+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||"undefined"!=typeof a.getAttribute&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=gb.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e.replace(Q," ")+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){k=q[u]||(q[u]={}),j=k[a]||[],n=j[0]===w&&j[1],m=j[0]===w&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[w,n,m];break}}else if(s&&(j=(b[u]||(b[u]={}))[a])&&j[0]===w)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(s&&((l[u]||(l[u]={}))[a]=[w,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||gb.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?ib(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=J(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:ib(function(a){var b=[],c=[],d=h(a.replace(R,"$1"));return d[u]?ib(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),b[0]=null,!c.pop()}}),has:ib(function(a){return function(b){return gb(a,b).length>0}}),contains:ib(function(a){return a=a.replace(cb,db),function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:ib(function(a){return W.test(a||"")||gb.error("unsupported lang: "+a),a=a.replace(cb,db).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Z.test(a.nodeName)},input:function(a){return Y.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:ob(function(){return[0]}),last:ob(function(a,b){return[b-1]}),eq:ob(function(a,b,c){return[0>c?c+b:c]}),even:ob(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:ob(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:ob(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:ob(function(a,b,c){for(var d=0>c?c+b:c;++d<b;)a.push(d);return a})}},d.pseudos.nth=d.pseudos.eq;for(b in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})d.pseudos[b]=mb(b);for(b in{submit:!0,reset:!0})d.pseudos[b]=nb(b);function qb(){}qb.prototype=d.filters=d.pseudos,d.setFilters=new qb,g=gb.tokenize=function(a,b){var c,e,f,g,h,i,j,k=z[a+" "];if(k)return b?0:k.slice(0);h=a,i=[],j=d.preFilter;while(h){(!c||(e=S.exec(h)))&&(e&&(h=h.slice(e[0].length)||h),i.push(f=[])),c=!1,(e=T.exec(h))&&(c=e.shift(),f.push({value:c,type:e[0].replace(R," ")}),h=h.slice(c.length));for(g in d.filter)!(e=X[g].exec(h))||j[g]&&!(e=j[g](e))||(c=e.shift(),f.push({value:c,type:g,matches:e}),h=h.slice(c.length));if(!c)break}return b?h.length:h?gb.error(a):z(a,i).slice(0)};function rb(a){for(var b=0,c=a.length,d="";c>b;b++)d+=a[b].value;return d}function sb(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[u]||(b[u]={}),(h=i[d])&&h[0]===w&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function tb(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function ub(a,b,c){for(var d=0,e=b.length;e>d;d++)gb(a,b[d],c);return c}function vb(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function wb(a,b,c,d,e,f){return d&&!d[u]&&(d=wb(d)),e&&!e[u]&&(e=wb(e,f)),ib(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||ub(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:vb(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=vb(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?J(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=vb(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):H.apply(g,r)})}function xb(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=sb(function(a){return a===b},h,!0),l=sb(function(a){return J(b,a)>-1},h,!0),m=[function(a,c,d){var e=!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d));return b=null,e}];f>i;i++)if(c=d.relative[a[i].type])m=[sb(tb(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return wb(i>1&&tb(m),i>1&&rb(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(R,"$1"),c,e>i&&xb(a.slice(i,e)),f>e&&xb(a=a.slice(e)),f>e&&rb(a))}m.push(c)}return tb(m)}function yb(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,m,o,p=0,q="0",r=f&&[],s=[],t=j,u=f||e&&d.find.TAG("*",k),v=w+=null==t?1:Math.random()||.1,x=u.length;for(k&&(j=g!==n&&g);q!==x&&null!=(l=u[q]);q++){if(e&&l){m=0;while(o=a[m++])if(o(l,g,h)){i.push(l);break}k&&(w=v)}c&&((l=!o&&l)&&p--,f&&r.push(l))}if(p+=q,c&&q!==p){m=0;while(o=b[m++])o(r,s,g,h);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=F.call(i));s=vb(s)}H.apply(i,s),k&&!f&&s.length>0&&p+b.length>1&&gb.uniqueSort(i)}return k&&(w=v,j=t),r};return c?ib(f):f}return h=gb.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=xb(b[c]),f[u]?d.push(f):e.push(f);f=A(a,yb(e,d)),f.selector=a}return f},i=gb.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(cb,db),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=X.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(cb,db),ab.test(j[0].type)&&pb(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&rb(j),!a)return H.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,ab.test(a)&&pb(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=jb(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),jb(function(a){return a.innerHTML="<a href='#'></a>","#"===a.firstChild.getAttribute("href")})||kb("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&jb(function(a){return a.innerHTML="<input/>",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||kb("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),jb(function(a){return null==a.getAttribute("disabled")})||kb(K,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),gb}(a);n.find=t,n.expr=t.selectors,n.expr[":"]=n.expr.pseudos,n.unique=t.uniqueSort,n.text=t.getText,n.isXMLDoc=t.isXML,n.contains=t.contains;var u=n.expr.match.needsContext,v=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,w=/^.[^:#\[\.,]*$/;function x(a,b,c){if(n.isFunction(b))return n.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return n.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(w.test(b))return n.filter(b,a,c);b=n.filter(b,a)}return n.grep(a,function(a){return g.call(b,a)>=0!==c})}n.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?n.find.matchesSelector(d,a)?[d]:[]:n.find.matches(a,n.grep(b,function(a){return 1===a.nodeType}))},n.fn.extend({find:function(a){var b,c=this.length,d=[],e=this;if("string"!=typeof a)return this.pushStack(n(a).filter(function(){for(b=0;c>b;b++)if(n.contains(e[b],this))return!0}));for(b=0;c>b;b++)n.find(a,e[b],d);return d=this.pushStack(c>1?n.unique(d):d),d.selector=this.selector?this.selector+" "+a:a,d},filter:function(a){return this.pushStack(x(this,a||[],!1))},not:function(a){return this.pushStack(x(this,a||[],!0))},is:function(a){return!!x(this,"string"==typeof a&&u.test(a)?n(a):a||[],!1).length}});var y,z=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,A=n.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a[0]&&">"===a[a.length-1]&&a.length>=3?[null,a,null]:z.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||y).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof n?b[0]:b,n.merge(this,n.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:l,!0)),v.test(c[1])&&n.isPlainObject(b))for(c in b)n.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}return d=l.getElementById(c[2]),d&&d.parentNode&&(this.length=1,this[0]=d),this.context=l,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):n.isFunction(a)?"undefined"!=typeof y.ready?y.ready(a):a(n):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),n.makeArray(a,this))};A.prototype=n.fn,y=n(l);var B=/^(?:parents|prev(?:Until|All))/,C={children:!0,contents:!0,next:!0,prev:!0};n.extend({dir:function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&n(a).is(c))break;d.push(a)}return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),n.fn.extend({has:function(a){var b=n(a,this),c=b.length;return this.filter(function(){for(var a=0;c>a;a++)if(n.contains(this,b[a]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=u.test(a)||"string"!=typeof a?n(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&n.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?n.unique(f):f)},index:function(a){return a?"string"==typeof a?g.call(n(a),this[0]):g.call(this,a.jquery?a[0]:a):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(n.unique(n.merge(this.get(),n(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function D(a,b){while((a=a[b])&&1!==a.nodeType);return a}n.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return n.dir(a,"parentNode")},parentsUntil:function(a,b,c){return n.dir(a,"parentNode",c)},next:function(a){return D(a,"nextSibling")},prev:function(a){return D(a,"previousSibling")},nextAll:function(a){return n.dir(a,"nextSibling")},prevAll:function(a){return n.dir(a,"previousSibling")},nextUntil:function(a,b,c){return n.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return n.dir(a,"previousSibling",c)},siblings:function(a){return n.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return n.sibling(a.firstChild)},contents:function(a){return a.contentDocument||n.merge([],a.childNodes)}},function(a,b){n.fn[a]=function(c,d){var e=n.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=n.filter(d,e)),this.length>1&&(C[a]||n.unique(e),B.test(a)&&e.reverse()),this.pushStack(e)}});var E=/\S+/g,F={};function G(a){var b=F[a]={};return n.each(a.match(E)||[],function(a,c){b[c]=!0}),b}n.Callbacks=function(a){a="string"==typeof a?F[a]||G(a):n.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(b=a.memory&&l,c=!0,g=e||0,e=0,f=h.length,d=!0;h&&f>g;g++)if(h[g].apply(l[0],l[1])===!1&&a.stopOnFalse){b=!1;break}d=!1,h&&(i?i.length&&j(i.shift()):b?h=[]:k.disable())},k={add:function(){if(h){var c=h.length;!function g(b){n.each(b,function(b,c){var d=n.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&g(c)})}(arguments),d?f=h.length:b&&(e=c,j(b))}return this},remove:function(){return h&&n.each(arguments,function(a,b){var c;while((c=n.inArray(b,h,c))>-1)h.splice(c,1),d&&(f>=c&&f--,g>=c&&g--)}),this},has:function(a){return a?n.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],f=0,this},disable:function(){return h=i=b=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,b||k.disable(),this},locked:function(){return!i},fireWith:function(a,b){return!h||c&&!i||(b=b||[],b=[a,b.slice?b.slice():b],d?i.push(b):j(b)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!c}};return k},n.extend({Deferred:function(a){var b=[["resolve","done",n.Callbacks("once memory"),"resolved"],["reject","fail",n.Callbacks("once memory"),"rejected"],["notify","progress",n.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return n.Deferred(function(c){n.each(b,function(b,f){var g=n.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&n.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?n.extend(a,d):d}},e={};return d.pipe=d.then,n.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&n.isFunction(a.promise)?e:0,g=1===f?a:n.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&n.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var H;n.fn.ready=function(a){return n.ready.promise().done(a),this},n.extend({isReady:!1,readyWait:1,holdReady:function(a){a?n.readyWait++:n.ready(!0)},ready:function(a){(a===!0?--n.readyWait:n.isReady)||(n.isReady=!0,a!==!0&&--n.readyWait>0||(H.resolveWith(l,[n]),n.fn.triggerHandler&&(n(l).triggerHandler("ready"),n(l).off("ready"))))}});function I(){l.removeEventListener("DOMContentLoaded",I,!1),a.removeEventListener("load",I,!1),n.ready()}n.ready.promise=function(b){return H||(H=n.Deferred(),"complete"===l.readyState?setTimeout(n.ready):(l.addEventListener("DOMContentLoaded",I,!1),a.addEventListener("load",I,!1))),H.promise(b)},n.ready.promise();var J=n.access=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===n.type(c)){e=!0;for(h in c)n.access(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,n.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(n(a),c)})),b))for(;i>h;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f};n.acceptData=function(a){return 1===a.nodeType||9===a.nodeType||!+a.nodeType};function K(){Object.defineProperty(this.cache={},0,{get:function(){return{}}}),this.expando=n.expando+K.uid++}K.uid=1,K.accepts=n.acceptData,K.prototype={key:function(a){if(!K.accepts(a))return 0;var b={},c=a[this.expando];if(!c){c=K.uid++;try{b[this.expando]={value:c},Object.defineProperties(a,b)}catch(d){b[this.expando]=c,n.extend(a,b)}}return this.cache[c]||(this.cache[c]={}),c},set:function(a,b,c){var d,e=this.key(a),f=this.cache[e];if("string"==typeof b)f[b]=c;else if(n.isEmptyObject(f))n.extend(this.cache[e],b);else for(d in b)f[d]=b[d];return f},get:function(a,b){var c=this.cache[this.key(a)];return void 0===b?c:c[b]},access:function(a,b,c){var d;return void 0===b||b&&"string"==typeof b&&void 0===c?(d=this.get(a,b),void 0!==d?d:this.get(a,n.camelCase(b))):(this.set(a,b,c),void 0!==c?c:b)},remove:function(a,b){var c,d,e,f=this.key(a),g=this.cache[f];if(void 0===b)this.cache[f]={};else{n.isArray(b)?d=b.concat(b.map(n.camelCase)):(e=n.camelCase(b),b in g?d=[b,e]:(d=e,d=d in g?[d]:d.match(E)||[])),c=d.length;while(c--)delete g[d[c]]}},hasData:function(a){return!n.isEmptyObject(this.cache[a[this.expando]]||{})},discard:function(a){a[this.expando]&&delete this.cache[a[this.expando]]}};var L=new K,M=new K,N=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,O=/([A-Z])/g;function P(a,b,c){var d;if(void 0===c&&1===a.nodeType)if(d="data-"+b.replace(O,"-$1").toLowerCase(),c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:N.test(c)?n.parseJSON(c):c}catch(e){}M.set(a,b,c)}else c=void 0;return c}n.extend({hasData:function(a){return M.hasData(a)||L.hasData(a)},data:function(a,b,c){return M.access(a,b,c)
},removeData:function(a,b){M.remove(a,b)},_data:function(a,b,c){return L.access(a,b,c)},_removeData:function(a,b){L.remove(a,b)}}),n.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=M.get(f),1===f.nodeType&&!L.get(f,"hasDataAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=n.camelCase(d.slice(5)),P(f,d,e[d])));L.set(f,"hasDataAttrs",!0)}return e}return"object"==typeof a?this.each(function(){M.set(this,a)}):J(this,function(b){var c,d=n.camelCase(a);if(f&&void 0===b){if(c=M.get(f,a),void 0!==c)return c;if(c=M.get(f,d),void 0!==c)return c;if(c=P(f,d,void 0),void 0!==c)return c}else this.each(function(){var c=M.get(this,d);M.set(this,d,b),-1!==a.indexOf("-")&&void 0!==c&&M.set(this,a,b)})},null,b,arguments.length>1,null,!0)},removeData:function(a){return this.each(function(){M.remove(this,a)})}}),n.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=L.get(a,b),c&&(!d||n.isArray(c)?d=L.access(a,b,n.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=n.queue(a,b),d=c.length,e=c.shift(),f=n._queueHooks(a,b),g=function(){n.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return L.get(a,c)||L.access(a,c,{empty:n.Callbacks("once memory").add(function(){L.remove(a,[b+"queue",c])})})}}),n.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.length<c?n.queue(this[0],a):void 0===b?this:this.each(function(){var c=n.queue(this,a,b);n._queueHooks(this,a),"fx"===a&&"inprogress"!==c[0]&&n.dequeue(this,a)})},dequeue:function(a){return this.each(function(){n.dequeue(this,a)})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,b){var c,d=1,e=n.Deferred(),f=this,g=this.length,h=function(){--d||e.resolveWith(f,[f])};"string"!=typeof a&&(b=a,a=void 0),a=a||"fx";while(g--)c=L.get(f[g],a+"queueHooks"),c&&c.empty&&(d++,c.empty.add(h));return h(),e.promise(b)}});var Q=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,R=["Top","Right","Bottom","Left"],S=function(a,b){return a=b||a,"none"===n.css(a,"display")||!n.contains(a.ownerDocument,a)},T=/^(?:checkbox|radio)$/i;!function(){var a=l.createDocumentFragment(),b=a.appendChild(l.createElement("div")),c=l.createElement("input");c.setAttribute("type","radio"),c.setAttribute("checked","checked"),c.setAttribute("name","t"),b.appendChild(c),k.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,b.innerHTML="<textarea>x</textarea>",k.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue}();var U="undefined";k.focusinBubbles="onfocusin"in a;var V=/^key/,W=/^(?:mouse|pointer|contextmenu)|click/,X=/^(?:focusinfocus|focusoutblur)$/,Y=/^([^.]*)(?:\.(.+)|)$/;function Z(){return!0}function $(){return!1}function _(){try{return l.activeElement}catch(a){}}n.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=L.get(a);if(r){c.handler&&(f=c,c=f.handler,e=f.selector),c.guid||(c.guid=n.guid++),(i=r.events)||(i=r.events={}),(g=r.handle)||(g=r.handle=function(b){return typeof n!==U&&n.event.triggered!==b.type?n.event.dispatch.apply(a,arguments):void 0}),b=(b||"").match(E)||[""],j=b.length;while(j--)h=Y.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o&&(l=n.event.special[o]||{},o=(e?l.delegateType:l.bindType)||o,l=n.event.special[o]||{},k=n.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&n.expr.match.needsContext.test(e),namespace:p.join(".")},f),(m=i[o])||(m=i[o]=[],m.delegateCount=0,l.setup&&l.setup.call(a,d,p,g)!==!1||a.addEventListener&&a.addEventListener(o,g,!1)),l.add&&(l.add.call(a,k),k.handler.guid||(k.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,k):m.push(k),n.event.global[o]=!0)}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=L.hasData(a)&&L.get(a);if(r&&(i=r.events)){b=(b||"").match(E)||[""],j=b.length;while(j--)if(h=Y.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=n.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,m=i[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),g=f=m.length;while(f--)k=m[f],!e&&q!==k.origType||c&&c.guid!==k.guid||h&&!h.test(k.namespace)||d&&d!==k.selector&&("**"!==d||!k.selector)||(m.splice(f,1),k.selector&&m.delegateCount--,l.remove&&l.remove.call(a,k));g&&!m.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||n.removeEvent(a,o,r.handle),delete i[o])}else for(o in i)n.event.remove(a,o+b[j],c,d,!0);n.isEmptyObject(i)&&(delete r.handle,L.remove(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,m,o,p=[d||l],q=j.call(b,"type")?b.type:b,r=j.call(b,"namespace")?b.namespace.split("."):[];if(g=h=d=d||l,3!==d.nodeType&&8!==d.nodeType&&!X.test(q+n.event.triggered)&&(q.indexOf(".")>=0&&(r=q.split("."),q=r.shift(),r.sort()),k=q.indexOf(":")<0&&"on"+q,b=b[n.expando]?b:new n.Event(q,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=r.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+r.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:n.makeArray(c,[b]),o=n.event.special[q]||{},e||!o.trigger||o.trigger.apply(d,c)!==!1)){if(!e&&!o.noBubble&&!n.isWindow(d)){for(i=o.delegateType||q,X.test(i+q)||(g=g.parentNode);g;g=g.parentNode)p.push(g),h=g;h===(d.ownerDocument||l)&&p.push(h.defaultView||h.parentWindow||a)}f=0;while((g=p[f++])&&!b.isPropagationStopped())b.type=f>1?i:o.bindType||q,m=(L.get(g,"events")||{})[b.type]&&L.get(g,"handle"),m&&m.apply(g,c),m=k&&g[k],m&&m.apply&&n.acceptData(g)&&(b.result=m.apply(g,c),b.result===!1&&b.preventDefault());return b.type=q,e||b.isDefaultPrevented()||o._default&&o._default.apply(p.pop(),c)!==!1||!n.acceptData(d)||k&&n.isFunction(d[q])&&!n.isWindow(d)&&(h=d[k],h&&(d[k]=null),n.event.triggered=q,d[q](),n.event.triggered=void 0,h&&(d[k]=h)),b.result}},dispatch:function(a){a=n.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(L.get(this,"events")||{})[a.type]||[],k=n.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=n.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,c=0;while((g=f.handlers[c++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(g.namespace))&&(a.handleObj=g,a.data=g.data,e=((n.event.special[g.origType]||{}).handle||g.handler).apply(f.elem,i),void 0!==e&&(a.result=e)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!==this;i=i.parentNode||this)if(i.disabled!==!0||"click"!==a.type){for(d=[],c=0;h>c;c++)f=b[c],e=f.selector+" ",void 0===d[e]&&(d[e]=f.needsContext?n(e,this).index(i)>=0:n.find(e,this,null,[i]).length),d[e]&&d.push(f);d.length&&g.push({elem:i,handlers:d})}return h<b.length&&g.push({elem:this,handlers:b.slice(h)}),g},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(a,b){return null==a.which&&(a.which=null!=b.charCode?b.charCode:b.keyCode),a}},mouseHooks:{props:"button buttons clientX clientY offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(a,b){var c,d,e,f=b.button;return null==a.pageX&&null!=b.clientX&&(c=a.target.ownerDocument||l,d=c.documentElement,e=c.body,a.pageX=b.clientX+(d&&d.scrollLeft||e&&e.scrollLeft||0)-(d&&d.clientLeft||e&&e.clientLeft||0),a.pageY=b.clientY+(d&&d.scrollTop||e&&e.scrollTop||0)-(d&&d.clientTop||e&&e.clientTop||0)),a.which||void 0===f||(a.which=1&f?1:2&f?3:4&f?2:0),a}},fix:function(a){if(a[n.expando])return a;var b,c,d,e=a.type,f=a,g=this.fixHooks[e];g||(this.fixHooks[e]=g=W.test(e)?this.mouseHooks:V.test(e)?this.keyHooks:{}),d=g.props?this.props.concat(g.props):this.props,a=new n.Event(f),b=d.length;while(b--)c=d[b],a[c]=f[c];return a.target||(a.target=l),3===a.target.nodeType&&(a.target=a.target.parentNode),g.filter?g.filter(a,f):a},special:{load:{noBubble:!0},focus:{trigger:function(){return this!==_()&&this.focus?(this.focus(),!1):void 0},delegateType:"focusin"},blur:{trigger:function(){return this===_()&&this.blur?(this.blur(),!1):void 0},delegateType:"focusout"},click:{trigger:function(){return"checkbox"===this.type&&this.click&&n.nodeName(this,"input")?(this.click(),!1):void 0},_default:function(a){return n.nodeName(a.target,"a")}},beforeunload:{postDispatch:function(a){void 0!==a.result&&a.originalEvent&&(a.originalEvent.returnValue=a.result)}}},simulate:function(a,b,c,d){var e=n.extend(new n.Event,c,{type:a,isSimulated:!0,originalEvent:{}});d?n.event.trigger(e,null,b):n.event.dispatch.call(b,e),e.isDefaultPrevented()&&c.preventDefault()}},n.removeEvent=function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)},n.Event=function(a,b){return this instanceof n.Event?(a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||void 0===a.defaultPrevented&&a.returnValue===!1?Z:$):this.type=a,b&&n.extend(this,b),this.timeStamp=a&&a.timeStamp||n.now(),void(this[n.expando]=!0)):new n.Event(a,b)},n.Event.prototype={isDefaultPrevented:$,isPropagationStopped:$,isImmediatePropagationStopped:$,preventDefault:function(){var a=this.originalEvent;this.isDefaultPrevented=Z,a&&a.preventDefault&&a.preventDefault()},stopPropagation:function(){var a=this.originalEvent;this.isPropagationStopped=Z,a&&a.stopPropagation&&a.stopPropagation()},stopImmediatePropagation:function(){var a=this.originalEvent;this.isImmediatePropagationStopped=Z,a&&a.stopImmediatePropagation&&a.stopImmediatePropagation(),this.stopPropagation()}},n.each({mouseenter:"mouseover",mouseleave:"mouseout",pointerenter:"pointerover",pointerleave:"pointerout"},function(a,b){n.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c,d=this,e=a.relatedTarget,f=a.handleObj;return(!e||e!==d&&!n.contains(d,e))&&(a.type=f.origType,c=f.handler.apply(this,arguments),a.type=b),c}}}),k.focusinBubbles||n.each({focus:"focusin",blur:"focusout"},function(a,b){var c=function(a){n.event.simulate(b,a.target,n.event.fix(a),!0)};n.event.special[b]={setup:function(){var d=this.ownerDocument||this,e=L.access(d,b);e||d.addEventListener(a,c,!0),L.access(d,b,(e||0)+1)},teardown:function(){var d=this.ownerDocument||this,e=L.access(d,b)-1;e?L.access(d,b,e):(d.removeEventListener(a,c,!0),L.remove(d,b))}}}),n.fn.extend({on:function(a,b,c,d,e){var f,g;if("object"==typeof a){"string"!=typeof b&&(c=c||b,b=void 0);for(g in a)this.on(g,b,c,a[g],e);return this}if(null==c&&null==d?(d=b,c=b=void 0):null==d&&("string"==typeof b?(d=c,c=void 0):(d=c,c=b,b=void 0)),d===!1)d=$;else if(!d)return this;return 1===e&&(f=d,d=function(a){return n().off(a),f.apply(this,arguments)},d.guid=f.guid||(f.guid=n.guid++)),this.each(function(){n.event.add(this,a,d,c,b)})},one:function(a,b,c,d){return this.on(a,b,c,d,1)},off:function(a,b,c){var d,e;if(a&&a.preventDefault&&a.handleObj)return d=a.handleObj,n(a.delegateTarget).off(d.namespace?d.origType+"."+d.namespace:d.origType,d.selector,d.handler),this;if("object"==typeof a){for(e in a)this.off(e,b,a[e]);return this}return(b===!1||"function"==typeof b)&&(c=b,b=void 0),c===!1&&(c=$),this.each(function(){n.event.remove(this,a,c,b)})},trigger:function(a,b){return this.each(function(){n.event.trigger(a,b,this)})},triggerHandler:function(a,b){var c=this[0];return c?n.event.trigger(a,b,c,!0):void 0}});var ab=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,bb=/<([\w:]+)/,cb=/<|&#?\w+;/,db=/<(?:script|style|link)/i,eb=/checked\s*(?:[^=]|=\s*.checked.)/i,fb=/^$|\/(?:java|ecma)script/i,gb=/^true\/(.*)/,hb=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,ib={option:[1,"<select multiple='multiple'>","</select>"],thead:[1,"<table>","</table>"],col:[2,"<table><colgroup>","</colgroup></table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:[0,"",""]};ib.optgroup=ib.option,ib.tbody=ib.tfoot=ib.colgroup=ib.caption=ib.thead,ib.th=ib.td;function jb(a,b){return n.nodeName(a,"table")&&n.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function kb(a){return a.type=(null!==a.getAttribute("type"))+"/"+a.type,a}function lb(a){var b=gb.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function mb(a,b){for(var c=0,d=a.length;d>c;c++)L.set(a[c],"globalEval",!b||L.get(b[c],"globalEval"))}function nb(a,b){var c,d,e,f,g,h,i,j;if(1===b.nodeType){if(L.hasData(a)&&(f=L.access(a),g=L.set(b,f),j=f.events)){delete g.handle,g.events={};for(e in j)for(c=0,d=j[e].length;d>c;c++)n.event.add(b,e,j[e][c])}M.hasData(a)&&(h=M.access(a),i=n.extend({},h),M.set(b,i))}}function ob(a,b){var c=a.getElementsByTagName?a.getElementsByTagName(b||"*"):a.querySelectorAll?a.querySelectorAll(b||"*"):[];return void 0===b||b&&n.nodeName(a,b)?n.merge([a],c):c}function pb(a,b){var c=b.nodeName.toLowerCase();"input"===c&&T.test(a.type)?b.checked=a.checked:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}n.extend({clone:function(a,b,c){var d,e,f,g,h=a.cloneNode(!0),i=n.contains(a.ownerDocument,a);if(!(k.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||n.isXMLDoc(a)))for(g=ob(h),f=ob(a),d=0,e=f.length;e>d;d++)pb(f[d],g[d]);if(b)if(c)for(f=f||ob(a),g=g||ob(h),d=0,e=f.length;e>d;d++)nb(f[d],g[d]);else nb(a,h);return g=ob(h,"script"),g.length>0&&mb(g,!i&&ob(a,"script")),h},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,k=b.createDocumentFragment(),l=[],m=0,o=a.length;o>m;m++)if(e=a[m],e||0===e)if("object"===n.type(e))n.merge(l,e.nodeType?[e]:e);else if(cb.test(e)){f=f||k.appendChild(b.createElement("div")),g=(bb.exec(e)||["",""])[1].toLowerCase(),h=ib[g]||ib._default,f.innerHTML=h[1]+e.replace(ab,"<$1></$2>")+h[2],j=h[0];while(j--)f=f.lastChild;n.merge(l,f.childNodes),f=k.firstChild,f.textContent=""}else l.push(b.createTextNode(e));k.textContent="",m=0;while(e=l[m++])if((!d||-1===n.inArray(e,d))&&(i=n.contains(e.ownerDocument,e),f=ob(k.appendChild(e),"script"),i&&mb(f),c)){j=0;while(e=f[j++])fb.test(e.type||"")&&c.push(e)}return k},cleanData:function(a){for(var b,c,d,e,f=n.event.special,g=0;void 0!==(c=a[g]);g++){if(n.acceptData(c)&&(e=c[L.expando],e&&(b=L.cache[e]))){if(b.events)for(d in b.events)f[d]?n.event.remove(c,d):n.removeEvent(c,d,b.handle);L.cache[e]&&delete L.cache[e]}delete M.cache[c[M.expando]]}}}),n.fn.extend({text:function(a){return J(this,function(a){return void 0===a?n.text(this):this.empty().each(function(){(1===this.nodeType||11===this.nodeType||9===this.nodeType)&&(this.textContent=a)})},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=jb(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=jb(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?n.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||n.cleanData(ob(c)),c.parentNode&&(b&&n.contains(c.ownerDocument,c)&&mb(ob(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++)1===a.nodeType&&(n.cleanData(ob(a,!1)),a.textContent="");return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return n.clone(this,a,b)})},html:function(a){return J(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a&&1===b.nodeType)return b.innerHTML;if("string"==typeof a&&!db.test(a)&&!ib[(bb.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(ab,"<$1></$2>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(n.cleanData(ob(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,n.cleanData(ob(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,l=this.length,m=this,o=l-1,p=a[0],q=n.isFunction(p);if(q||l>1&&"string"==typeof p&&!k.checkClone&&eb.test(p))return this.each(function(c){var d=m.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(l&&(c=n.buildFragment(a,this[0].ownerDocument,!1,this),d=c.firstChild,1===c.childNodes.length&&(c=d),d)){for(f=n.map(ob(c,"script"),kb),g=f.length;l>j;j++)h=c,j!==o&&(h=n.clone(h,!0,!0),g&&n.merge(f,ob(h,"script"))),b.call(this[j],h,j);if(g)for(i=f[f.length-1].ownerDocument,n.map(f,lb),j=0;g>j;j++)h=f[j],fb.test(h.type||"")&&!L.access(h,"globalEval")&&n.contains(i,h)&&(h.src?n._evalUrl&&n._evalUrl(h.src):n.globalEval(h.textContent.replace(hb,"")))}return this}}),n.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){n.fn[a]=function(a){for(var c,d=[],e=n(a),g=e.length-1,h=0;g>=h;h++)c=h===g?this:this.clone(!0),n(e[h])[b](c),f.apply(d,c.get());return this.pushStack(d)}});var qb,rb={};function sb(b,c){var d,e=n(c.createElement(b)).appendTo(c.body),f=a.getDefaultComputedStyle&&(d=a.getDefaultComputedStyle(e[0]))?d.display:n.css(e[0],"display");return e.detach(),f}function tb(a){var b=l,c=rb[a];return c||(c=sb(a,b),"none"!==c&&c||(qb=(qb||n("<iframe frameborder='0' width='0' height='0'/>")).appendTo(b.documentElement),b=qb[0].contentDocument,b.write(),b.close(),c=sb(a,b),qb.detach()),rb[a]=c),c}var ub=/^margin/,vb=new RegExp("^("+Q+")(?!px)[a-z%]+$","i"),wb=function(b){return b.ownerDocument.defaultView.opener?b.ownerDocument.defaultView.getComputedStyle(b,null):a.getComputedStyle(b,null)};function xb(a,b,c){var d,e,f,g,h=a.style;return c=c||wb(a),c&&(g=c.getPropertyValue(b)||c[b]),c&&(""!==g||n.contains(a.ownerDocument,a)||(g=n.style(a,b)),vb.test(g)&&ub.test(b)&&(d=h.width,e=h.minWidth,f=h.maxWidth,h.minWidth=h.maxWidth=h.width=g,g=c.width,h.width=d,h.minWidth=e,h.maxWidth=f)),void 0!==g?g+"":g}function yb(a,b){return{get:function(){return a()?void delete this.get:(this.get=b).apply(this,arguments)}}}!function(){var b,c,d=l.documentElement,e=l.createElement("div"),f=l.createElement("div");if(f.style){f.style.backgroundClip="content-box",f.cloneNode(!0).style.backgroundClip="",k.clearCloneStyle="content-box"===f.style.backgroundClip,e.style.cssText="border:0;width:0;height:0;top:0;left:-9999px;margin-top:1px;position:absolute",e.appendChild(f);function g(){f.style.cssText="-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;display:block;margin-top:1%;top:1%;border:1px;padding:1px;width:4px;position:absolute",f.innerHTML="",d.appendChild(e);var g=a.getComputedStyle(f,null);b="1%"!==g.top,c="4px"===g.width,d.removeChild(e)}a.getComputedStyle&&n.extend(k,{pixelPosition:function(){return g(),b},boxSizingReliable:function(){return null==c&&g(),c},reliableMarginRight:function(){var b,c=f.appendChild(l.createElement("div"));return c.style.cssText=f.style.cssText="-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;margin:0;border:0;padding:0",c.style.marginRight=c.style.width="0",f.style.width="1px",d.appendChild(e),b=!parseFloat(a.getComputedStyle(c,null).marginRight),d.removeChild(e),f.removeChild(c),b}})}}(),n.swap=function(a,b,c,d){var e,f,g={};for(f in b)g[f]=a.style[f],a.style[f]=b[f];e=c.apply(a,d||[]);for(f in b)a.style[f]=g[f];return e};var zb=/^(none|table(?!-c[ea]).+)/,Ab=new RegExp("^("+Q+")(.*)$","i"),Bb=new RegExp("^([+-])=("+Q+")","i"),Cb={position:"absolute",visibility:"hidden",display:"block"},Db={letterSpacing:"0",fontWeight:"400"},Eb=["Webkit","O","Moz","ms"];function Fb(a,b){if(b in a)return b;var c=b[0].toUpperCase()+b.slice(1),d=b,e=Eb.length;while(e--)if(b=Eb[e]+c,b in a)return b;return d}function Gb(a,b,c){var d=Ab.exec(b);return d?Math.max(0,d[1]-(c||0))+(d[2]||"px"):b}function Hb(a,b,c,d,e){for(var f=c===(d?"border":"content")?4:"width"===b?1:0,g=0;4>f;f+=2)"margin"===c&&(g+=n.css(a,c+R[f],!0,e)),d?("content"===c&&(g-=n.css(a,"padding"+R[f],!0,e)),"margin"!==c&&(g-=n.css(a,"border"+R[f]+"Width",!0,e))):(g+=n.css(a,"padding"+R[f],!0,e),"padding"!==c&&(g+=n.css(a,"border"+R[f]+"Width",!0,e)));return g}function Ib(a,b,c){var d=!0,e="width"===b?a.offsetWidth:a.offsetHeight,f=wb(a),g="border-box"===n.css(a,"boxSizing",!1,f);if(0>=e||null==e){if(e=xb(a,b,f),(0>e||null==e)&&(e=a.style[b]),vb.test(e))return e;d=g&&(k.boxSizingReliable()||e===a.style[b]),e=parseFloat(e)||0}return e+Hb(a,b,c||(g?"border":"content"),d,f)+"px"}function Jb(a,b){for(var c,d,e,f=[],g=0,h=a.length;h>g;g++)d=a[g],d.style&&(f[g]=L.get(d,"olddisplay"),c=d.style.display,b?(f[g]||"none"!==c||(d.style.display=""),""===d.style.display&&S(d)&&(f[g]=L.access(d,"olddisplay",tb(d.nodeName)))):(e=S(d),"none"===c&&e||L.set(d,"olddisplay",e?c:n.css(d,"display"))));for(g=0;h>g;g++)d=a[g],d.style&&(b&&"none"!==d.style.display&&""!==d.style.display||(d.style.display=b?f[g]||"":"none"));return a}n.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=xb(a,"opacity");return""===c?"1":c}}}},cssNumber:{columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":"cssFloat"},style:function(a,b,c,d){if(a&&3!==a.nodeType&&8!==a.nodeType&&a.style){var e,f,g,h=n.camelCase(b),i=a.style;return b=n.cssProps[h]||(n.cssProps[h]=Fb(i,h)),g=n.cssHooks[b]||n.cssHooks[h],void 0===c?g&&"get"in g&&void 0!==(e=g.get(a,!1,d))?e:i[b]:(f=typeof c,"string"===f&&(e=Bb.exec(c))&&(c=(e[1]+1)*e[2]+parseFloat(n.css(a,b)),f="number"),null!=c&&c===c&&("number"!==f||n.cssNumber[h]||(c+="px"),k.clearCloneStyle||""!==c||0!==b.indexOf("background")||(i[b]="inherit"),g&&"set"in g&&void 0===(c=g.set(a,c,d))||(i[b]=c)),void 0)}},css:function(a,b,c,d){var e,f,g,h=n.camelCase(b);return b=n.cssProps[h]||(n.cssProps[h]=Fb(a.style,h)),g=n.cssHooks[b]||n.cssHooks[h],g&&"get"in g&&(e=g.get(a,!0,c)),void 0===e&&(e=xb(a,b,d)),"normal"===e&&b in Db&&(e=Db[b]),""===c||c?(f=parseFloat(e),c===!0||n.isNumeric(f)?f||0:e):e}}),n.each(["height","width"],function(a,b){n.cssHooks[b]={get:function(a,c,d){return c?zb.test(n.css(a,"display"))&&0===a.offsetWidth?n.swap(a,Cb,function(){return Ib(a,b,d)}):Ib(a,b,d):void 0},set:function(a,c,d){var e=d&&wb(a);return Gb(a,c,d?Hb(a,b,d,"border-box"===n.css(a,"boxSizing",!1,e),e):0)}}}),n.cssHooks.marginRight=yb(k.reliableMarginRight,function(a,b){return b?n.swap(a,{display:"inline-block"},xb,[a,"marginRight"]):void 0}),n.each({margin:"",padding:"",border:"Width"},function(a,b){n.cssHooks[a+b]={expand:function(c){for(var d=0,e={},f="string"==typeof c?c.split(" "):[c];4>d;d++)e[a+R[d]+b]=f[d]||f[d-2]||f[0];return e}},ub.test(a)||(n.cssHooks[a+b].set=Gb)}),n.fn.extend({css:function(a,b){return J(this,function(a,b,c){var d,e,f={},g=0;if(n.isArray(b)){for(d=wb(a),e=b.length;e>g;g++)f[b[g]]=n.css(a,b[g],!1,d);return f}return void 0!==c?n.style(a,b,c):n.css(a,b)},a,b,arguments.length>1)},show:function(){return Jb(this,!0)},hide:function(){return Jb(this)},toggle:function(a){return"boolean"==typeof a?a?this.show():this.hide():this.each(function(){S(this)?n(this).show():n(this).hide()})}});function Kb(a,b,c,d,e){return new Kb.prototype.init(a,b,c,d,e)}n.Tween=Kb,Kb.prototype={constructor:Kb,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||"swing",this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(n.cssNumber[c]?"":"px")},cur:function(){var a=Kb.propHooks[this.prop];return a&&a.get?a.get(this):Kb.propHooks._default.get(this)},run:function(a){var b,c=Kb.propHooks[this.prop];return this.pos=b=this.options.duration?n.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):Kb.propHooks._default.set(this),this}},Kb.prototype.init.prototype=Kb.prototype,Kb.propHooks={_default:{get:function(a){var b;return null==a.elem[a.prop]||a.elem.style&&null!=a.elem.style[a.prop]?(b=n.css(a.elem,a.prop,""),b&&"auto"!==b?b:0):a.elem[a.prop]},set:function(a){n.fx.step[a.prop]?n.fx.step[a.prop](a):a.elem.style&&(null!=a.elem.style[n.cssProps[a.prop]]||n.cssHooks[a.prop])?n.style(a.elem,a.prop,a.now+a.unit):a.elem[a.prop]=a.now}}},Kb.propHooks.scrollTop=Kb.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},n.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2}},n.fx=Kb.prototype.init,n.fx.step={};var Lb,Mb,Nb=/^(?:toggle|show|hide)$/,Ob=new RegExp("^(?:([+-])=|)("+Q+")([a-z%]*)$","i"),Pb=/queueHooks$/,Qb=[Vb],Rb={"*":[function(a,b){var c=this.createTween(a,b),d=c.cur(),e=Ob.exec(b),f=e&&e[3]||(n.cssNumber[a]?"":"px"),g=(n.cssNumber[a]||"px"!==f&&+d)&&Ob.exec(n.css(c.elem,a)),h=1,i=20;if(g&&g[3]!==f){f=f||g[3],e=e||[],g=+d||1;do h=h||".5",g/=h,n.style(c.elem,a,g+f);while(h!==(h=c.cur()/d)&&1!==h&&--i)}return e&&(g=c.start=+g||+d||0,c.unit=f,c.end=e[1]?g+(e[1]+1)*e[2]:+e[2]),c}]};function Sb(){return setTimeout(function(){Lb=void 0}),Lb=n.now()}function Tb(a,b){var c,d=0,e={height:a};for(b=b?1:0;4>d;d+=2-b)c=R[d],e["margin"+c]=e["padding"+c]=a;return b&&(e.opacity=e.width=a),e}function Ub(a,b,c){for(var d,e=(Rb[b]||[]).concat(Rb["*"]),f=0,g=e.length;g>f;f++)if(d=e[f].call(c,b,a))return d}function Vb(a,b,c){var d,e,f,g,h,i,j,k,l=this,m={},o=a.style,p=a.nodeType&&S(a),q=L.get(a,"fxshow");c.queue||(h=n._queueHooks(a,"fx"),null==h.unqueued&&(h.unqueued=0,i=h.empty.fire,h.empty.fire=function(){h.unqueued||i()}),h.unqueued++,l.always(function(){l.always(function(){h.unqueued--,n.queue(a,"fx").length||h.empty.fire()})})),1===a.nodeType&&("height"in b||"width"in b)&&(c.overflow=[o.overflow,o.overflowX,o.overflowY],j=n.css(a,"display"),k="none"===j?L.get(a,"olddisplay")||tb(a.nodeName):j,"inline"===k&&"none"===n.css(a,"float")&&(o.display="inline-block")),c.overflow&&(o.overflow="hidden",l.always(function(){o.overflow=c.overflow[0],o.overflowX=c.overflow[1],o.overflowY=c.overflow[2]}));for(d in b)if(e=b[d],Nb.exec(e)){if(delete b[d],f=f||"toggle"===e,e===(p?"hide":"show")){if("show"!==e||!q||void 0===q[d])continue;p=!0}m[d]=q&&q[d]||n.style(a,d)}else j=void 0;if(n.isEmptyObject(m))"inline"===("none"===j?tb(a.nodeName):j)&&(o.display=j);else{q?"hidden"in q&&(p=q.hidden):q=L.access(a,"fxshow",{}),f&&(q.hidden=!p),p?n(a).show():l.done(function(){n(a).hide()}),l.done(function(){var b;L.remove(a,"fxshow");for(b in m)n.style(a,b,m[b])});for(d in m)g=Ub(p?q[d]:0,d,l),d in q||(q[d]=g.start,p&&(g.end=g.start,g.start="width"===d||"height"===d?1:0))}}function Wb(a,b){var c,d,e,f,g;for(c in a)if(d=n.camelCase(c),e=b[d],f=a[c],n.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=n.cssHooks[d],g&&"expand"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}function Xb(a,b,c){var d,e,f=0,g=Qb.length,h=n.Deferred().always(function(){delete i.elem}),i=function(){if(e)return!1;for(var b=Lb||Sb(),c=Math.max(0,j.startTime+j.duration-b),d=c/j.duration||0,f=1-d,g=0,i=j.tweens.length;i>g;g++)j.tweens[g].run(f);return h.notifyWith(a,[j,f,c]),1>f&&i?c:(h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:n.extend({},b),opts:n.extend(!0,{specialEasing:{}},c),originalProperties:b,originalOptions:c,startTime:Lb||Sb(),duration:c.duration,tweens:[],createTween:function(b,c){var d=n.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(d),d},stop:function(b){var c=0,d=b?j.tweens.length:0;if(e)return this;for(e=!0;d>c;c++)j.tweens[c].run(1);return b?h.resolveWith(a,[j,b]):h.rejectWith(a,[j,b]),this}}),k=j.props;for(Wb(k,j.opts.specialEasing);g>f;f++)if(d=Qb[f].call(j,a,k,j.opts))return d;return n.map(k,Ub,j),n.isFunction(j.opts.start)&&j.opts.start.call(a,j),n.fx.timer(n.extend(i,{elem:a,anim:j,queue:j.opts.queue})),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always)}n.Animation=n.extend(Xb,{tweener:function(a,b){n.isFunction(a)?(b=a,a=["*"]):a=a.split(" ");for(var c,d=0,e=a.length;e>d;d++)c=a[d],Rb[c]=Rb[c]||[],Rb[c].unshift(b)},prefilter:function(a,b){b?Qb.unshift(a):Qb.push(a)}}),n.speed=function(a,b,c){var d=a&&"object"==typeof a?n.extend({},a):{complete:c||!c&&b||n.isFunction(a)&&a,duration:a,easing:c&&b||b&&!n.isFunction(b)&&b};return d.duration=n.fx.off?0:"number"==typeof d.duration?d.duration:d.duration in n.fx.speeds?n.fx.speeds[d.duration]:n.fx.speeds._default,(null==d.queue||d.queue===!0)&&(d.queue="fx"),d.old=d.complete,d.complete=function(){n.isFunction(d.old)&&d.old.call(this),d.queue&&n.dequeue(this,d.queue)},d},n.fn.extend({fadeTo:function(a,b,c,d){return this.filter(S).css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=n.isEmptyObject(a),f=n.speed(b,c,d),g=function(){var b=Xb(this,n.extend({},a),f);(e||L.get(this,"finish"))&&b.stop(!0)};return g.finish=g,e||f.queue===!1?this.each(g):this.queue(f.queue,g)},stop:function(a,b,c){var d=function(a){var b=a.stop;delete a.stop,b(c)};return"string"!=typeof a&&(c=b,b=a,a=void 0),b&&a!==!1&&this.queue(a||"fx",[]),this.each(function(){var b=!0,e=null!=a&&a+"queueHooks",f=n.timers,g=L.get(this);if(e)g[e]&&g[e].stop&&d(g[e]);else for(e in g)g[e]&&g[e].stop&&Pb.test(e)&&d(g[e]);for(e=f.length;e--;)f[e].elem!==this||null!=a&&f[e].queue!==a||(f[e].anim.stop(c),b=!1,f.splice(e,1));(b||!c)&&n.dequeue(this,a)})},finish:function(a){return a!==!1&&(a=a||"fx"),this.each(function(){var b,c=L.get(this),d=c[a+"queue"],e=c[a+"queueHooks"],f=n.timers,g=d?d.length:0;for(c.finish=!0,n.queue(this,a,[]),e&&e.stop&&e.stop.call(this,!0),b=f.length;b--;)f[b].elem===this&&f[b].queue===a&&(f[b].anim.stop(!0),f.splice(b,1));for(b=0;g>b;b++)d[b]&&d[b].finish&&d[b].finish.call(this);delete c.finish})}}),n.each(["toggle","show","hide"],function(a,b){var c=n.fn[b];n.fn[b]=function(a,d,e){return null==a||"boolean"==typeof a?c.apply(this,arguments):this.animate(Tb(b,!0),a,d,e)}}),n.each({slideDown:Tb("show"),slideUp:Tb("hide"),slideToggle:Tb("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){n.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),n.timers=[],n.fx.tick=function(){var a,b=0,c=n.timers;for(Lb=n.now();b<c.length;b++)a=c[b],a()||c[b]!==a||c.splice(b--,1);c.length||n.fx.stop(),Lb=void 0},n.fx.timer=function(a){n.timers.push(a),a()?n.fx.start():n.timers.pop()},n.fx.interval=13,n.fx.start=function(){Mb||(Mb=setInterval(n.fx.tick,n.fx.interval))},n.fx.stop=function(){clearInterval(Mb),Mb=null},n.fx.speeds={slow:600,fast:200,_default:400},n.fn.delay=function(a,b){return a=n.fx?n.fx.speeds[a]||a:a,b=b||"fx",this.queue(b,function(b,c){var d=setTimeout(b,a);c.stop=function(){clearTimeout(d)}})},function(){var a=l.createElement("input"),b=l.createElement("select"),c=b.appendChild(l.createElement("option"));a.type="checkbox",k.checkOn=""!==a.value,k.optSelected=c.selected,b.disabled=!0,k.optDisabled=!c.disabled,a=l.createElement("input"),a.value="t",a.type="radio",k.radioValue="t"===a.value}();var Yb,Zb,$b=n.expr.attrHandle;n.fn.extend({attr:function(a,b){return J(this,n.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){n.removeAttr(this,a)})}}),n.extend({attr:function(a,b,c){var d,e,f=a.nodeType;if(a&&3!==f&&8!==f&&2!==f)return typeof a.getAttribute===U?n.prop(a,b,c):(1===f&&n.isXMLDoc(a)||(b=b.toLowerCase(),d=n.attrHooks[b]||(n.expr.match.bool.test(b)?Zb:Yb)),void 0===c?d&&"get"in d&&null!==(e=d.get(a,b))?e:(e=n.find.attr(a,b),null==e?void 0:e):null!==c?d&&"set"in d&&void 0!==(e=d.set(a,c,b))?e:(a.setAttribute(b,c+""),c):void n.removeAttr(a,b))
},removeAttr:function(a,b){var c,d,e=0,f=b&&b.match(E);if(f&&1===a.nodeType)while(c=f[e++])d=n.propFix[c]||c,n.expr.match.bool.test(c)&&(a[d]=!1),a.removeAttribute(c)},attrHooks:{type:{set:function(a,b){if(!k.radioValue&&"radio"===b&&n.nodeName(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}}}}),Zb={set:function(a,b,c){return b===!1?n.removeAttr(a,c):a.setAttribute(c,c),c}},n.each(n.expr.match.bool.source.match(/\w+/g),function(a,b){var c=$b[b]||n.find.attr;$b[b]=function(a,b,d){var e,f;return d||(f=$b[b],$b[b]=e,e=null!=c(a,b,d)?b.toLowerCase():null,$b[b]=f),e}});var _b=/^(?:input|select|textarea|button)$/i;n.fn.extend({prop:function(a,b){return J(this,n.prop,a,b,arguments.length>1)},removeProp:function(a){return this.each(function(){delete this[n.propFix[a]||a]})}}),n.extend({propFix:{"for":"htmlFor","class":"className"},prop:function(a,b,c){var d,e,f,g=a.nodeType;if(a&&3!==g&&8!==g&&2!==g)return f=1!==g||!n.isXMLDoc(a),f&&(b=n.propFix[b]||b,e=n.propHooks[b]),void 0!==c?e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:a[b]=c:e&&"get"in e&&null!==(d=e.get(a,b))?d:a[b]},propHooks:{tabIndex:{get:function(a){return a.hasAttribute("tabindex")||_b.test(a.nodeName)||a.href?a.tabIndex:-1}}}}),k.optSelected||(n.propHooks.selected={get:function(a){var b=a.parentNode;return b&&b.parentNode&&b.parentNode.selectedIndex,null}}),n.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){n.propFix[this.toLowerCase()]=this});var ac=/[\t\r\n\f]/g;n.fn.extend({addClass:function(a){var b,c,d,e,f,g,h="string"==typeof a&&a,i=0,j=this.length;if(n.isFunction(a))return this.each(function(b){n(this).addClass(a.call(this,b,this.className))});if(h)for(b=(a||"").match(E)||[];j>i;i++)if(c=this[i],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(ac," "):" ")){f=0;while(e=b[f++])d.indexOf(" "+e+" ")<0&&(d+=e+" ");g=n.trim(d),c.className!==g&&(c.className=g)}return this},removeClass:function(a){var b,c,d,e,f,g,h=0===arguments.length||"string"==typeof a&&a,i=0,j=this.length;if(n.isFunction(a))return this.each(function(b){n(this).removeClass(a.call(this,b,this.className))});if(h)for(b=(a||"").match(E)||[];j>i;i++)if(c=this[i],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(ac," "):"")){f=0;while(e=b[f++])while(d.indexOf(" "+e+" ")>=0)d=d.replace(" "+e+" "," ");g=a?n.trim(d):"",c.className!==g&&(c.className=g)}return this},toggleClass:function(a,b){var c=typeof a;return"boolean"==typeof b&&"string"===c?b?this.addClass(a):this.removeClass(a):this.each(n.isFunction(a)?function(c){n(this).toggleClass(a.call(this,c,this.className,b),b)}:function(){if("string"===c){var b,d=0,e=n(this),f=a.match(E)||[];while(b=f[d++])e.hasClass(b)?e.removeClass(b):e.addClass(b)}else(c===U||"boolean"===c)&&(this.className&&L.set(this,"__className__",this.className),this.className=this.className||a===!1?"":L.get(this,"__className__")||"")})},hasClass:function(a){for(var b=" "+a+" ",c=0,d=this.length;d>c;c++)if(1===this[c].nodeType&&(" "+this[c].className+" ").replace(ac," ").indexOf(b)>=0)return!0;return!1}});var bc=/\r/g;n.fn.extend({val:function(a){var b,c,d,e=this[0];{if(arguments.length)return d=n.isFunction(a),this.each(function(c){var e;1===this.nodeType&&(e=d?a.call(this,c,n(this).val()):a,null==e?e="":"number"==typeof e?e+="":n.isArray(e)&&(e=n.map(e,function(a){return null==a?"":a+""})),b=n.valHooks[this.type]||n.valHooks[this.nodeName.toLowerCase()],b&&"set"in b&&void 0!==b.set(this,e,"value")||(this.value=e))});if(e)return b=n.valHooks[e.type]||n.valHooks[e.nodeName.toLowerCase()],b&&"get"in b&&void 0!==(c=b.get(e,"value"))?c:(c=e.value,"string"==typeof c?c.replace(bc,""):null==c?"":c)}}}),n.extend({valHooks:{option:{get:function(a){var b=n.find.attr(a,"value");return null!=b?b:n.trim(n.text(a))}},select:{get:function(a){for(var b,c,d=a.options,e=a.selectedIndex,f="select-one"===a.type||0>e,g=f?null:[],h=f?e+1:d.length,i=0>e?h:f?e:0;h>i;i++)if(c=d[i],!(!c.selected&&i!==e||(k.optDisabled?c.disabled:null!==c.getAttribute("disabled"))||c.parentNode.disabled&&n.nodeName(c.parentNode,"optgroup"))){if(b=n(c).val(),f)return b;g.push(b)}return g},set:function(a,b){var c,d,e=a.options,f=n.makeArray(b),g=e.length;while(g--)d=e[g],(d.selected=n.inArray(d.value,f)>=0)&&(c=!0);return c||(a.selectedIndex=-1),f}}}}),n.each(["radio","checkbox"],function(){n.valHooks[this]={set:function(a,b){return n.isArray(b)?a.checked=n.inArray(n(a).val(),b)>=0:void 0}},k.checkOn||(n.valHooks[this].get=function(a){return null===a.getAttribute("value")?"on":a.value})}),n.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(a,b){n.fn[b]=function(a,c){return arguments.length>0?this.on(b,null,a,c):this.trigger(b)}}),n.fn.extend({hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)},bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return 1===arguments.length?this.off(a,"**"):this.off(b,a||"**",c)}});var cc=n.now(),dc=/\?/;n.parseJSON=function(a){return JSON.parse(a+"")},n.parseXML=function(a){var b,c;if(!a||"string"!=typeof a)return null;try{c=new DOMParser,b=c.parseFromString(a,"text/xml")}catch(d){b=void 0}return(!b||b.getElementsByTagName("parsererror").length)&&n.error("Invalid XML: "+a),b};var ec=/#.*$/,fc=/([?&])_=[^&]*/,gc=/^(.*?):[ \t]*([^\r\n]*)$/gm,hc=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,ic=/^(?:GET|HEAD)$/,jc=/^\/\//,kc=/^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/,lc={},mc={},nc="*/".concat("*"),oc=a.location.href,pc=kc.exec(oc.toLowerCase())||[];function qc(a){return function(b,c){"string"!=typeof b&&(c=b,b="*");var d,e=0,f=b.toLowerCase().match(E)||[];if(n.isFunction(c))while(d=f[e++])"+"===d[0]?(d=d.slice(1)||"*",(a[d]=a[d]||[]).unshift(c)):(a[d]=a[d]||[]).push(c)}}function rc(a,b,c,d){var e={},f=a===mc;function g(h){var i;return e[h]=!0,n.each(a[h]||[],function(a,h){var j=h(b,c,d);return"string"!=typeof j||f||e[j]?f?!(i=j):void 0:(b.dataTypes.unshift(j),g(j),!1)}),i}return g(b.dataTypes[0])||!e["*"]&&g("*")}function sc(a,b){var c,d,e=n.ajaxSettings.flatOptions||{};for(c in b)void 0!==b[c]&&((e[c]?a:d||(d={}))[c]=b[c]);return d&&n.extend(!0,a,d),a}function tc(a,b,c){var d,e,f,g,h=a.contents,i=a.dataTypes;while("*"===i[0])i.shift(),void 0===d&&(d=a.mimeType||b.getResponseHeader("Content-Type"));if(d)for(e in h)if(h[e]&&h[e].test(d)){i.unshift(e);break}if(i[0]in c)f=i[0];else{for(e in c){if(!i[0]||a.converters[e+" "+i[0]]){f=e;break}g||(g=e)}f=f||g}return f?(f!==i[0]&&i.unshift(f),c[f]):void 0}function uc(a,b,c,d){var e,f,g,h,i,j={},k=a.dataTypes.slice();if(k[1])for(g in a.converters)j[g.toLowerCase()]=a.converters[g];f=k.shift();while(f)if(a.responseFields[f]&&(c[a.responseFields[f]]=b),!i&&d&&a.dataFilter&&(b=a.dataFilter(b,a.dataType)),i=f,f=k.shift())if("*"===f)f=i;else if("*"!==i&&i!==f){if(g=j[i+" "+f]||j["* "+f],!g)for(e in j)if(h=e.split(" "),h[1]===f&&(g=j[i+" "+h[0]]||j["* "+h[0]])){g===!0?g=j[e]:j[e]!==!0&&(f=h[0],k.unshift(h[1]));break}if(g!==!0)if(g&&a["throws"])b=g(b);else try{b=g(b)}catch(l){return{state:"parsererror",error:g?l:"No conversion from "+i+" to "+f}}}return{state:"success",data:b}}n.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:oc,type:"GET",isLocal:hc.test(pc[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":nc,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":n.parseJSON,"text xml":n.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(a,b){return b?sc(sc(a,n.ajaxSettings),b):sc(n.ajaxSettings,a)},ajaxPrefilter:qc(lc),ajaxTransport:qc(mc),ajax:function(a,b){"object"==typeof a&&(b=a,a=void 0),b=b||{};var c,d,e,f,g,h,i,j,k=n.ajaxSetup({},b),l=k.context||k,m=k.context&&(l.nodeType||l.jquery)?n(l):n.event,o=n.Deferred(),p=n.Callbacks("once memory"),q=k.statusCode||{},r={},s={},t=0,u="canceled",v={readyState:0,getResponseHeader:function(a){var b;if(2===t){if(!f){f={};while(b=gc.exec(e))f[b[1].toLowerCase()]=b[2]}b=f[a.toLowerCase()]}return null==b?null:b},getAllResponseHeaders:function(){return 2===t?e:null},setRequestHeader:function(a,b){var c=a.toLowerCase();return t||(a=s[c]=s[c]||a,r[a]=b),this},overrideMimeType:function(a){return t||(k.mimeType=a),this},statusCode:function(a){var b;if(a)if(2>t)for(b in a)q[b]=[q[b],a[b]];else v.always(a[v.status]);return this},abort:function(a){var b=a||u;return c&&c.abort(b),x(0,b),this}};if(o.promise(v).complete=p.add,v.success=v.done,v.error=v.fail,k.url=((a||k.url||oc)+"").replace(ec,"").replace(jc,pc[1]+"//"),k.type=b.method||b.type||k.method||k.type,k.dataTypes=n.trim(k.dataType||"*").toLowerCase().match(E)||[""],null==k.crossDomain&&(h=kc.exec(k.url.toLowerCase()),k.crossDomain=!(!h||h[1]===pc[1]&&h[2]===pc[2]&&(h[3]||("http:"===h[1]?"80":"443"))===(pc[3]||("http:"===pc[1]?"80":"443")))),k.data&&k.processData&&"string"!=typeof k.data&&(k.data=n.param(k.data,k.traditional)),rc(lc,k,b,v),2===t)return v;i=n.event&&k.global,i&&0===n.active++&&n.event.trigger("ajaxStart"),k.type=k.type.toUpperCase(),k.hasContent=!ic.test(k.type),d=k.url,k.hasContent||(k.data&&(d=k.url+=(dc.test(d)?"&":"?")+k.data,delete k.data),k.cache===!1&&(k.url=fc.test(d)?d.replace(fc,"$1_="+cc++):d+(dc.test(d)?"&":"?")+"_="+cc++)),k.ifModified&&(n.lastModified[d]&&v.setRequestHeader("If-Modified-Since",n.lastModified[d]),n.etag[d]&&v.setRequestHeader("If-None-Match",n.etag[d])),(k.data&&k.hasContent&&k.contentType!==!1||b.contentType)&&v.setRequestHeader("Content-Type",k.contentType),v.setRequestHeader("Accept",k.dataTypes[0]&&k.accepts[k.dataTypes[0]]?k.accepts[k.dataTypes[0]]+("*"!==k.dataTypes[0]?", "+nc+"; q=0.01":""):k.accepts["*"]);for(j in k.headers)v.setRequestHeader(j,k.headers[j]);if(k.beforeSend&&(k.beforeSend.call(l,v,k)===!1||2===t))return v.abort();u="abort";for(j in{success:1,error:1,complete:1})v[j](k[j]);if(c=rc(mc,k,b,v)){v.readyState=1,i&&m.trigger("ajaxSend",[v,k]),k.async&&k.timeout>0&&(g=setTimeout(function(){v.abort("timeout")},k.timeout));try{t=1,c.send(r,x)}catch(w){if(!(2>t))throw w;x(-1,w)}}else x(-1,"No Transport");function x(a,b,f,h){var j,r,s,u,w,x=b;2!==t&&(t=2,g&&clearTimeout(g),c=void 0,e=h||"",v.readyState=a>0?4:0,j=a>=200&&300>a||304===a,f&&(u=tc(k,v,f)),u=uc(k,u,v,j),j?(k.ifModified&&(w=v.getResponseHeader("Last-Modified"),w&&(n.lastModified[d]=w),w=v.getResponseHeader("etag"),w&&(n.etag[d]=w)),204===a||"HEAD"===k.type?x="nocontent":304===a?x="notmodified":(x=u.state,r=u.data,s=u.error,j=!s)):(s=x,(a||!x)&&(x="error",0>a&&(a=0))),v.status=a,v.statusText=(b||x)+"",j?o.resolveWith(l,[r,x,v]):o.rejectWith(l,[v,x,s]),v.statusCode(q),q=void 0,i&&m.trigger(j?"ajaxSuccess":"ajaxError",[v,k,j?r:s]),p.fireWith(l,[v,x]),i&&(m.trigger("ajaxComplete",[v,k]),--n.active||n.event.trigger("ajaxStop")))}return v},getJSON:function(a,b,c){return n.get(a,b,c,"json")},getScript:function(a,b){return n.get(a,void 0,b,"script")}}),n.each(["get","post"],function(a,b){n[b]=function(a,c,d,e){return n.isFunction(c)&&(e=e||d,d=c,c=void 0),n.ajax({url:a,type:b,dataType:e,data:c,success:d})}}),n._evalUrl=function(a){return n.ajax({url:a,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})},n.fn.extend({wrapAll:function(a){var b;return n.isFunction(a)?this.each(function(b){n(this).wrapAll(a.call(this,b))}):(this[0]&&(b=n(a,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstElementChild)a=a.firstElementChild;return a}).append(this)),this)},wrapInner:function(a){return this.each(n.isFunction(a)?function(b){n(this).wrapInner(a.call(this,b))}:function(){var b=n(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=n.isFunction(a);return this.each(function(c){n(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){n.nodeName(this,"body")||n(this).replaceWith(this.childNodes)}).end()}}),n.expr.filters.hidden=function(a){return a.offsetWidth<=0&&a.offsetHeight<=0},n.expr.filters.visible=function(a){return!n.expr.filters.hidden(a)};var vc=/%20/g,wc=/\[\]$/,xc=/\r?\n/g,yc=/^(?:submit|button|image|reset|file)$/i,zc=/^(?:input|select|textarea|keygen)/i;function Ac(a,b,c,d){var e;if(n.isArray(b))n.each(b,function(b,e){c||wc.test(a)?d(a,e):Ac(a+"["+("object"==typeof e?b:"")+"]",e,c,d)});else if(c||"object"!==n.type(b))d(a,b);else for(e in b)Ac(a+"["+e+"]",b[e],c,d)}n.param=function(a,b){var c,d=[],e=function(a,b){b=n.isFunction(b)?b():null==b?"":b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};if(void 0===b&&(b=n.ajaxSettings&&n.ajaxSettings.traditional),n.isArray(a)||a.jquery&&!n.isPlainObject(a))n.each(a,function(){e(this.name,this.value)});else for(c in a)Ac(c,a[c],b,e);return d.join("&").replace(vc,"+")},n.fn.extend({serialize:function(){return n.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var a=n.prop(this,"elements");return a?n.makeArray(a):this}).filter(function(){var a=this.type;return this.name&&!n(this).is(":disabled")&&zc.test(this.nodeName)&&!yc.test(a)&&(this.checked||!T.test(a))}).map(function(a,b){var c=n(this).val();return null==c?null:n.isArray(c)?n.map(c,function(a){return{name:b.name,value:a.replace(xc,"\r\n")}}):{name:b.name,value:c.replace(xc,"\r\n")}}).get()}}),n.ajaxSettings.xhr=function(){try{return new XMLHttpRequest}catch(a){}};var Bc=0,Cc={},Dc={0:200,1223:204},Ec=n.ajaxSettings.xhr();a.attachEvent&&a.attachEvent("onunload",function(){for(var a in Cc)Cc[a]()}),k.cors=!!Ec&&"withCredentials"in Ec,k.ajax=Ec=!!Ec,n.ajaxTransport(function(a){var b;return k.cors||Ec&&!a.crossDomain?{send:function(c,d){var e,f=a.xhr(),g=++Bc;if(f.open(a.type,a.url,a.async,a.username,a.password),a.xhrFields)for(e in a.xhrFields)f[e]=a.xhrFields[e];a.mimeType&&f.overrideMimeType&&f.overrideMimeType(a.mimeType),a.crossDomain||c["X-Requested-With"]||(c["X-Requested-With"]="XMLHttpRequest");for(e in c)f.setRequestHeader(e,c[e]);b=function(a){return function(){b&&(delete Cc[g],b=f.onload=f.onerror=null,"abort"===a?f.abort():"error"===a?d(f.status,f.statusText):d(Dc[f.status]||f.status,f.statusText,"string"==typeof f.responseText?{text:f.responseText}:void 0,f.getAllResponseHeaders()))}},f.onload=b(),f.onerror=b("error"),b=Cc[g]=b("abort");try{f.send(a.hasContent&&a.data||null)}catch(h){if(b)throw h}},abort:function(){b&&b()}}:void 0}),n.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(a){return n.globalEval(a),a}}}),n.ajaxPrefilter("script",function(a){void 0===a.cache&&(a.cache=!1),a.crossDomain&&(a.type="GET")}),n.ajaxTransport("script",function(a){if(a.crossDomain){var b,c;return{send:function(d,e){b=n("<script>").prop({async:!0,charset:a.scriptCharset,src:a.url}).on("load error",c=function(a){b.remove(),c=null,a&&e("error"===a.type?404:200,a.type)}),l.head.appendChild(b[0])},abort:function(){c&&c()}}}});var Fc=[],Gc=/(=)\?(?=&|$)|\?\?/;n.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var a=Fc.pop()||n.expando+"_"+cc++;return this[a]=!0,a}}),n.ajaxPrefilter("json jsonp",function(b,c,d){var e,f,g,h=b.jsonp!==!1&&(Gc.test(b.url)?"url":"string"==typeof b.data&&!(b.contentType||"").indexOf("application/x-www-form-urlencoded")&&Gc.test(b.data)&&"data");return h||"jsonp"===b.dataTypes[0]?(e=b.jsonpCallback=n.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,h?b[h]=b[h].replace(Gc,"$1"+e):b.jsonp!==!1&&(b.url+=(dc.test(b.url)?"&":"?")+b.jsonp+"="+e),b.converters["script json"]=function(){return g||n.error(e+" was not called"),g[0]},b.dataTypes[0]="json",f=a[e],a[e]=function(){g=arguments},d.always(function(){a[e]=f,b[e]&&(b.jsonpCallback=c.jsonpCallback,Fc.push(e)),g&&n.isFunction(f)&&f(g[0]),g=f=void 0}),"script"):void 0}),n.parseHTML=function(a,b,c){if(!a||"string"!=typeof a)return null;"boolean"==typeof b&&(c=b,b=!1),b=b||l;var d=v.exec(a),e=!c&&[];return d?[b.createElement(d[1])]:(d=n.buildFragment([a],b,e),e&&e.length&&n(e).remove(),n.merge([],d.childNodes))};var Hc=n.fn.load;n.fn.load=function(a,b,c){if("string"!=typeof a&&Hc)return Hc.apply(this,arguments);var d,e,f,g=this,h=a.indexOf(" ");return h>=0&&(d=n.trim(a.slice(h)),a=a.slice(0,h)),n.isFunction(b)?(c=b,b=void 0):b&&"object"==typeof b&&(e="POST"),g.length>0&&n.ajax({url:a,type:e,dataType:"html",data:b}).done(function(a){f=arguments,g.html(d?n("<div>").append(n.parseHTML(a)).find(d):a)}).complete(c&&function(a,b){g.each(c,f||[a.responseText,b,a])}),this},n.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(a,b){n.fn[b]=function(a){return this.on(b,a)}}),n.expr.filters.animated=function(a){return n.grep(n.timers,function(b){return a===b.elem}).length};var Ic=a.document.documentElement;function Jc(a){return n.isWindow(a)?a:9===a.nodeType&&a.defaultView}n.offset={setOffset:function(a,b,c){var d,e,f,g,h,i,j,k=n.css(a,"position"),l=n(a),m={};"static"===k&&(a.style.position="relative"),h=l.offset(),f=n.css(a,"top"),i=n.css(a,"left"),j=("absolute"===k||"fixed"===k)&&(f+i).indexOf("auto")>-1,j?(d=l.position(),g=d.top,e=d.left):(g=parseFloat(f)||0,e=parseFloat(i)||0),n.isFunction(b)&&(b=b.call(a,c,h)),null!=b.top&&(m.top=b.top-h.top+g),null!=b.left&&(m.left=b.left-h.left+e),"using"in b?b.using.call(a,m):l.css(m)}},n.fn.extend({offset:function(a){if(arguments.length)return void 0===a?this:this.each(function(b){n.offset.setOffset(this,a,b)});var b,c,d=this[0],e={top:0,left:0},f=d&&d.ownerDocument;if(f)return b=f.documentElement,n.contains(b,d)?(typeof d.getBoundingClientRect!==U&&(e=d.getBoundingClientRect()),c=Jc(f),{top:e.top+c.pageYOffset-b.clientTop,left:e.left+c.pageXOffset-b.clientLeft}):e},position:function(){if(this[0]){var a,b,c=this[0],d={top:0,left:0};return"fixed"===n.css(c,"position")?b=c.getBoundingClientRect():(a=this.offsetParent(),b=this.offset(),n.nodeName(a[0],"html")||(d=a.offset()),d.top+=n.css(a[0],"borderTopWidth",!0),d.left+=n.css(a[0],"borderLeftWidth",!0)),{top:b.top-d.top-n.css(c,"marginTop",!0),left:b.left-d.left-n.css(c,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||Ic;while(a&&!n.nodeName(a,"html")&&"static"===n.css(a,"position"))a=a.offsetParent;return a||Ic})}}),n.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(b,c){var d="pageYOffset"===c;n.fn[b]=function(e){return J(this,function(b,e,f){var g=Jc(b);return void 0===f?g?g[c]:b[e]:void(g?g.scrollTo(d?a.pageXOffset:f,d?f:a.pageYOffset):b[e]=f)},b,e,arguments.length,null)}}),n.each(["top","left"],function(a,b){n.cssHooks[b]=yb(k.pixelPosition,function(a,c){return c?(c=xb(a,b),vb.test(c)?n(a).position()[b]+"px":c):void 0})}),n.each({Height:"height",Width:"width"},function(a,b){n.each({padding:"inner"+a,content:b,"":"outer"+a},function(c,d){n.fn[d]=function(d,e){var f=arguments.length&&(c||"boolean"!=typeof d),g=c||(d===!0||e===!0?"margin":"border");return J(this,function(b,c,d){var e;return n.isWindow(b)?b.document.documentElement["client"+a]:9===b.nodeType?(e=b.documentElement,Math.max(b.body["scroll"+a],e["scroll"+a],b.body["offset"+a],e["offset"+a],e["client"+a])):void 0===d?n.css(b,c,g):n.style(b,c,d,g)},b,f?d:void 0,f,null)}})}),n.fn.size=function(){return this.length},n.fn.andSelf=n.fn.addBack,"function"==typeof define&&define.amd&&define("jquery",[],function(){return n});var Kc=a.jQuery,Lc=a.$;return n.noConflict=function(b){return a.$===n&&(a.$=Lc),b&&a.jQuery===n&&(a.jQuery=Kc),n},typeof b===U&&(a.jQuery=a.$=n),n});
mod_mailjet.js000060400000001440152455615060007372 0ustar00/**
 * Created with JetBrains PhpStorm.
 * User: jonathan
 * Date: 10/31/12
 * Time: 10:23 AM
 * To change this template use File | Settings | File Templates.
 */


jQuery(document).ready(function($){
    $('.mailjet-subscribe').submit(function(e) {
        e.preventDefault();
        var f = $(e.currentTarget);
        var p = f.parent();
        $.ajax({
            type: "POST",
            url: "index.php",
            data: f.serialize(),
            dataType: "json",
            success: function(data){
                p.find('.mailjet-error').hide();
                p.find('.mailjet-success').show();
            },
            error: function() {
                p.find('.mailjet-success').hide();
                p.find('.mailjet-error').show();
            }
        });
    });
});