config-test.php 0000666 00000000444 13634722572 0007520 0 ustar 00
* @author http://code.google.com/u/1stvamp/ (Issue 64 patch)
*
* @deprecated Use Minify_CSSmin
*/
class Minify_CSS
{
/**
* Minify a CSS string
*
* @param string $css
*
* @param array $options available options:
*
* 'preserveComments': (default true) multi-line comments that begin
* with "/*!" will be preserved with newlines before and after to
* enhance readability.
*
* 'removeCharsets': (default true) remove all @charset at-rules
*
* 'prependRelativePath': (default null) if given, this string will be
* prepended to all relative URIs in import/url declarations
*
* 'currentDir': (default null) if given, this is assumed to be the
* directory of the current CSS file. Using this, minify will rewrite
* all relative URIs in import/url declarations to correctly point to
* the desired files. For this to work, the files *must* exist and be
* visible by the PHP process.
*
* 'symlinks': (default = array()) If the CSS file is stored in
* a symlink-ed directory, provide an array of link paths to
* target paths, where the link paths are within the document root. Because
* paths need to be normalized for this to work, use "//" to substitute
* the doc root in the link paths (the array keys). E.g.:
*
* array('//symlink' => '/real/target/path') // unix
* array('//static' => 'D:\\staticStorage') // Windows
*
*
* 'docRoot': (default = $_SERVER['DOCUMENT_ROOT'])
* see Minify_CSS_UriRewriter::rewrite
*
* @return string
*/
public static function minify($css, $options = array())
{
$options = array_merge(array(
'compress' => true,
'removeCharsets' => true,
'preserveComments' => true,
'currentDir' => null,
'docRoot' => $_SERVER['DOCUMENT_ROOT'],
'prependRelativePath' => null,
'symlinks' => array(),
), $options);
if ($options['removeCharsets']) {
$css = preg_replace('/@charset[^;]+;\\s*/', '', $css);
}
if ($options['compress']) {
if (! $options['preserveComments']) {
$css = Minify_CSS_Compressor::process($css, $options);
} else {
$processor = array('Minify_CSS_Compressor', 'process');
$css = Minify_CommentPreserver::process($css, $processor, array($options));
}
}
if (! $options['currentDir'] && ! $options['prependRelativePath']) {
return $css;
}
if ($options['currentDir']) {
$currentDir = $options['currentDir'];
$docRoot = $options['docRoot'];
$symlinks = $options['symlinks'];
return Minify_CSS_UriRewriter::rewrite($css, $currentDir, $docRoot, $symlinks);
}
return Minify_CSS_UriRewriter::prepend($css, $options['prependRelativePath']);
}
}
lib/Minify/Cache/Memcache.php 0000666 00000005766 13634722572 0012020 0 ustar 00
* // fall back to disk caching if memcache can't connect
* $memcache = new Memcache;
* if ($memcache->connect('localhost', 11211)) {
* Minify::setCache(new Minify_Cache_Memcache($memcache));
* } else {
* Minify::setCache();
* }
*
**/
class Minify_Cache_Memcache implements Minify_CacheInterface
{
/**
* Create a Minify_Cache_Memcache object, to be passed to
* Minify::setCache().
*
* @param Memcache $memcache already-connected instance
*
* @param int $expire seconds until expiration (default = 0
* meaning the item will not get an expiration date)
*/
public function __construct($memcache, $expire = 0)
{
$this->_mc = $memcache;
$this->_exp = $expire;
}
/**
* Write data to cache.
*
* @param string $id cache id
*
* @param string $data
*
* @return bool success
*/
public function store($id, $data)
{
return $this->_mc->set($id, "{$_SERVER['REQUEST_TIME']}|{$data}", 0, $this->_exp);
}
/**
* Get the size of a cache entry
*
* @param string $id cache id
*
* @return int size in bytes
*/
public function getSize($id)
{
if (! $this->_fetch($id)) {
return false;
}
if (function_exists('mb_strlen') && ((int)ini_get('mbstring.func_overload') & 2)) {
return mb_strlen($this->_data, '8bit');
} else {
return strlen($this->_data);
}
}
/**
* Does a valid cache entry exist?
*
* @param string $id cache id
*
* @param int $srcMtime mtime of the original source file(s)
*
* @return bool exists
*/
public function isValid($id, $srcMtime)
{
return ($this->_fetch($id) && ($this->_lm >= $srcMtime));
}
/**
* Send the cached content to output
*
* @param string $id cache id
*/
public function display($id)
{
echo $this->_fetch($id) ? $this->_data : '';
}
/**
* Fetch the cached content
*
* @param string $id cache id
*
* @return string
*/
public function fetch($id)
{
return $this->_fetch($id) ? $this->_data : '';
}
private $_mc = null;
private $_exp = null;
// cache of most recently fetched id
private $_lm = null;
private $_data = null;
private $_id = null;
/**
* Fetch data and timestamp from memcache, store in instance
*
* @param string $id
*
* @return bool success
*/
private function _fetch($id)
{
if ($this->_id === $id) {
return true;
}
$ret = $this->_mc->get($id);
if (false === $ret) {
$this->_id = null;
return false;
}
list($this->_lm, $this->_data) = explode('|', $ret, 2);
$this->_id = $id;
return true;
}
}
lib/Minify/Cache/APC.php 0000666 00000005321 13634722572 0010704 0 ustar 00
* Minify::setCache(new Minify_Cache_APC());
*
*
* @package Minify
* @author Chris Edwards
**/
class Minify_Cache_APC implements Minify_CacheInterface
{
/**
* Create a Minify_Cache_APC object, to be passed to
* Minify::setCache().
*
*
* @param int $expire seconds until expiration (default = 0
* meaning the item will not get an expiration date)
*
* @return null
*/
public function __construct($expire = 0)
{
$this->_exp = $expire;
}
/**
* Write data to cache.
*
* @param string $id cache id
*
* @param string $data
*
* @return bool success
*/
public function store($id, $data)
{
return apc_store($id, "{$_SERVER['REQUEST_TIME']}|{$data}", $this->_exp);
}
/**
* Get the size of a cache entry
*
* @param string $id cache id
*
* @return int size in bytes
*/
public function getSize($id)
{
if (! $this->_fetch($id)) {
return false;
}
if (function_exists('mb_strlen') && ((int)ini_get('mbstring.func_overload') & 2)) {
return mb_strlen($this->_data, '8bit');
} else {
return strlen($this->_data);
}
}
/**
* Does a valid cache entry exist?
*
* @param string $id cache id
*
* @param int $srcMtime mtime of the original source file(s)
*
* @return bool exists
*/
public function isValid($id, $srcMtime)
{
return ($this->_fetch($id) && ($this->_lm >= $srcMtime));
}
/**
* Send the cached content to output
*
* @param string $id cache id
*/
public function display($id)
{
echo $this->_fetch($id) ? $this->_data : '';
}
/**
* Fetch the cached content
*
* @param string $id cache id
*
* @return string
*/
public function fetch($id)
{
return $this->_fetch($id) ? $this->_data : '';
}
private $_exp = null;
// cache of most recently fetched id
private $_lm = null;
private $_data = null;
private $_id = null;
/**
* Fetch data and timestamp from apc, store in instance
*
* @param string $id
*
* @return bool success
*/
private function _fetch($id)
{
if ($this->_id === $id) {
return true;
}
$ret = apc_fetch($id);
if (false === $ret) {
$this->_id = null;
return false;
}
list($this->_lm, $this->_data) = explode('|', $ret, 2);
$this->_id = $id;
return true;
}
}
lib/Minify/Cache/ZendPlatform.php 0000666 00000005166 13634722572 0012715 0 ustar 00
* Minify::setCache(new Minify_Cache_ZendPlatform());
*
*
* @package Minify
* @author Patrick van Dissel
*/
class Minify_Cache_ZendPlatform implements Minify_CacheInterface
{
/**
* Create a Minify_Cache_ZendPlatform object, to be passed to
* Minify::setCache().
*
* @param int $expire seconds until expiration (default = 0
* meaning the item will not get an expiration date)
*
*/
public function __construct($expire = 0)
{
$this->_exp = $expire;
}
/**
* Write data to cache.
*
* @param string $id cache id
*
* @param string $data
*
* @return bool success
*/
public function store($id, $data)
{
return output_cache_put($id, "{$_SERVER['REQUEST_TIME']}|{$data}");
}
/**
* Get the size of a cache entry
*
* @param string $id cache id
*
* @return int size in bytes
*/
public function getSize($id)
{
return $this->_fetch($id) ? strlen($this->_data) : false;
}
/**
* Does a valid cache entry exist?
*
* @param string $id cache id
*
* @param int $srcMtime mtime of the original source file(s)
*
* @return bool exists
*/
public function isValid($id, $srcMtime)
{
return ($this->_fetch($id) && ($this->_lm >= $srcMtime));
}
/**
* Send the cached content to output
*
* @param string $id cache id
*/
public function display($id)
{
echo $this->_fetch($id) ? $this->_data : '';
}
/**
* Fetch the cached content
*
* @param string $id cache id
*
* @return string
*/
public function fetch($id)
{
return $this->_fetch($id) ? $this->_data : '';
}
private $_exp = null;
// cache of most recently fetched id
private $_lm = null;
private $_data = null;
private $_id = null;
/**
* Fetch data and timestamp from ZendPlatform, store in instance
*
* @param string $id
*
* @return bool success
*/
private function _fetch($id)
{
if ($this->_id === $id) {
return true;
}
$ret = output_cache_get($id, $this->_exp);
if (false === $ret) {
$this->_id = null;
return false;
}
list($this->_lm, $this->_data) = explode('|', $ret, 2);
$this->_id = $id;
return true;
}
}
lib/Minify/Cache/Null.php 0000666 00000002424 13634722572 0011214 0 ustar 00 locking = $fileLocking;
$this->path = $path;
if (!$logger) {
$logger = new \Monolog\Logger('minify');
}
$this->logger = $logger;
}
/**
* Write data to cache.
*
* @param string $id cache id (e.g. a filename)
*
* @param string $data
*
* @return bool success
*/
public function store($id, $data)
{
$flag = $this->locking ? LOCK_EX : null;
$file = $this->path . '/' . $id;
if (! @file_put_contents($file, $data, $flag)) {
$this->logger->warning("Minify_Cache_File: Write failed to '$file'");
}
// write control
if ($data !== $this->fetch($id)) {
@unlink($file);
$this->logger->warning("Minify_Cache_File: Post-write read failed for '$file'");
return false;
}
return true;
}
/**
* Get the size of a cache entry
*
* @param string $id cache id (e.g. a filename)
*
* @return int size in bytes
*/
public function getSize($id)
{
return filesize($this->path . '/' . $id);
}
/**
* Does a valid cache entry exist?
*
* @param string $id cache id (e.g. a filename)
*
* @param int $srcMtime mtime of the original source file(s)
*
* @return bool exists
*/
public function isValid($id, $srcMtime)
{
$file = $this->path . '/' . $id;
return (is_file($file) && (filemtime($file) >= $srcMtime));
}
/**
* Send the cached content to output
*
* @param string $id cache id (e.g. a filename)
*/
public function display($id)
{
if (!$this->locking) {
readfile($this->path . '/' . $id);
return;
}
$fp = fopen($this->path . '/' . $id, 'rb');
flock($fp, LOCK_SH);
fpassthru($fp);
flock($fp, LOCK_UN);
fclose($fp);
}
/**
* Fetch the cached content
*
* @param string $id cache id (e.g. a filename)
*
* @return string
*/
public function fetch($id)
{
if (!$this->locking) {
return file_get_contents($this->path . '/' . $id);
}
$fp = fopen($this->path . '/' . $id, 'rb');
if (!$fp) {
return false;
}
flock($fp, LOCK_SH);
$ret = stream_get_contents($fp);
flock($fp, LOCK_UN);
fclose($fp);
return $ret;
}
/**
* Fetch the cache path used
*
* @return string
*/
public function getPath()
{
return $this->path;
}
/**
* Get a usable temp directory
*
* @return string
* @deprecated
*/
public static function tmp()
{
trigger_error(__METHOD__ . ' is deprecated in Minfy 3.0', E_USER_DEPRECATED);
return sys_get_temp_dir();
}
/**
* Send message to the Minify logger
* @param string $msg
* @return null
* @deprecated Use $this->logger
*/
protected function _log($msg)
{
trigger_error(__METHOD__ . ' is deprecated in Minify 3.0.', E_USER_DEPRECATED);
$this->logger->warning($msg);
}
}
lib/Minify/Cache/XCache.php 0000666 00000005413 13634722572 0011436 0 ustar 00
* Minify::setCache(new Minify_Cache_XCache());
*
*
* @package Minify
* @author Elan Ruusamäe
**/
class Minify_Cache_XCache implements Minify_CacheInterface
{
/**
* Create a Minify_Cache_XCache object, to be passed to
* Minify::setCache().
*
* @param int $expire seconds until expiration (default = 0
* meaning the item will not get an expiration date)
*/
public function __construct($expire = 0)
{
$this->_exp = $expire;
}
/**
* Write data to cache.
*
* @param string $id cache id
* @param string $data
* @return bool success
*/
public function store($id, $data)
{
return xcache_set($id, "{$_SERVER['REQUEST_TIME']}|{$data}", $this->_exp);
}
/**
* Get the size of a cache entry
*
* @param string $id cache id
* @return int size in bytes
*/
public function getSize($id)
{
if (! $this->_fetch($id)) {
return false;
}
if (function_exists('mb_strlen') && ((int)ini_get('mbstring.func_overload') & 2)) {
return mb_strlen($this->_data, '8bit');
} else {
return strlen($this->_data);
}
}
/**
* Does a valid cache entry exist?
*
* @param string $id cache id
* @param int $srcMtime mtime of the original source file(s)
* @return bool exists
*/
public function isValid($id, $srcMtime)
{
return ($this->_fetch($id) && ($this->_lm >= $srcMtime));
}
/**
* Send the cached content to output
*
* @param string $id cache id
*/
public function display($id)
{
echo $this->_fetch($id) ? $this->_data : '';
}
/**
* Fetch the cached content
*
* @param string $id cache id
* @return string
*/
public function fetch($id)
{
return $this->_fetch($id) ? $this->_data : '';
}
private $_exp = null;
// cache of most recently fetched id
private $_lm = null;
private $_data = null;
private $_id = null;
/**
* Fetch data and timestamp from xcache, store in instance
*
* @param string $id
* @return bool success
*/
private function _fetch($id)
{
if ($this->_id === $id) {
return true;
}
$ret = xcache_get($id);
if (false === $ret) {
$this->_id = null;
return false;
}
list($this->_lm, $this->_data) = explode('|', $ret, 2);
$this->_id = $id;
return true;
}
}
lib/Minify/Cache/WinCache.php 0000666 00000005703 13634722572 0011766 0 ustar 00
* Minify::setCache(new Minify_Cache_WinCache());
*
*
* @package Minify
* @author Matthias Fax
**/
class Minify_Cache_WinCache implements Minify_CacheInterface
{
/**
* Create a Minify_Cache_Wincache object, to be passed to
* Minify::setCache().
*
* @param int $expire seconds until expiration (default = 0
* meaning the item will not get an expiration date)
*
* @throws Exception
*/
public function __construct($expire = 0)
{
if (!function_exists('wincache_ucache_info')) {
throw new Exception("WinCache for PHP is not installed to be able to use Minify_Cache_WinCache!");
}
$this->_exp = $expire;
}
/**
* Write data to cache.
*
* @param string $id cache id
*
* @param string $data
*
* @return bool success
*/
public function store($id, $data)
{
return wincache_ucache_set($id, "{$_SERVER['REQUEST_TIME']}|{$data}", $this->_exp);
}
/**
* Get the size of a cache entry
*
* @param string $id cache id
*
* @return int size in bytes
*/
public function getSize($id)
{
if (!$this->_fetch($id)) {
return false;
}
if (function_exists('mb_strlen') && ((int) ini_get('mbstring.func_overload') & 2)) {
return mb_strlen($this->_data, '8bit');
} else {
return strlen($this->_data);
}
}
/**
* Does a valid cache entry exist?
*
* @param string $id cache id
*
* @param int $srcMtime mtime of the original source file(s)
*
* @return bool exists
*/
public function isValid($id, $srcMtime)
{
return ($this->_fetch($id) && ($this->_lm >= $srcMtime));
}
/**
* Send the cached content to output
*
* @param string $id cache id
*/
public function display($id)
{
echo $this->_fetch($id) ? $this->_data : '';
}
/**
* Fetch the cached content
*
* @param string $id cache id
*
* @return string
*/
public function fetch($id)
{
return $this->_fetch($id) ? $this->_data : '';
}
private $_exp = null;
// cache of most recently fetched id
private $_lm = null;
private $_data = null;
private $_id = null;
/**
* Fetch data and timestamp from WinCache, store in instance
*
* @param string $id
*
* @return bool success
*/
private function _fetch($id)
{
if ($this->_id === $id) {
return true;
}
$suc = false;
$ret = wincache_ucache_get($id, $suc);
if (!$suc) {
$this->_id = null;
return false;
}
list($this->_lm, $this->_data) = explode('|', $ret, 2);
$this->_id = $id;
return true;
}
} lib/Minify/Env.php 0000666 00000006213 13634722572 0010027 0 ustar 00 server['DOCUMENT_ROOT'];
}
/**
* @return string
*/
public function getRequestUri()
{
return $this->server['REQUEST_URI'];
}
public function __construct($options = array())
{
$options = array_merge(array(
'server' => $_SERVER,
'get' => $_GET,
'post' => $_POST,
'cookie' => $_COOKIE,
), $options);
$this->server = $options['server'];
if (empty($this->server['DOCUMENT_ROOT'])) {
$this->server['DOCUMENT_ROOT'] = $this->computeDocRoot($options['server']);
} else {
$this->server['DOCUMENT_ROOT'] = rtrim($this->server['DOCUMENT_ROOT'], '/\\');
}
$this->server['DOCUMENT_ROOT'] = $this->normalizePath($this->server['DOCUMENT_ROOT']);
$this->get = $options['get'];
$this->post = $options['post'];
$this->cookie = $options['cookie'];
}
public function server($key = null)
{
if (null === $key) {
return $this->server;
}
return isset($this->server[$key]) ? $this->server[$key] : null;
}
public function cookie($key = null, $default = null)
{
if (null === $key) {
return $this->cookie;
}
return isset($this->cookie[$key]) ? $this->cookie[$key] : $default;
}
public function get($key = null, $default = null)
{
if (null === $key) {
return $this->get;
}
return isset($this->get[$key]) ? $this->get[$key] : $default;
}
public function post($key = null, $default = null)
{
if (null === $key) {
return $this->post;
}
return isset($this->post[$key]) ? $this->post[$key] : $default;
}
/**
* turn windows-style slashes into unix-style,
* remove trailing slash
* and lowercase drive letter
*
* @param string $path absolute path
*
* @return string
*/
public function normalizePath($path)
{
$realpath = realpath($path);
if ($realpath) {
$path = $realpath;
}
$path = str_replace('\\', '/', $path);
$path = rtrim($path, '/');
if (substr($path, 1, 1) === ':') {
$path = lcfirst($path);
}
return $path;
}
protected $server;
protected $get;
protected $post;
protected $cookie;
/**
* Compute $_SERVER['DOCUMENT_ROOT'] for IIS using SCRIPT_FILENAME and SCRIPT_NAME.
*
* @param array $server
* @return string
*/
protected function computeDocRoot(array $server)
{
if (isset($server['SERVER_SOFTWARE']) && 0 !== strpos($server['SERVER_SOFTWARE'], 'Microsoft-IIS/')) {
throw new InvalidArgumentException('DOCUMENT_ROOT is not provided and could not be computed');
}
$substrLength = strlen($server['SCRIPT_FILENAME']) - strlen($server['SCRIPT_NAME']);
$docRoot = substr($server['SCRIPT_FILENAME'], 0, $substrLength);
return rtrim($docRoot, '\\');
}
}
lib/Minify/Config.php 0000666 00000002047 13634722572 0010505 0 ustar 00
*
* @todo can use a stream wrapper to unit test this?
*/
class Minify_JS_ClosureCompiler
{
/**
* @var string The option key for the maximum POST byte size
*/
const OPTION_MAX_BYTES = 'maxBytes';
/**
* @var string The option key for additional params. @see __construct
*/
const OPTION_ADDITIONAL_OPTIONS = 'additionalParams';
/**
* @var string The option key for the fallback Minifier
*/
const OPTION_FALLBACK_FUNCTION = 'fallbackFunc';
/**
* @var string The option key for the service URL
*/
const OPTION_COMPILER_URL = 'compilerUrl';
/**
* @var int The default maximum POST byte size according to https://developers.google.com/closure/compiler/docs/api-ref
*/
const DEFAULT_MAX_BYTES = 200000;
/**
* @var string[] $DEFAULT_OPTIONS The default options to pass to the compiler service
*
* @note This would be a constant if PHP allowed it
*/
private static $DEFAULT_OPTIONS = array(
'output_format' => 'text',
'compilation_level' => 'SIMPLE_OPTIMIZATIONS'
);
/**
* @var string $url URL of compiler server. defaults to Google's
*/
protected $serviceUrl = 'https://closure-compiler.appspot.com/compile';
/**
* @var int $maxBytes The maximum JS size that can be sent to the compiler server in bytes
*/
protected $maxBytes = self::DEFAULT_MAX_BYTES;
/**
* @var string[] $additionalOptions Additional options to pass to the compiler service
*/
protected $additionalOptions = array();
/**
* @var callable Function to minify JS if service fails. Default is JSMin
*/
protected $fallbackMinifier = array('JSMin\\JSMin', 'minify');
/**
* Minify JavaScript code via HTTP request to a Closure Compiler API
*
* @param string $js input code
* @param array $options Options passed to __construct(). @see __construct
*
* @return string
*/
public static function minify($js, array $options = array())
{
$obj = new self($options);
return $obj->min($js);
}
/**
* @param array $options Options with keys available below:
*
* fallbackFunc : (callable) function to minify if service unavailable. Default is JSMin.
*
* compilerUrl : (string) URL to closure compiler server
*
* maxBytes : (int) The maximum amount of bytes to be sent as js_code in the POST request.
* Defaults to 200000.
*
* additionalParams : (string[]) Additional parameters to pass to the compiler server. Can be anything named
* in https://developers.google.com/closure/compiler/docs/api-ref except for js_code and
* output_info
*/
public function __construct(array $options = array())
{
if (isset($options[self::OPTION_FALLBACK_FUNCTION])) {
$this->fallbackMinifier = $options[self::OPTION_FALLBACK_FUNCTION];
}
if (isset($options[self::OPTION_COMPILER_URL])) {
$this->serviceUrl = $options[self::OPTION_COMPILER_URL];
}
if (isset($options[self::OPTION_ADDITIONAL_OPTIONS]) && is_array($options[self::OPTION_ADDITIONAL_OPTIONS])) {
$this->additionalOptions = $options[self::OPTION_ADDITIONAL_OPTIONS];
}
if (isset($options[self::OPTION_MAX_BYTES])) {
$this->maxBytes = (int) $options[self::OPTION_MAX_BYTES];
}
}
/**
* Call the service to perform the minification
*
* @param string $js JavaScript code
* @return string
* @throws Minify_JS_ClosureCompiler_Exception
*/
public function min($js)
{
$postBody = $this->buildPostBody($js);
if ($this->maxBytes > 0) {
$bytes = (function_exists('mb_strlen') && ((int)ini_get('mbstring.func_overload') & 2))
? mb_strlen($postBody, '8bit')
: strlen($postBody);
if ($bytes > $this->maxBytes) {
throw new Minify_JS_ClosureCompiler_Exception(
'POST content larger than ' . $this->maxBytes . ' bytes'
);
}
}
$response = $this->getResponse($postBody);
if (preg_match('/^Error\(\d\d?\):/', $response)) {
if (is_callable($this->fallbackMinifier)) {
// use fallback
$response = "/* Received errors from Closure Compiler API:\n$response"
. "\n(Using fallback minifier)\n*/\n";
$response .= call_user_func($this->fallbackMinifier, $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;
}
/**
* Get the response for a given POST body
*
* @param string $postBody
* @return string
* @throws Minify_JS_ClosureCompiler_Exception
*/
protected function getResponse($postBody)
{
$allowUrlFopen = preg_match('/1|yes|on|true/i', ini_get('allow_url_fopen'));
if ($allowUrlFopen) {
$contents = file_get_contents($this->serviceUrl, false, stream_context_create(array(
'http' => array(
'method' => 'POST',
'compilation_level' => 'SIMPLE',
'output_format' => 'text',
'output_info' => 'compiled_code',
'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($this->serviceUrl);
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);
}
/**
* Build a POST request body
*
* @param string $js JavaScript code
* @param bool $returnErrors
* @return string
*/
protected function buildPostBody($js, $returnErrors = false)
{
return http_build_query(
array_merge(
self::$DEFAULT_OPTIONS,
$this->additionalOptions,
array(
'js_code' => $js,
'output_info' => ($returnErrors ? 'errors' : 'compiled_code')
)
),
null,
'&'
);
}
}
class Minify_JS_ClosureCompiler_Exception extends Exception
{
}
lib/Minify/JS/JShrink.php 0000666 00000002332 13634722572 0011161 0 ustar 00
* @link https://github.com/tedious/JShrink
*
*/
class JShrink
{
/**
* Contains the default options for minification. This array is merged with
* the one passed in by the user to create the request specific set of
* options (stored in the $options attribute).
*
* @var string[]
*/
protected static $defaultOptions = array('flaggedComments' => true);
/**
* Takes a string containing javascript and removes unneeded characters in
* order to shrink the code without altering it's functionality.
*
* @param string $js The raw javascript to be minified
* @param array $options Various runtime options in an associative array
*
* @see JShrink\Minifier::minify()
* @return string
*/
public static function minify($js, array $options = array())
{
$options = array_merge(
self::$defaultOptions,
$options
);
return \JShrink\Minifier::minify($js, $options);
}
}
lib/Minify/SourceInterface.php 0000666 00000002624 13634722572 0012362 0 ustar 00
* Minify_ClosureCompiler::$jarFile = '/path/to/closure-compiler-20120123.jar';
* Minify_ClosureCompiler::$tempDir = '/tmp';
* $code = Minify_ClosureCompiler::minify(
* $code,
* array('compilation_level' => 'SIMPLE_OPTIMIZATIONS')
* );
*
* --compilation_level WHITESPACE_ONLY, SIMPLE_OPTIMIZATIONS, ADVANCED_OPTIMIZATIONS
*
*
*
* @package Minify
* @author Stephen Clay
* @author Elan Ruusamäe
*/
class Minify_ClosureCompiler
{
public static $isDebug = false;
/**
* Filepath of the Closure Compiler jar file. This must be set before
* calling minifyJs().
*
* @var string
*/
public static $jarFile;
/**
* Writable temp directory. This must be set before calling minifyJs().
*
* @var string
*/
public static $tempDir;
/**
* Filepath of "java" executable (may be needed if not in shell's PATH)
*
* @var string
*/
public static $javaExecutable = 'java';
/**
* Default command line options passed to closure-compiler
*
* @var array
*/
public static $defaultOptions = array(
'charset' => 'utf-8',
'compilation_level' => 'SIMPLE_OPTIMIZATIONS',
'warning_level' => 'QUIET',
);
/**
* Minify a Javascript string
*
* @param string $js
* @param array $options (verbose is ignored)
* @see https://code.google.com/p/closure-compiler/source/browse/trunk/README
* @return string
* @throws Minify_ClosureCompiler_Exception
*/
public static function minify($js, $options = array())
{
$min = new static();
return $min->process($js, $options);
}
/**
* Process $js using $options.
*
* @param string $js
* @param array $options
* @return string
* @throws Exception
* @throws Minify_ClosureCompiler_Exception
*/
public function process($js, $options)
{
$tmpFile = $this->dumpFile(self::$tempDir, $js);
try {
$result = $this->compile($tmpFile, $options);
} catch (Exception $e) {
unlink($tmpFile);
throw $e;
}
unlink($tmpFile);
return $result;
}
/**
* @param string $tmpFile
* @param array $options
* @return string
* @throws Minify_ClosureCompiler_Exception
*/
protected function compile($tmpFile, $options)
{
$command = $this->getCommand($options, $tmpFile);
return implode("\n", $this->shell($command));
}
/**
* @param array $userOptions
* @param string $tmpFile
* @return string
*/
protected function getCommand($userOptions, $tmpFile)
{
$args = array_merge(
$this->getCompilerCommandLine(),
$this->getOptionsCommandLine($userOptions)
);
return implode(' ', $args) . ' ' . escapeshellarg($tmpFile);
}
/**
* @return array
* @throws Minify_ClosureCompiler_Exception
*/
protected function getCompilerCommandLine()
{
$this->checkJar(self::$jarFile);
$server = array(
self::$javaExecutable,
'-jar',
escapeshellarg(self::$jarFile)
);
return $server;
}
/**
* @param array $userOptions
* @return array
*/
protected function getOptionsCommandLine($userOptions)
{
$args = array();
$options = array_merge(
static::$defaultOptions,
$userOptions
);
foreach ($options as $key => $value) {
$args[] = "--{$key} " . escapeshellarg($value);
}
return $args;
}
/**
* @param string $jarFile
* @throws Minify_ClosureCompiler_Exception
*/
protected function checkJar($jarFile)
{
if (!is_file($jarFile)) {
throw new Minify_ClosureCompiler_Exception('$jarFile(' . $jarFile . ') is not a valid file.');
}
if (!is_readable($jarFile)) {
throw new Minify_ClosureCompiler_Exception('$jarFile(' . $jarFile . ') is not readable.');
}
}
/**
* @param string $tempDir
* @throws Minify_ClosureCompiler_Exception
*/
protected function checkTempdir($tempDir)
{
if (!is_dir($tempDir)) {
throw new Minify_ClosureCompiler_Exception('$tempDir(' . $tempDir . ') is not a valid direcotry.');
}
if (!is_writable($tempDir)) {
throw new Minify_ClosureCompiler_Exception('$tempDir(' . $tempDir . ') is not writable.');
}
}
/**
* Write $content to a temporary file residing in $dir.
*
* @param string $dir
* @param string $content
* @return string
* @throws Minify_ClosureCompiler_Exception
*/
protected function dumpFile($dir, $content)
{
$this->checkTempdir($dir);
$tmpFile = tempnam($dir, 'cc_');
if (!$tmpFile) {
throw new Minify_ClosureCompiler_Exception('Could not create temp file in "' . $dir . '".');
}
file_put_contents($tmpFile, $content);
return $tmpFile;
}
/**
* Execute command, throw if exit code is not in $expectedCodes array
*
* @param string $command
* @param array $expectedCodes
* @return mixed
* @throws Minify_ClosureCompiler_Exception
*/
protected function shell($command, $expectedCodes = array(0))
{
exec($command, $output, $result_code);
if (!in_array($result_code, $expectedCodes)) {
throw new Minify_ClosureCompiler_Exception("Unpexpected return code: $result_code");
}
return $output;
}
}
class Minify_ClosureCompiler_Exception extends Exception
{
}
lib/Minify/Controller/Base.php 0000666 00000003361 13634722572 0012275 0 ustar 00
*/
abstract class Minify_Controller_Base implements Minify_ControllerInterface
{
/**
* @var Minify_Env
*/
protected $env;
/**
* @var Minify_Source_Factory
*/
protected $sourceFactory;
/**
* @var LoggerInterface
*/
protected $logger;
/**
* @param Minify_Env $env
* @param Minify_Source_Factory $sourceFactory
* @param LoggerInterface $logger
*/
public function __construct(Minify_Env $env, Minify_Source_Factory $sourceFactory, LoggerInterface $logger = null)
{
$this->env = $env;
$this->sourceFactory = $sourceFactory;
if (!$logger) {
$logger = new Logger('minify');
}
$this->logger = $logger;
}
/**
* Create controller sources and options for Minify::serve()
*
* @param array $options controller and Minify options
*
* @return Minify_ServeConfiguration
*/
abstract public function createConfiguration(array $options);
/**
* Send message to the Minify logger
*
* @param string $msg
*
* @return null
* @deprecated use $this->logger
*/
public function log($msg)
{
trigger_error(__METHOD__ . ' is deprecated in Minify 3.0.', E_USER_DEPRECATED);
$this->logger->info($msg);
}
/**
* {@inheritdoc}
*/
public function getEnv()
{
return $this->env;
}
}
lib/Minify/Controller/Groups.php 0000666 00000004106 13634722572 0012700 0 ustar 00
* Minify::serve('Groups', array(
* 'groups' => array(
* 'css' => array('//css/type.css', '//css/layout.css')
* ,'js' => array('//js/jquery.js', '//js/site.js')
* )
* ));
*
*
* If the above code were placed in /serve.php, it would enable the URLs
* /serve.php/js and /serve.php/css
*
* @package Minify
* @author Stephen Clay
*/
class Minify_Controller_Groups extends Minify_Controller_Files
{
/**
* Set up groups of files as sources
*
* @param array $options controller and Minify options
*
* 'groups': (required) array mapping PATH_INFO strings to arrays
* of complete file paths. @see Minify_Controller_Groups
*
* @return array Minify options
*/
public function createConfiguration(array $options)
{
// strip controller options
$groups = $options['groups'];
unset($options['groups']);
$server = $this->env->server();
// mod_fcgid places PATH_INFO in ORIG_PATH_INFO
if (isset($server['ORIG_PATH_INFO'])) {
$pathInfo = substr($server['ORIG_PATH_INFO'], 1);
} elseif (isset($server['PATH_INFO'])) {
$pathInfo = substr($server['PATH_INFO'], 1);
} else {
$pathInfo = false;
}
if (false === $pathInfo || ! isset($groups[$pathInfo])) {
// no PATH_INFO or not a valid group
$this->logger->info("Missing PATH_INFO or no group set for \"$pathInfo\"");
return new Minify_ServeConfiguration($options);
}
$files = $groups[$pathInfo];
// if $files is a single object, casting will break it
if (is_object($files)) {
$files = array($files);
} elseif (! is_array($files)) {
$files = (array)$files;
}
$options['files'] = $files;
return parent::createConfiguration($options);
}
}
lib/Minify/Controller/MinApp.php 0000666 00000016064 13634722572 0012613 0 ustar 00
*/
class Minify_Controller_MinApp extends Minify_Controller_Base
{
/**
* Set up groups of files as sources
*
* @param array $options controller and Minify options
*
* @return array Minify options
*/
public function createConfiguration(array $options)
{
// PHP insecure by default: realpath() and other FS functions can't handle null bytes.
$get = $this->env->get();
foreach (array('g', 'b', 'f') as $key) {
if (isset($get[$key])) {
$get[$key] = str_replace("\x00", '', (string)$get[$key]);
}
}
// filter controller options
$defaults = array(
'groupsOnly' => false,
'groups' => array(),
'symlinks' => array(),
);
$minApp = isset($options['minApp']) ? $options['minApp'] : array();
$localOptions = array_merge($defaults, $minApp);
unset($options['minApp']);
// normalize $symlinks in order to map to target
$symlinks = array();
foreach ($localOptions['symlinks'] as $link => $target) {
if (0 === strpos($link, '//')) {
$link = rtrim(substr($link, 1), '/') . '/';
$target = rtrim($target, '/\\');
$symlinks[$link] = $target;
}
}
$sources = array();
$selectionId = '';
$firstMissing = null;
if (isset($get['g'])) {
// add group(s)
$selectionId .= 'g=' . $get['g'];
$keys = explode(',', $get['g']);
if ($keys != array_unique($keys)) {
$this->logger->info("Duplicate group key found.");
return new Minify_ServeConfiguration($options);
}
foreach ($keys as $key) {
if (! isset($localOptions['groups'][$key])) {
$this->logger->info("A group configuration for \"{$key}\" was not found");
return new Minify_ServeConfiguration($options);
}
$files = $localOptions['groups'][$key];
// if $files is a single object, casting will break it
if (is_object($files)) {
$files = array($files);
} elseif (! is_array($files)) {
$files = (array)$files;
}
foreach ($files as $file) {
try {
$source = $this->sourceFactory->makeSource($file);
$sources[] = $source;
} catch (Minify_Source_FactoryException $e) {
$this->logger->error($e->getMessage());
if (null === $firstMissing) {
$firstMissing = basename($file);
continue;
} else {
$secondMissing = basename($file);
$this->logger->info("More than one file was missing: '$firstMissing', '$secondMissing'");
return new Minify_ServeConfiguration($options);
}
}
}
}
}
if (! $localOptions['groupsOnly'] && isset($get['f'])) {
// try user files
// The following restrictions are to limit the URLs that minify will
// respond to.
// verify at least one file, files are single comma separated, and are all same extension
$validPattern = preg_match('/^[^,]+\\.(css|less|scss|js)(?:,[^,]+\\.\\1)*$/', $get['f'], $m);
$hasComment = strpos($get['f'], '//') !== false;
$hasEscape = strpos($get['f'], '\\') !== false;
if (!$validPattern || $hasComment || $hasEscape) {
$this->logger->info("GET param 'f' was invalid");
return new Minify_ServeConfiguration($options);
}
$ext = ".{$m[1]}";
$files = explode(',', $get['f']);
if ($files != array_unique($files)) {
$this->logger->info("Duplicate files were specified");
return new Minify_ServeConfiguration($options);
}
if (isset($get['b'])) {
// check for validity
$isValidBase = preg_match('@^[^/]+(?:/[^/]+)*$@', $get['b']);
$hasDots = false !== strpos($get['b'], '..');
$isDot = $get['b'] === '.';
if ($isValidBase && !$hasDots && !$isDot) {
// valid base
$base = "/{$get['b']}/";
} else {
$this->logger->info("GET param 'b' was invalid");
return new Minify_ServeConfiguration($options);
}
} else {
$base = '/';
}
$basenames = array(); // just for cache id
foreach ($files as $file) {
$uri = $base . $file;
$path = $this->env->getDocRoot() . $uri;
// try to rewrite path
foreach ($symlinks as $link => $target) {
if (0 === strpos($uri, $link)) {
$path = $target . DIRECTORY_SEPARATOR . substr($uri, strlen($link));
break;
}
}
try {
$source = $this->sourceFactory->makeSource($path);
$sources[] = $source;
$basenames[] = basename($path, $ext);
} catch (Minify_Source_FactoryException $e) {
$this->logger->error($e->getMessage());
if (null === $firstMissing) {
$firstMissing = $uri;
continue;
} else {
$secondMissing = $uri;
$this->logger->info("More than one file was missing: '$firstMissing', '$secondMissing`'");
return new Minify_ServeConfiguration($options);
}
}
}
if ($selectionId) {
$selectionId .= '_f=';
}
$selectionId .= implode(',', $basenames) . $ext;
}
if (!$sources) {
$this->logger->info("No sources to serve");
return new Minify_ServeConfiguration($options);
}
if (null !== $firstMissing) {
array_unshift($sources, new Minify_Source(array(
'id' => 'missingFile',
// should not cause cache invalidation
'lastModified' => 0,
// due to caching, filename is unreliable.
'content' => "/* Minify: at least one missing file. See " . Minify::URL_DEBUG . " */\n",
'minifier' => 'Minify::nullMinifier',
)));
}
return new Minify_ServeConfiguration($options, $sources, $selectionId);
}
}
lib/Minify/Controller/Files.php 0000666 00000003462 13634722572 0012467 0 ustar 00
* $options = [
* 'checkAllowDirs' => false, // allow files to be anywhere
* ];
* $sourceFactory = new Minify_Source_Factory($env, $options, $cache);
* $controller = new Minify_Controller_Files($env, $sourceFactory);
* $minify->serve($controller, [
* 'files' => [
* '//js/jquery.js',
* '//js/plugins.js',
* '/home/username/file.js',
* ],
* ]);
*
*
* @package Minify
* @author Stephen Clay
*/
class Minify_Controller_Files extends Minify_Controller_Base
{
/**
* Set up file sources
*
* @param array $options controller and Minify options
* @return Minify_ServeConfiguration
*
* Controller options:
*
* 'files': (required) array of complete file paths, or a single path
*/
public function createConfiguration(array $options)
{
// strip controller options
$files = $options['files'];
// if $files is a single object, casting will break it
if (is_object($files)) {
$files = array($files);
} elseif (! is_array($files)) {
$files = (array)$files;
}
unset($options['files']);
$sources = array();
foreach ($files as $file) {
try {
$sources[] = $this->sourceFactory->makeSource($file);
} catch (Minify_Source_FactoryException $e) {
$this->logger->error($e->getMessage());
return new Minify_ServeConfiguration($options);
}
}
return new Minify_ServeConfiguration($options, $sources);
}
}
lib/Minify/Controller/Page.php 0000666 00000004201 13634722572 0012271 0 ustar 00
*/
class Minify_Controller_Page extends Minify_Controller_Base
{
/**
* Set up source of HTML content
*
* @param array $options controller and Minify options
* @return array Minify options
*
* Controller options:
*
* 'content': (required) HTML markup
*
* 'id': (required) id of page (string for use in server-side caching)
*
* 'lastModifiedTime': timestamp of when this content changed. This
* is recommended to allow both server and client-side caching.
*
* 'minifyAll': should all CSS and Javascript blocks be individually
* minified? (default false)
*/
public function createConfiguration(array $options)
{
if (isset($options['file'])) {
$sourceSpec = array(
'filepath' => $options['file']
);
$f = $options['file'];
} else {
// strip controller options
$sourceSpec = array(
'content' => $options['content'],
'id' => $options['id'],
);
$f = $options['id'];
unset($options['content'], $options['id']);
}
// something like "builder,index.php" or "directory,file.html"
$selectionId = strtr(substr($f, 1 + strlen(dirname(dirname($f)))), '/\\', ',,');
if (isset($options['minifyAll'])) {
// this will be the 2nd argument passed to Minify_HTML::minify()
$sourceSpec['minifyOptions'] = array(
'cssMinifier' => array('Minify_CSSmin', 'minify'),
'jsMinifier' => array('JSMin\\JSMin', 'minify'),
);
unset($options['minifyAll']);
}
$sourceSpec['contentType'] = Minify::TYPE_HTML;
$sources[] = new Minify_Source($sourceSpec);
return new Minify_ServeConfiguration($options, $sources, $selectionId);
}
}
lib/Minify/ImportProcessor.php 0000666 00000016451 13634722572 0012456 0 ustar 00
* @author Simon Schick
*/
class Minify_ImportProcessor
{
public static $filesIncluded = array();
public static function process($file)
{
self::$filesIncluded = array();
self::$_isCss = (strtolower(substr($file, -4)) === '.css');
$obj = new Minify_ImportProcessor(dirname($file));
return $obj->_getContent($file);
}
// allows callback funcs to know the current directory
private $_currentDir;
// allows callback funcs to know the directory of the file that inherits this one
private $_previewsDir;
// allows _importCB to write the fetched content back to the obj
private $_importedContent = '';
private static $_isCss;
/**
* @param String $currentDir
* @param String $previewsDir Is only used internally
*/
private function __construct($currentDir, $previewsDir = "")
{
$this->_currentDir = $currentDir;
$this->_previewsDir = $previewsDir;
}
private function _getContent($file, $is_imported = false)
{
$file = preg_replace('~\\?.*~', '', $file);
$file = realpath($file);
if (! $file
|| in_array($file, self::$filesIncluded)
|| false === ($content = @file_get_contents($file))) {
// file missing, already included, or failed read
return '';
}
self::$filesIncluded[] = realpath($file);
$this->_currentDir = dirname($file);
// remove UTF-8 BOM if present
if (pack("CCC",0xef,0xbb,0xbf) === substr($content, 0, 3)) {
$content = substr($content, 3);
}
// ensure uniform EOLs
$content = str_replace("\r\n", "\n", $content);
// process @imports
$pattern = '/
@import\\s+
(?:url\\(\\s*)? # maybe url(
[\'"]? # maybe quote
(.*?) # 1 = URI
[\'"]? # maybe end quote
(?:\\s*\\))? # maybe )
([a-zA-Z,\\s]*)? # 2 = media list
; # end token
/x';
$content = preg_replace_callback($pattern, array($this, '_importCB'), $content);
// You only need to rework the import-path if the script is imported
if (self::$_isCss && $is_imported) {
// rewrite remaining relative URIs
$pattern = '/url\\(\\s*([^\\)\\s]+)\\s*\\)/';
$content = preg_replace_callback($pattern, array($this, '_urlCB'), $content);
}
return $this->_importedContent . $content;
}
private function _importCB($m)
{
$url = $m[1];
$mediaList = preg_replace('/\\s+/', '', $m[2]);
if (strpos($url, '://') > 0) {
// protocol, leave in place for CSS, comment for JS
return self::$_isCss
? $m[0]
: "/* Minify_ImportProcessor will not include remote content */";
}
if ('/' === $url[0]) {
// protocol-relative or root path
$url = ltrim($url, '/');
$file = realpath($_SERVER['DOCUMENT_ROOT']) . DIRECTORY_SEPARATOR
. strtr($url, '/', DIRECTORY_SEPARATOR);
} else {
// relative to current path
$file = $this->_currentDir . DIRECTORY_SEPARATOR
. strtr($url, '/', DIRECTORY_SEPARATOR);
}
$obj = new Minify_ImportProcessor(dirname($file), $this->_currentDir);
$content = $obj->_getContent($file, true);
if ('' === $content) {
// failed. leave in place for CSS, comment for JS
return self::$_isCss
? $m[0]
: "/* Minify_ImportProcessor could not fetch '{$file}' */";
}
return (!self::$_isCss || preg_match('@(?:^$|\\ball\\b)@', $mediaList))
? $content
: "@media {$mediaList} {\n{$content}\n}\n";
}
private function _urlCB($m)
{
// $m[1] is either quoted or not
$quote = ($m[1][0] === "'" || $m[1][0] === '"') ? $m[1][0] : '';
$url = ($quote === '') ? $m[1] : substr($m[1], 1, strlen($m[1]) - 2);
if ('/' !== $url[0]) {
if (strpos($url, '//') > 0) {
// probably starts with protocol, do not alter
} else {
// prepend path with current dir separator (OS-independent)
$path = $this->_currentDir
. DIRECTORY_SEPARATOR . strtr($url, '/', DIRECTORY_SEPARATOR);
// update the relative path by the directory of the file that imported this one
$url = self::getPathDiff(realpath($this->_previewsDir), $path);
}
}
return "url({$quote}{$url}{$quote})";
}
/**
* @param string $from
* @param string $to
* @param string $ps
* @return string
*/
private function getPathDiff($from, $to, $ps = DIRECTORY_SEPARATOR)
{
$realFrom = $this->truepath($from);
$realTo = $this->truepath($to);
$arFrom = explode($ps, rtrim($realFrom, $ps));
$arTo = explode($ps, rtrim($realTo, $ps));
while (count($arFrom) && count($arTo) && ($arFrom[0] == $arTo[0])) {
array_shift($arFrom);
array_shift($arTo);
}
return str_pad("", count($arFrom) * 3, '..' . $ps) . implode($ps, $arTo);
}
/**
* This function is to replace PHP's extremely buggy realpath().
* @param string $path The original path, can be relative etc.
* @return string The resolved path, it might not exist.
* @see http://stackoverflow.com/questions/4049856/replace-phps-realpath
*/
private function truepath($path)
{
// whether $path is unix or not
$unipath = ('' === $path) || ($path{0} !== '/');
// attempts to detect if path is relative in which case, add cwd
if (strpos($path, ':') === false && $unipath) {
$path = $this->_currentDir . DIRECTORY_SEPARATOR . $path;
}
// resolve path parts (single dot, double dot and double delimiters)
$path = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $path);
$parts = array_filter(explode(DIRECTORY_SEPARATOR, $path), 'strlen');
$absolutes = array();
foreach ($parts as $part) {
if ('.' === $part) {
continue;
}
if ('..' === $part) {
array_pop($absolutes);
} else {
$absolutes[] = $part;
}
}
$path = implode(DIRECTORY_SEPARATOR, $absolutes);
// resolve any symlinks
if (file_exists($path) && linkinfo($path) > 0) {
$path = readlink($path);
}
// put initial separator that could have been lost
$path = !$unipath ? '/' . $path : $path;
return $path;
}
}
lib/Minify/LessCssSource.php 0000666 00000005512 13634722572 0012040 0 ustar 00 cache = $cache;
}
/**
* Get last modified of all parsed files
*
* @return int
*/
public function getLastModified()
{
$cache = $this->getCache();
return $cache['lastModified'];
}
/**
* Get content
*
* @return string
*/
public function getContent()
{
$cache = $this->getCache();
return $cache['compiled'];
}
/**
* Get lessphp cache object
*
* @return array
*/
private function getCache()
{
// cache for single run
// so that getLastModified and getContent in single request do not add additional cache roundtrips (i.e memcache)
if (isset($this->parsed)) {
return $this->parsed;
}
// check from cache first
$cache = null;
$cacheId = $this->getCacheId();
if ($this->cache->isValid($cacheId, 0)) {
if ($cache = $this->cache->fetch($cacheId)) {
$cache = unserialize($cache);
}
}
$less = $this->getCompiler();
$input = $cache ? $cache : $this->filepath;
$cache = $less->cachedCompile($input);
if (!is_array($input) || $cache['updated'] > $input['updated']) {
$cache['lastModified'] = $this->getMaxLastModified($cache);
$this->cache->store($cacheId, serialize($cache));
}
return $this->parsed = $cache;
}
/**
* Calculate maximum last modified of all files,
* as the 'updated' timestamp in cache is not the same as file last modified timestamp:
* @link https://github.com/leafo/lessphp/blob/v0.4.0/lessc.inc.php#L1904
* @return int
*/
private function getMaxLastModified($cache)
{
$lastModified = 0;
foreach ($cache['files'] as $mtime) {
$lastModified = max($lastModified, $mtime);
}
return $lastModified;
}
/**
* Make a unique cache id for for this source.
*
* @param string $prefix
*
* @return string
*/
private function getCacheId($prefix = 'minify')
{
$md5 = md5($this->filepath);
return "{$prefix}_less2_{$md5}";
}
/**
* Get instance of less compiler
*
* @return lessc
*/
private function getCompiler()
{
$less = new lessc();
// do not spend CPU time letting less doing minify
$less->setPreserveComments(true);
return $less;
}
}
lib/Minify/CommentPreserver.php 0000666 00000005071 13634722572 0012600 0 ustar 00
*/
class Minify_CommentPreserver
{
/**
* String to be prepended to each preserved comment
*
* @var string
*/
public static $prepend = "\n";
/**
* String to be appended to each preserved comment
*
* @var string
*/
public static $append = "\n";
/**
* Process a string outside of C-style comments that begin with "/*!"
*
* On each non-empty string outside these comments, the given processor
* function will be called. The comments will be surrounded by
* Minify_CommentPreserver::$preprend and Minify_CommentPreserver::$append.
*
* @param string $content
* @param callback $processor function
* @param array $args array of extra arguments to pass to the processor
* function (default = array())
* @return string
*/
public static function process($content, $processor, $args = array())
{
$ret = '';
while (true) {
list($beforeComment, $comment, $afterComment) = self::_nextComment($content);
if ('' !== $beforeComment) {
$callArgs = $args;
array_unshift($callArgs, $beforeComment);
$ret .= call_user_func_array($processor, $callArgs);
}
if (false === $comment) {
break;
}
$ret .= $comment;
$content = $afterComment;
}
return $ret;
}
/**
* Extract comments that YUI Compressor preserves.
*
* @param string $in input
*
* @return array 3 elements are returned. If a YUI comment is found, the
* 2nd element is the comment and the 1st and 3rd are the surrounding
* strings. If no comment is found, the entire string is returned as the
* 1st element and the other two are false.
*/
private static function _nextComment($in)
{
if (false === ($start = strpos($in, '/*!')) || false === ($end = strpos($in, '*/', $start + 3))) {
return array($in, false, false);
}
$beforeComment = substr($in, 0, $start);
$comment = self::$prepend . '/*!' . substr($in, $start + 3, $end - $start - 1) . self::$append;
$endChars = (strlen($in) - $end - 2);
$afterComment = (0 === $endChars) ? '' : substr($in, -$endChars);
return array($beforeComment, $comment, $afterComment);
}
}
lib/Minify/CSS/Compressor.php 0000666 00000020773 13634722572 0012072 0 ustar 00
* @author http://code.google.com/u/1stvamp/ (Issue 64 patch)
*
* @deprecated Use CSSmin (tubalmartin/cssmin)
*/
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
$pattern = '@\\s*/\\*([\\s\\S]*?)\\*/\\s*@';
$css = preg_replace_callback($pattern, 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
$pattern = '/
url\\( # url(
\\s*
([^\\)]+?) # 1 = the URL (really just a bunch of non right parenthesis)
\\s*
\\) # )
/x';
$css = preg_replace($pattern, 'url($1)', $css);
// remove ws between rules and colons
$pattern = '/
\\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';
$css = preg_replace($pattern, '$1$2:$3', $css);
// remove ws in selectors
$pattern = '/
(?: # non-capture
\\s*
[^~>+,\\s]+ # selector part
\\s*
[,>+~] # combinators
)+
\\s*
[^~>+,\\s]+ # selector part
{ # open declaration block
/x';
$css = preg_replace_callback($pattern, array($this, '_selectorsCB'), $css);
// minimize hex colors
$pattern = '/([^=])#([a-f\\d])\\2([a-f\\d])\\3([a-f\\d])\\4([\\s;\\}])/i';
$css = preg_replace($pattern, '$1#$2$3$4$5', $css);
// remove spaces between font families
$pattern = '/font-family:([^;}]+)([;}])/';
$css = preg_replace_callback($pattern, 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)
$pattern = '/([\\w#\\.\\*]+)\\s+([\\w#\\.\\*]+){/';
$css = preg_replace($pattern, "$1\n$2{", $css);
// Use newline after 1st numeric value (to limit line lengths).
$pattern = '/
((?:padding|margin|border|outline):\\d+(?:px|em)?) # 1 = prop : 1st numeric value
\\s+
/x';
$css = preg_replace($pattern, "$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
$pattern = '@
^/ # comment started like /*/
\\s*
(\\S[\\s\\S]+?) # has at least some non-ws content
\\s*
/\\* # ends like /*/ or /**/
@x';
if (preg_match($pattern, $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
$flags = PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY;
$pieces = preg_split('/(\'[^\']+\'|"[^"]+")/', $m[1], null, $flags);
$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];
}
}
lib/Minify/CSS/UriRewriter.php 0000666 00000024604 13634722572 0012216 0 ustar 00
*/
class Minify_CSS_UriRewriter
{
/**
* rewrite() and rewriteRelative() append debugging information here
*
* @var string
*/
public static $debugText = '';
/**
* In CSS content, rewrite file relative URIs as root relative
*
* @param string $css
*
* @param string $currentDir The directory of the current CSS file.
*
* @param string $docRoot The document root of the web site in which
* the CSS file resides (default = $_SERVER['DOCUMENT_ROOT']).
*
* @param array $symlinks (default = array()) If the CSS file is stored in
* a symlink-ed directory, provide an array of link paths to
* target paths, where the link paths are within the document root. Because
* paths need to be normalized for this to work, use "//" to substitute
* the doc root in the link paths (the array keys). E.g.:
*
* array('//symlink' => '/real/target/path') // unix
* array('//static' => 'D:\\staticStorage') // Windows
*
*
* @return string
*/
public static function rewrite($css, $currentDir, $docRoot = null, $symlinks = array())
{
self::$_docRoot = self::_realpath(
$docRoot ? $docRoot : $_SERVER['DOCUMENT_ROOT']
);
self::$_currentDir = self::_realpath($currentDir);
self::$_symlinks = array();
// normalize symlinks in order to map to link
foreach ($symlinks as $link => $target) {
$link = ($link === '//') ? self::$_docRoot : str_replace('//', self::$_docRoot . '/', $link);
$link = strtr($link, '/', DIRECTORY_SEPARATOR);
self::$_symlinks[$link] = self::_realpath($target);
}
self::$debugText .= "docRoot : " . self::$_docRoot . "\n"
. "currentDir : " . self::$_currentDir . "\n";
if (self::$_symlinks) {
self::$debugText .= "symlinks : " . var_export(self::$_symlinks, 1) . "\n";
}
self::$debugText .= "\n";
$css = self::_trimUrls($css);
$css = self::_owlifySvgPaths($css);
// rewrite
$pattern = '/@import\\s+([\'"])(.*?)[\'"]/';
$css = preg_replace_callback($pattern, array(self::$className, '_processUriCB'), $css);
$pattern = '/url\\(\\s*([\'"](.*?)[\'"]|[^\\)\\s]+)\\s*\\)/';
$css = preg_replace_callback($pattern, array(self::$className, '_processUriCB'), $css);
$css = self::_unOwlify($css);
return $css;
}
/**
* In CSS content, prepend a path to relative URIs
*
* @param string $css
*
* @param string $path The path to prepend.
*
* @return string
*/
public static function prepend($css, $path)
{
self::$_prependPath = $path;
$css = self::_trimUrls($css);
$css = self::_owlifySvgPaths($css);
// append
$pattern = '/@import\\s+([\'"])(.*?)[\'"]/';
$css = preg_replace_callback($pattern, array(self::$className, '_processUriCB'), $css);
$pattern = '/url\\(\\s*([\'"](.*?)[\'"]|[^\\)\\s]+)\\s*\\)/';
$css = preg_replace_callback($pattern, array(self::$className, '_processUriCB'), $css);
$css = self::_unOwlify($css);
self::$_prependPath = null;
return $css;
}
/**
* Get a root relative URI from a file relative URI
*
*
* Minify_CSS_UriRewriter::rewriteRelative(
* '../img/hello.gif'
* , '/home/user/www/css' // path of CSS file
* , '/home/user/www' // doc root
* );
* // returns '/img/hello.gif'
*
* // example where static files are stored in a symlinked directory
* Minify_CSS_UriRewriter::rewriteRelative(
* 'hello.gif'
* , '/var/staticFiles/theme'
* , '/home/user/www'
* , array('/home/user/www/static' => '/var/staticFiles')
* );
* // returns '/static/theme/hello.gif'
*
*
* @param string $uri file relative URI
*
* @param string $realCurrentDir realpath of the current file's directory.
*
* @param string $realDocRoot realpath of the site document root.
*
* @param array $symlinks (default = array()) If the file is stored in
* a symlink-ed directory, provide an array of link paths to
* real target paths, where the link paths "appear" to be within the document
* root. E.g.:
*
* array('/home/foo/www/not/real/path' => '/real/target/path') // unix
* array('C:\\htdocs\\not\\real' => 'D:\\real\\target\\path') // Windows
*
*
* @return string
*/
public static function rewriteRelative($uri, $realCurrentDir, $realDocRoot, $symlinks = array())
{
// prepend path with current dir separator (OS-independent)
$path = strtr($realCurrentDir, '/', DIRECTORY_SEPARATOR);
$path .= DIRECTORY_SEPARATOR . strtr($uri, '/', DIRECTORY_SEPARATOR);
self::$debugText .= "file-relative URI : {$uri}\n"
. "path prepended : {$path}\n";
// "unresolve" a symlink back to doc root
foreach ($symlinks as $link => $target) {
if (0 === strpos($path, $target)) {
// replace $target with $link
$path = $link . substr($path, strlen($target));
self::$debugText .= "symlink unresolved : {$path}\n";
break;
}
}
// strip doc root
$path = substr($path, strlen($realDocRoot));
self::$debugText .= "docroot stripped : {$path}\n";
// fix to root-relative URI
$uri = strtr($path, '/\\', '//');
$uri = self::removeDots($uri);
self::$debugText .= "traversals removed : {$uri}\n\n";
return $uri;
}
/**
* Remove instances of "./" and "../" where possible from a root-relative URI
*
* @param string $uri
*
* @return string
*/
public static function removeDots($uri)
{
$uri = str_replace('/./', '/', $uri);
// inspired by patch from Oleg Cherniy
do {
$uri = preg_replace('@/[^/]+/\\.\\./@', '/', $uri, 1, $changed);
} while ($changed);
return $uri;
}
/**
* Defines which class to call as part of callbacks, change this
* if you extend Minify_CSS_UriRewriter
*
* @var string
*/
protected static $className = 'Minify_CSS_UriRewriter';
/**
* Get realpath with any trailing slash removed. If realpath() fails,
* just remove the trailing slash.
*
* @param string $path
*
* @return mixed path with no trailing slash
*/
protected static function _realpath($path)
{
$realPath = realpath($path);
if ($realPath !== false) {
$path = $realPath;
}
return rtrim($path, '/\\');
}
/**
* Directory of this stylesheet
*
* @var string
*/
private static $_currentDir = '';
/**
* DOC_ROOT
*
* @var string
*/
private static $_docRoot = '';
/**
* directory replacements to map symlink targets back to their
* source (within the document root) E.g. '/var/www/symlink' => '/var/realpath'
*
* @var array
*/
private static $_symlinks = array();
/**
* Path to prepend
*
* @var string
*/
private static $_prependPath = null;
/**
* @param string $css
*
* @return string
*/
private static function _trimUrls($css)
{
$pattern = '/
url\\( # url(
\\s*
([^\\)]+?) # 1 = URI (assuming does not contain ")")
\\s*
\\) # )
/x';
return preg_replace($pattern, 'url($1)', $css);
}
/**
* @param array $m
*
* @return string
*/
private static function _processUriCB($m)
{
// $m matched either '/@import\\s+([\'"])(.*?)[\'"]/' or '/url\\(\\s*([^\\)\\s]+)\\s*\\)/'
$isImport = ($m[0][0] === '@');
// determine URI and the quote character (if any)
if ($isImport) {
$quoteChar = $m[1];
$uri = $m[2];
} else {
// $m[1] is either quoted or not
$quoteChar = ($m[1][0] === "'" || $m[1][0] === '"') ? $m[1][0] : '';
$uri = ($quoteChar === '') ? $m[1] : substr($m[1], 1, strlen($m[1]) - 2);
}
if ($uri === '') {
return $m[0];
}
// if not root/scheme relative and not starts with scheme
if (!preg_match('~^(/|[a-z]+\:)~', $uri)) {
// URI is file-relative: rewrite depending on options
if (self::$_prependPath === null) {
$uri = self::rewriteRelative($uri, self::$_currentDir, self::$_docRoot, self::$_symlinks);
} else {
$uri = self::$_prependPath . $uri;
if ($uri[0] === '/') {
$root = '';
$rootRelative = $uri;
$uri = $root . self::removeDots($rootRelative);
} elseif (preg_match('@^((https?\:)?//([^/]+))/@', $uri, $m) && (false !== strpos($m[3], '.'))) {
$root = $m[1];
$rootRelative = substr($uri, strlen($root));
$uri = $root . self::removeDots($rootRelative);
}
}
}
if ($isImport) {
return "@import {$quoteChar}{$uri}{$quoteChar}";
} else {
return "url({$quoteChar}{$uri}{$quoteChar})";
}
}
/**
* Mungs some inline SVG URL declarations so they won't be touched
*
* @link https://github.com/mrclay/minify/issues/517
* @see _unOwlify
*
* @param string $css
* @return string
*/
private static function _owlifySvgPaths($css)
{
$pattern = '~\b((?:clip-path|mask|-webkit-mask)\s*\:\s*)url(\(\s*#\w+\s*\))~';
return preg_replace($pattern, '$1owl$2', $css);
}
/**
* Undo work of _owlify
*
* @see _owlifySvgPaths
*
* @param string $css
* @return string
*/
private static function _unOwlify($css)
{
$pattern = '~\b((?:clip-path|mask|-webkit-mask)\s*\:\s*)owl~';
return preg_replace($pattern, '$1url', $css);
}
}
lib/Minify/Packer.php 0000666 00000001444 13634722572 0010505 0 ustar 00 pack());
}
}
lib/Minify/Source.php 0000666 00000012513 13634722572 0010537 0 ustar 00
*/
class Minify_Source implements Minify_SourceInterface
{
/**
* @var int time of last modification
*/
protected $lastModified;
/**
* @var callback minifier function specifically for this source.
*/
protected $minifier;
/**
* @var array minification options specific to this source.
*/
protected $minifyOptions = array();
/**
* @var string full path of file
*/
protected $filepath;
/**
* @var string HTTP Content Type (Minify requires one of the constants Minify::TYPE_*)
*/
protected $contentType;
/**
* @var string
*/
protected $content;
/**
* @var callable
*/
protected $getContentFunc;
/**
* @var string
*/
protected $id;
/**
* Create a Minify_Source
*
* In the $spec array(), you can either provide a 'filepath' to an existing
* file (existence will not be checked!) or give 'id' (unique string for
* the content), 'content' (the string content) and 'lastModified'
* (unixtime of last update).
*
* @param array $spec options
*/
public function __construct($spec)
{
if (isset($spec['filepath'])) {
$ext = pathinfo($spec['filepath'], PATHINFO_EXTENSION);
switch ($ext) {
case 'js': $this->contentType = Minify::TYPE_JS;
break;
case 'less': // fallthrough
case 'scss': // fallthrough
case 'css': $this->contentType = Minify::TYPE_CSS;
break;
case 'htm': // fallthrough
case 'html': $this->contentType = Minify::TYPE_HTML;
break;
}
$this->filepath = $spec['filepath'];
$this->id = $spec['filepath'];
// TODO ideally not touch disk in constructor
$this->lastModified = filemtime($spec['filepath']);
if (!empty($spec['uploaderHoursBehind'])) {
// offset for Windows uploaders with out of sync clocks
$this->lastModified += round($spec['uploaderHoursBehind'] * 3600);
}
} elseif (isset($spec['id'])) {
$this->id = 'id::' . $spec['id'];
if (isset($spec['content'])) {
$this->content = $spec['content'];
} else {
$this->getContentFunc = $spec['getContentFunc'];
}
$this->lastModified = isset($spec['lastModified']) ? $spec['lastModified'] : time();
}
if (isset($spec['contentType'])) {
$this->contentType = $spec['contentType'];
}
if (isset($spec['minifier'])) {
$this->setMinifier($spec['minifier']);
}
if (isset($spec['minifyOptions'])) {
$this->minifyOptions = $spec['minifyOptions'];
}
}
/**
* {@inheritdoc}
*/
public function getLastModified()
{
return $this->lastModified;
}
/**
* {@inheritdoc}
*/
public function getMinifier()
{
return $this->minifier;
}
/**
* {@inheritdoc}
*/
public function setMinifier($minifier = null)
{
if ($minifier === '') {
error_log(__METHOD__ . " cannot accept empty string. Use 'Minify::nullMinifier' or 'trim'.");
$minifier = 'Minify::nullMinifier';
}
if ($minifier !== null && !is_callable($minifier, true)) {
throw new InvalidArgumentException('minifier must be null or a valid callable');
}
$this->minifier = $minifier;
}
/**
* {@inheritdoc}
*/
public function getMinifierOptions()
{
return $this->minifyOptions;
}
/**
* {@inheritdoc}
*/
public function setMinifierOptions(array $options)
{
$this->minifyOptions = $options;
}
/**
* {@inheritdoc}
*/
public function getContentType()
{
return $this->contentType;
}
/**
* {@inheritdoc}
*/
public function getContent()
{
if (null === $this->filepath) {
if (null === $this->content) {
$content = call_user_func($this->getContentFunc, $this->id);
} else {
$content = $this->content;
}
} else {
$content = file_get_contents($this->filepath);
}
// remove UTF-8 BOM if present
if (strpos($content, "\xEF\xBB\xBF") === 0) {
return substr($content, 3);
}
return $content;
}
/**
* {@inheritdoc}
*/
public function getId()
{
return $this->id;
}
/**
* {@inheritdoc}
*/
public function getFilePath()
{
return $this->filepath;
}
/**
* {@inheritdoc}
*/
public function setupUriRewrites()
{
if ($this->filepath
&& !isset($this->minifyOptions['currentDir'])
&& !isset($this->minifyOptions['prependRelativePath'])) {
$this->minifyOptions['currentDir'] = dirname($this->filepath);
}
}
}
lib/Minify/ControllerInterface.php 0000666 00000000632 13634722572 0013242 0 ustar 00
* Minify_YUICompressor::$jarFile = '/path/to/yuicompressor-2.4.6.jar';
* Minify_YUICompressor::$tempDir = '/tmp';
* $code = Minify_YUICompressor::minifyJs(
* $code
* ,array('nomunge' => true, 'line-break' => 1000)
* );
*
*
* Note: In case you run out stack (default is 512k), you may increase stack size in $options:
* array('stack-size' => '2048k')
*
* @todo unit tests, $options docs
*
* @package Minify
* @author Stephen Clay
*/
class Minify_YUICompressor
{
/**
* Filepath of the YUI Compressor jar file. This must be set before
* calling minifyJs() or minifyCss().
*
* @var string
*/
public static $jarFile;
/**
* Writable temp directory. This must be set before calling minifyJs()
* or minifyCss().
*
* @var string
*/
public static $tempDir;
/**
* Filepath of "java" executable (may be needed if not in shell's PATH)
*
* @var string
*/
public static $javaExecutable = 'java';
/**
* Minify a Javascript string
*
* @param string $js
*
* @param array $options (verbose is ignored)
*
* @see http://www.julienlecomte.net/yuicompressor/README
*
* @return string
*/
public static function minifyJs($js, $options = array())
{
return self::_minify('js', $js, $options);
}
/**
* Minify a CSS string
*
* @param string $css
*
* @param array $options (verbose is ignored)
*
* @see http://www.julienlecomte.net/yuicompressor/README
*
* @return string
*/
public static function minifyCss($css, $options = array())
{
return self::_minify('css', $css, $options);
}
private static function _minify($type, $content, $options)
{
self::_prepare();
if (! ($tmpFile = tempnam(self::$tempDir, 'yuic_'))) {
throw new Exception('Minify_YUICompressor : could not create temp file in "'.self::$tempDir.'".');
}
file_put_contents($tmpFile, $content);
exec(self::_getCmd($options, $type, $tmpFile), $output, $result_code);
unlink($tmpFile);
if ($result_code != 0) {
throw new Exception('Minify_YUICompressor : YUI compressor execution failed.');
}
return implode("\n", $output);
}
private static function _getCmd($userOptions, $type, $tmpFile)
{
$defaults = array(
'charset' => '',
'line-break' => 5000,
'type' => $type,
'nomunge' => false,
'preserve-semi' => false,
'disable-optimizations' => false,
'stack-size' => '',
);
$o = array_merge($defaults, $userOptions);
$cmd = self::$javaExecutable
. (!empty($o['stack-size']) ? ' -Xss' . $o['stack-size'] : '')
. ' -jar ' . escapeshellarg(self::$jarFile)
. " --type {$type}"
. (preg_match('/^[\\da-zA-Z0-9\\-]+$/', $o['charset'])
? " --charset {$o['charset']}"
: '')
. (is_numeric($o['line-break']) && $o['line-break'] >= 0
? ' --line-break ' . (int)$o['line-break']
: '');
if ($type === 'js') {
foreach (array('nomunge', 'preserve-semi', 'disable-optimizations') as $opt) {
$cmd .= $o[$opt]
? " --{$opt}"
: '';
}
}
return $cmd . ' ' . escapeshellarg($tmpFile);
}
private static function _prepare()
{
if (! is_file(self::$jarFile)) {
throw new Exception('Minify_YUICompressor : $jarFile('.self::$jarFile.') is not a valid file.');
}
if (! is_readable(self::$jarFile)) {
throw new Exception('Minify_YUICompressor : $jarFile('.self::$jarFile.') is not readable.');
}
if (! is_dir(self::$tempDir)) {
throw new Exception('Minify_YUICompressor : $tempDir('.self::$tempDir.') is not a valid direcotry.');
}
if (! is_writable(self::$tempDir)) {
throw new Exception('Minify_YUICompressor : $tempDir('.self::$tempDir.') is not writable.');
}
}
}
lib/Minify/Lines.php 0000666 00000014352 13634722572 0010354 0 ustar 00
* @author Adam Pedersen (Issue 55 fix)
*/
class Minify_Lines
{
/**
* Add line numbers in C-style comments
*
* This uses a very basic parser easily fooled by comment tokens inside
* strings or regexes, but, otherwise, generally clean code will not be
* mangled. URI rewriting can also be performed.
*
* @param string $content
*
* @param array $options available options:
*
* 'id': (optional) string to identify file. E.g. file name/path
*
* 'currentDir': (default null) if given, this is assumed to be the
* directory of the current CSS file. Using this, minify will rewrite
* all relative URIs in import/url declarations to correctly point to
* the desired files, and prepend a comment with debugging information about
* this process.
*
* @return string
*/
public static function minify($content, $options = array())
{
$id = (isset($options['id']) && $options['id']) ? $options['id'] : '';
$content = str_replace("\r\n", "\n", $content);
$lines = explode("\n", $content);
$numLines = count($lines);
// determine left padding
$padTo = strlen((string) $numLines); // e.g. 103 lines = 3 digits
$inComment = false;
$i = 0;
$newLines = array();
while (null !== ($line = array_shift($lines))) {
if (('' !== $id) && (0 === $i % 50)) {
if ($inComment) {
array_push($newLines, '', "/* {$id} *|", '');
} else {
array_push($newLines, '', "/* {$id} */", '');
}
}
++$i;
$newLines[] = self::_addNote($line, $i, $inComment, $padTo);
$inComment = self::_eolInComment($line, $inComment);
}
$content = implode("\n", $newLines) . "\n";
// check for desired URI rewriting
if (isset($options['currentDir'])) {
Minify_CSS_UriRewriter::$debugText = '';
$docRoot = isset($options['docRoot']) ? $options['docRoot'] : $_SERVER['DOCUMENT_ROOT'];
$symlinks = isset($options['symlinks']) ? $options['symlinks'] : array();
$content = Minify_CSS_UriRewriter::rewrite($content, $options['currentDir'], $docRoot, $symlinks);
$content = "/* Minify_CSS_UriRewriter::\$debugText\n\n"
. Minify_CSS_UriRewriter::$debugText . "*/\n"
. $content;
}
return $content;
}
/**
* Is the parser within a C-style comment at the end of this line?
*
* @param string $line current line of code
*
* @param bool $inComment was the parser in a C-style comment at the
* beginning of the previous line?
*
* @return bool
*/
private static function _eolInComment($line, $inComment)
{
while (strlen($line)) {
if ($inComment) {
// only "*/" can end the comment
$index = self::_find($line, '*/');
if ($index === false) {
return true;
}
// stop comment and keep walking line
$inComment = false;
@$line = (string)substr($line, $index + 2);
continue;
}
// look for "//" and "/*"
$single = self::_find($line, '//');
$multi = self::_find($line, '/*');
if ($multi === false) {
return false;
}
if ($single === false || $multi < $single) {
// start comment and keep walking line
$inComment = true;
@$line = (string)substr($line, $multi + 2);
continue;
}
// a single-line comment preceeded it
return false;
}
return $inComment;
}
/**
* Prepend a comment (or note) to the given line
*
* @param string $line current line of code
*
* @param string $note content of note/comment
*
* @param bool $inComment was the parser in a comment at the
* beginning of the line?
*
* @param int $padTo minimum width of comment
*
* @return string
*/
private static function _addNote($line, $note, $inComment, $padTo)
{
if ($inComment) {
$line = '/* ' . str_pad($note, $padTo, ' ', STR_PAD_RIGHT) . ' *| ' . $line;
} else {
$line = '/* ' . str_pad($note, $padTo, ' ', STR_PAD_RIGHT) . ' */ ' . $line;
}
return rtrim($line);
}
/**
* Find a token trying to avoid false positives
*
* @param string $str String containing the token
* @param string $token Token being checked
* @return bool
*/
private static function _find($str, $token)
{
switch ($token) {
case '//':
$fakes = array(
'://' => 1,
'"//' => 1,
'\'//' => 1,
'".//' => 2,
'\'.//' => 2,
);
break;
case '/*':
$fakes = array(
'"/*' => 1,
'\'/*' => 1,
'"//*' => 2,
'\'//*' => 2,
'".//*' => 3,
'\'.//*' => 3,
'*/*' => 1,
'\\/*' => 1,
);
break;
default:
$fakes = array();
}
$index = strpos($str, $token);
$offset = 0;
while ($index !== false) {
foreach ($fakes as $fake => $skip) {
$check = substr($str, $index - $skip, strlen($fake));
if ($check === $fake) {
// move offset and scan again
$offset += $index + strlen($token);
$index = strpos($str, $token, $offset);
break;
}
}
// legitimate find
return $index;
}
return $index;
}
}
lib/Minify/HTML/Helper.php 0000666 00000016353 13634722572 0011270 0 ustar 00
*/
class Minify_HTML_Helper
{
public $rewriteWorks = true;
public $minAppUri = '/min';
public $groupsConfigFile = '';
/**
* Get an HTML-escaped Minify URI for a group or set of files
*
* @param string|array $keyOrFiles a group key or array of filepaths/URIs
* @param array $opts options:
* 'farExpires' : (default true) append a modified timestamp for cache revving
* 'debug' : (default false) append debug flag
* 'charset' : (default 'UTF-8') for htmlspecialchars
* 'minAppUri' : (default '/min') URI of min directory
* 'rewriteWorks' : (default true) does mod_rewrite work in min app?
* 'groupsConfigFile' : specify if different
* @return string
*/
public static function getUri($keyOrFiles, $opts = array())
{
$opts = array_merge(array( // default options
'farExpires' => true,
'debug' => false,
'charset' => 'UTF-8',
'minAppUri' => '/min',
'rewriteWorks' => true,
'groupsConfigFile' => self::app()->groupsConfigPath,
), $opts);
$h = new self;
$h->minAppUri = $opts['minAppUri'];
$h->rewriteWorks = $opts['rewriteWorks'];
$h->groupsConfigFile = $opts['groupsConfigFile'];
if (is_array($keyOrFiles)) {
$h->setFiles($keyOrFiles, $opts['farExpires']);
} else {
$h->setGroup($keyOrFiles, $opts['farExpires']);
}
$uri = $h->getRawUri($opts['farExpires'], $opts['debug']);
return htmlspecialchars($uri, ENT_QUOTES, $opts['charset']);
}
/**
* Get non-HTML-escaped URI to minify the specified files
*
* @param bool $farExpires
* @param bool $debug
* @return string
*/
public function getRawUri($farExpires = true, $debug = false)
{
$path = rtrim($this->minAppUri, '/') . '/';
if (! $this->rewriteWorks) {
$path .= '?';
}
if (null === $this->_groupKey) {
// @todo: implement shortest uri
$path = self::_getShortestUri($this->_filePaths, $path);
} else {
$path .= "g=" . $this->_groupKey;
}
if ($debug) {
$path .= "&debug";
} elseif ($farExpires && $this->_lastModified) {
$path .= "&" . $this->_lastModified;
}
return $path;
}
/**
* Set the files that will comprise the URI we're building
*
* @param array $files
* @param bool $checkLastModified
*/
public function setFiles($files, $checkLastModified = true)
{
$this->_groupKey = null;
if ($checkLastModified) {
$this->_lastModified = self::getLastModified($files);
}
// normalize paths like in /min/f=
foreach ($files as $k => $file) {
if (0 === strpos($file, '//')) {
$file = substr($file, 2);
} elseif (0 === strpos($file, '/') || 1 === strpos($file, ':\\')) {
$file = substr($file, strlen(self::app()->env->getDocRoot()) + 1);
}
$file = strtr($file, '\\', '/');
$files[$k] = $file;
}
$this->_filePaths = $files;
}
/**
* Set the group of files that will comprise the URI we're building
*
* @param string $key
* @param bool $checkLastModified
*/
public function setGroup($key, $checkLastModified = true)
{
$this->_groupKey = $key;
if ($checkLastModified) {
if (! $this->groupsConfigFile) {
$this->groupsConfigFile = self::app()->groupsConfigPath;
}
if (is_file($this->groupsConfigFile)) {
$gc = (require $this->groupsConfigFile);
$keys = explode(',', $key);
foreach ($keys as $key) {
if (!isset($gc[$key])) {
// this can happen if value is null
// which could be solved with array_filter
continue;
}
$this->_lastModified = self::getLastModified($gc[$key], $this->_lastModified);
}
}
}
}
/**
* Get the max(lastModified) of all files
*
* @param array|string $sources
* @param int $lastModified
* @return int
*/
public static function getLastModified($sources, $lastModified = 0)
{
$max = $lastModified;
$factory = self::app()->sourceFactory;
/** @var Minify_Source $source */
foreach ((array)$sources as $source) {
$source = $factory->makeSource($source);
$max = max($max, $source->getLastModified());
}
return $max;
}
/**
* @param \Minify\App $app
* @return \Minify\App
* @internal
*/
public static function app(\Minify\App $app = null)
{
static $cached;
if ($app) {
$cached = $app;
return $app;
}
if ($cached === null) {
$cached = (require __DIR__ . '/../../../bootstrap.php');
}
return $cached;
}
protected $_groupKey = null; // if present, URI will be like g=...
protected $_filePaths = array();
protected $_lastModified = null;
/**
* In a given array of strings, find the character they all have at
* a particular index
*
* @param array $arr array of strings
* @param int $pos index to check
* @return mixed a common char or '' if any do not match
*/
protected static function _getCommonCharAtPos($arr, $pos)
{
if (!isset($arr[0][$pos])) {
return '';
}
$c = $arr[0][$pos];
$l = count($arr);
if ($l === 1) {
return $c;
}
for ($i = 1; $i < $l; ++$i) {
if ($arr[$i][$pos] !== $c) {
return '';
}
}
return $c;
}
/**
* Get the shortest URI to minify the set of source files
*
* @param array $paths root-relative URIs of files
* @param string $minRoot root-relative URI of the "min" application
* @return string
*/
protected static function _getShortestUri($paths, $minRoot = '/min/')
{
$pos = 0;
$base = '';
while (true) {
$c = self::_getCommonCharAtPos($paths, $pos);
if ($c === '') {
break;
} else {
$base .= $c;
}
++$pos;
}
$base = preg_replace('@[^/]+$@', '', $base);
$uri = $minRoot . 'f=' . implode(',', $paths);
if (substr($base, -1) === '/') {
// we have a base dir!
$basedPaths = $paths;
$l = count($paths);
for ($i = 0; $i < $l; ++$i) {
$basedPaths[$i] = substr($paths[$i], strlen($base));
}
$base = substr($base, 0, strlen($base) - 1);
$bUri = $minRoot . 'b=' . $base . '&f=' . implode(',', $basedPaths);
$uri = strlen($uri) < strlen($bUri) ? $uri : $bUri;
}
return $uri;
}
}
lib/Minify/DebugDetector.php 0000666 00000001420 13634722572 0012012 0 ustar 00
*/
class Minify_DebugDetector
{
public static function shouldDebugRequest(Minify_Env $env)
{
if ($env->get('debug') !== null) {
return true;
}
$cookieValue = $env->cookie('minifyDebug');
if ($cookieValue) {
foreach (preg_split('/\\s+/', $cookieValue) as $debugUri) {
$pattern = '@' . preg_quote($debugUri, '@') . '@i';
$pattern = str_replace(array('\\*', '\\?'), array('.*', '.'), $pattern);
if (preg_match($pattern, $env->getRequestUri())) {
return true;
}
}
}
return false;
}
}
lib/Minify/SourceSet.php 0000666 00000001116 13634722572 0011210 0 ustar 00 getId(), $source->getMinifier(), $source->getMinifierOptions()
);
}
return md5(serialize($info));
}
}
lib/Minify/CSSmin.php 0000666 00000005255 13634722572 0010440 0 ustar 00
*/
class Minify_CSSmin
{
/**
* Minify a CSS string
*
* @param string $css
*
* @param array $options available options:
*
* 'removeCharsets': (default true) remove all @charset at-rules
*
* 'prependRelativePath': (default null) if given, this string will be
* prepended to all relative URIs in import/url declarations
*
* 'currentDir': (default null) if given, this is assumed to be the
* directory of the current CSS file. Using this, minify will rewrite
* all relative URIs in import/url declarations to correctly point to
* the desired files. For this to work, the files *must* exist and be
* visible by the PHP process.
*
* 'symlinks': (default = array()) If the CSS file is stored in
* a symlink-ed directory, provide an array of link paths to
* target paths, where the link paths are within the document root. Because
* paths need to be normalized for this to work, use "//" to substitute
* the doc root in the link paths (the array keys). E.g.:
*
* array('//symlink' => '/real/target/path') // unix
* array('//static' => 'D:\\staticStorage') // Windows
*
*
* 'docRoot': (default = $_SERVER['DOCUMENT_ROOT'])
* see Minify_CSS_UriRewriter::rewrite
*
* @return string
*/
public static function minify($css, $options = array())
{
$options = array_merge(array(
'compress' => true,
'removeCharsets' => true,
'currentDir' => null,
'docRoot' => $_SERVER['DOCUMENT_ROOT'],
'prependRelativePath' => null,
'symlinks' => array(),
), $options);
if ($options['removeCharsets']) {
$css = preg_replace('/@charset[^;]+;\\s*/', '', $css);
}
if ($options['compress']) {
$obj = new CSSmin();
$css = $obj->run($css);
}
if (! $options['currentDir'] && ! $options['prependRelativePath']) {
return $css;
}
if ($options['currentDir']) {
return Minify_CSS_UriRewriter::rewrite(
$css
,$options['currentDir']
,$options['docRoot']
,$options['symlinks']
);
}
return Minify_CSS_UriRewriter::prepend(
$css
,$options['prependRelativePath']
);
}
}
lib/Minify/HTML.php 0000666 00000017765 13634722572 0010061 0 ustar 00
*/
class Minify_HTML
{
/**
* @var boolean
*/
protected $_jsCleanComments = true;
/**
* "Minify" an HTML page
*
* @param string $html
*
* @param array $options
*
* 'cssMinifier' : (optional) callback function to process content of STYLE
* elements.
*
* 'jsMinifier' : (optional) callback function to process content of SCRIPT
* elements. Note: the type attribute is ignored.
*
* 'xhtml' : (optional boolean) should content be treated as XHTML1.0? If
* unset, minify will sniff for an XHTML doctype.
*
* @return string
*/
public static function minify($html, $options = array())
{
$min = new self($html, $options);
return $min->process();
}
/**
* Create a minifier object
*
* @param string $html
*
* @param array $options
*
* 'cssMinifier' : (optional) callback function to process content of STYLE
* elements.
*
* 'jsMinifier' : (optional) callback function to process content of SCRIPT
* elements. Note: the type attribute is ignored.
*
* 'jsCleanComments' : (optional) whether to remove HTML comments beginning and end of script block
*
* 'xhtml' : (optional boolean) should content be treated as XHTML1.0? If
* unset, minify will sniff for an XHTML doctype.
*/
public function __construct($html, $options = array())
{
$this->_html = str_replace("\r\n", "\n", trim($html));
if (isset($options['xhtml'])) {
$this->_isXhtml = (bool)$options['xhtml'];
}
if (isset($options['cssMinifier'])) {
$this->_cssMinifier = $options['cssMinifier'];
}
if (isset($options['jsMinifier'])) {
$this->_jsMinifier = $options['jsMinifier'];
}
if (isset($options['jsCleanComments'])) {
$this->_jsCleanComments = (bool)$options['jsCleanComments'];
}
}
/**
* Minify the markeup given in the constructor
*
* @return string
*/
public function process()
{
if ($this->_isXhtml === null) {
$this->_isXhtml = (false !== strpos($this->_html, '_html);
// fill placeholders
$this->_html = str_replace(
array_keys($this->_placeholders)
,array_values($this->_placeholders)
,$this->_html
);
// issue 229: multi-pass to catch scripts that didn't get replaced in textareas
$this->_html = str_replace(
array_keys($this->_placeholders)
,array_values($this->_placeholders)
,$this->_html
);
return $this->_html;
}
protected function _commentCB($m)
{
return (0 === strpos($m[1], '[') || false !== strpos($m[1], '_replacementHash . count($this->_placeholders) . '%';
$this->_placeholders[$placeholder] = $content;
return $placeholder;
}
protected $_isXhtml;
protected $_replacementHash;
protected $_placeholders = array();
protected $_cssMinifier;
protected $_jsMinifier;
protected function _removePreCB($m)
{
return $this->_reservePlace("_reservePlace("
";
}
if (0 !== strpos(realpath(__FILE__), realpath($_SERVER['DOCUMENT_ROOT']))) {
echo "DOCUMENT_ROOT doesn't contain this file. You may "
. " need to set \$min_documentRoot manually
";
}
if (isset($_SERVER['SUBDOMAIN_DOCUMENT_ROOT'])) {
echo "\$_SERVER['SUBDOMAIN_DOCUMENT_ROOT'] is set. "
. "You may need to set \$min_documentRoot to this in config.php
";
}
}
//*/ builder/bm2.js 0000666 00000001076 13634722572 0007233 0 ustar 00 javascript:(function(){
var d = document
,c = d.cookie
,m = c.match(/\bminifyDebug=([^; ]+)/)
,v = m ? decodeURIComponent(m[1]) : ''
,p = prompt('Debug Minify URIs on ' + location.hostname + ' which contain:'
+ '\n(empty for none, space = OR, * = any string, ? = any char)', v)
;
if (p === null) return;
p = p.replace(/^\s+|\s+$/, '');
v = (p === '')
? 'minifyDebug=; expires=Fri, 27 Jul 2001 02:47:11 UTC; path=/'
: 'minifyDebug=' + encodeURIComponent(p) + '; path=/';
d.cookie = v;
})(); builder/jquery-1.6.3.min.js 0000666 00000262754 13634722572 0011333 0 ustar 00 /*! jQuery v1.6.3 http://jquery.com/ | http://jquery.org/license */
(function(a,b){function cu(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cr(a){if(!cg[a]){var b=c.body,d=f("<"+a+">").appendTo(b),e=d.css("display");d.remove();if(e==="none"||e===""){ch||(ch=c.createElement("iframe"),ch.frameBorder=ch.width=ch.height=0),b.appendChild(ch);if(!ci||!ch.createElement)ci=(ch.contentWindow||ch.contentDocument).document,ci.write((c.compatMode==="CSS1Compat"?"":"")+""),ci.close();d=ci.createElement(a),ci.body.appendChild(d),e=f.css(d,"display"),b.removeChild(ch)}cg[a]=e}return cg[a]}function cq(a,b){var c={};f.each(cm.concat.apply([],cm.slice(0,b)),function(){c[this]=a});return c}function cp(){cn=b}function co(){setTimeout(cp,0);return cn=f.now()}function cf(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ce(){try{return new a.XMLHttpRequest}catch(b){}}function b$(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g0){c!=="border"&&f.each(e,function(){c||(d-=parseFloat(f.css(a,"padding"+this))||0),c==="margin"?d+=parseFloat(f.css(a,c+this))||0:d-=parseFloat(f.css(a,"border"+this+"Width"))||0});return d+"px"}d=bv(a,b,b);if(d<0||d==null)d=a.style[b]||0;d=parseFloat(d)||0,c&&f.each(e,function(){d+=parseFloat(f.css(a,"padding"+this))||0,c!=="padding"&&(d+=parseFloat(f.css(a,"border"+this+"Width"))||0),c==="margin"&&(d+=parseFloat(f.css(a,c+this))||0)});return d+"px"}function bl(a,b){b.src?f.ajax({url:b.src,async:!1,dataType:"script"}):f.globalEval((b.text||b.textContent||b.innerHTML||"").replace(bd,"/*$0*/")),b.parentNode&&b.parentNode.removeChild(b)}function bk(a){f.nodeName(a,"input")?bj(a):"getElementsByTagName"in a&&f.grep(a.getElementsByTagName("input"),bj)}function bj(a){if(a.type==="checkbox"||a.type==="radio")a.defaultChecked=a.checked}function bi(a){return"getElementsByTagName"in a?a.getElementsByTagName("*"):"querySelectorAll"in a?a.querySelectorAll("*"):[]}function bh(a,b){var c;if(b.nodeType===1){b.clearAttributes&&b.clearAttributes(),b.mergeAttributes&&b.mergeAttributes(a),c=b.nodeName.toLowerCase();if(c==="object")b.outerHTML=a.outerHTML;else if(c!=="input"||a.type!=="checkbox"&&a.type!=="radio"){if(c==="option")b.selected=a.defaultSelected;else if(c==="input"||c==="textarea")b.defaultValue=a.defaultValue}else a.checked&&(b.defaultChecked=b.checked=a.checked),b.value!==a.value&&(b.value=a.value);b.removeAttribute(f.expando)}}function bg(a,b){if(b.nodeType===1&&!!f.hasData(a)){var c=f.expando,d=f.data(a),e=f.data(b,d);if(d=d[c]){var g=d.events;e=e[c]=f.extend({},d);if(g){delete e.handle,e.events={};for(var h in g)for(var i=0,j=g[h].length;i=0===c})}function U(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function M(a,b){return(a&&a!=="*"?a+".":"")+b.replace(y,"`").replace(z,"&")}function L(a){var b,c,d,e,g,h,i,j,k,l,m,n,o,p=[],q=[],r=f._data(this,"events");if(!(a.liveFired===this||!r||!r.live||a.target.disabled||a.button&&a.type==="click")){a.namespace&&(n=new RegExp("(^|\\.)"+a.namespace.split(".").join("\\.(?:.*\\.)?")+"(\\.|$)")),a.liveFired=this;var s=r.live.slice(0);for(i=0;ic)break;a.currentTarget=e.elem,a.data=e.handleObj.data,a.handleObj=e.handleObj,o=e.handleObj.origHandler.apply(e.elem,arguments);if(o===!1||a.isPropagationStopped()){c=e.level,o===!1&&(b=!1);if(a.isImmediatePropagationStopped())break}}return b}}function J(a,c,d){var e=f.extend({},d[0]);e.type=a,e.originalEvent={},e.liveFired=b,f.event.handle.call(c,e),e.isDefaultPrevented()&&d[0].preventDefault()}function D(){return!0}function C(){return!1}function m(a,c,d){var e=c+"defer",g=c+"queue",h=c+"mark",i=f.data(a,e,b,!0);i&&(d==="queue"||!f.data(a,g,b,!0))&&(d==="mark"||!f.data(a,h,b,!0))&&setTimeout(function(){!f.data(a,g,b,!0)&&!f.data(a,h,b,!0)&&(f.removeData(a,e,!0),i.resolve())},0)}function l(a){for(var b in a)if(b!=="toJSON")return!1;return!0}function k(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(j,"$1-$2").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:f.isNaN(d)?i.test(d)?f.parseJSON(d):d:parseFloat(d)}catch(g){}f.data(a,c,d)}else d=b}return d}var c=a.document,d=a.navigator,e=a.location,f=function(){function K(){if(!e.isReady){try{c.documentElement.doScroll("left")}catch(a){setTimeout(K,1);return}e.ready()}}var e=function(a,b){return new e.fn.init(a,b,h)},f=a.jQuery,g=a.$,h,i=/^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,j=/\S/,k=/^\s+/,l=/\s+$/,m=/\d/,n=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,o=/^[\],:{}\s]*$/,p=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,q=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,r=/(?:^|:|,)(?:\s*\[)+/g,s=/(webkit)[ \/]([\w.]+)/,t=/(opera)(?:.*version)?[ \/]([\w.]+)/,u=/(msie) ([\w.]+)/,v=/(mozilla)(?:.*? rv:([\w.]+))?/,w=/-([a-z]|[0-9])/ig,x=/^-ms-/,y=function(a,b){return(b+"").toUpperCase()},z=d.userAgent,A,B,C,D=Object.prototype.toString,E=Object.prototype.hasOwnProperty,F=Array.prototype.push,G=Array.prototype.slice,H=String.prototype.trim,I=Array.prototype.indexOf,J={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a=="string"){a.charAt(0)!=="<"||a.charAt(a.length-1)!==">"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=n.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:"",jquery:"1.6.3",length:0,size:function(){return this.length},toArray:function(){return G.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?F.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),B.done(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(G.apply(this,arguments),"slice",G.call(arguments).join(","))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:F,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i=="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!="object"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j0)return;B.resolveWith(c,[e]),e.fn.trigger&&e(c).trigger("ready").unbind("ready")}},bindReady:function(){if(!B){B=e._Deferred();if(c.readyState==="complete")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",C,!1),a.addEventListener("load",e.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",C),a.attachEvent("onload",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&K()}}},isFunction:function(a){return e.type(a)==="function"},isArray:Array.isArray||function(a){return e.type(a)==="array"},isWindow:function(a){return a&&typeof a=="object"&&"setInterval"in a},isNaN:function(a){return a==null||!m.test(a)||isNaN(a)},type:function(a){return a==null?String(a):J[D.call(a)]||"object"},isPlainObject:function(a){if(!a||e.type(a)!=="object"||a.nodeType||e.isWindow(a))return!1;try{if(a.constructor&&!E.call(a,"constructor")&&!E.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}var d;for(d in a);return d===b||E.call(a,d)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw a},parseJSON:function(b){if(typeof b!="string"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(o.test(b.replace(p,"@").replace(q,"]").replace(r,"")))return(new Function("return "+b))();e.error("Invalid JSON: "+b)},parseXML:function(c){var d,f;try{a.DOMParser?(f=new DOMParser,d=f.parseFromString(c,"text/xml")):(d=new ActiveXObject("Microsoft.XMLDOM"),d.async="false",d.loadXML(c))}catch(g){d=b}(!d||!d.documentElement||d.getElementsByTagName("parsererror").length)&&e.error("Invalid XML: "+c);return d},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(x,"ms-").replace(w,y)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i1?h.call(arguments,0):c,--e||g.resolveWith(g,h.call(b,0))}}var b=arguments,c=0,d=b.length,e=d,g=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred();if(d>1){for(;ca ",d=a.getElementsByTagName("*"),e=a.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=a.getElementsByTagName("input")[0],k={leadingWhitespace:a.firstChild.nodeType===3,tbody:!a.getElementsByTagName("tbody").length,htmlSerialize:!!a.getElementsByTagName("link").length,style:/top/.test(e.getAttribute("style")),hrefNormalized:e.getAttribute("href")==="/a",opacity:/^0.55$/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,getSetAttribute:a.className!=="t",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0},i.checked=!0,k.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,k.optDisabled=!h.disabled;try{delete a.test}catch(v){k.deleteExpando=!1}!a.addEventListener&&a.attachEvent&&a.fireEvent&&(a.attachEvent("onclick",function(){k.noCloneEvent=!1}),a.cloneNode(!0).fireEvent("onclick")),i=c.createElement("input"),i.value="t",i.setAttribute("type","radio"),k.radioValue=i.value==="t",i.setAttribute("checked","checked"),a.appendChild(i),l=c.createDocumentFragment(),l.appendChild(a.firstChild),k.checkClone=l.cloneNode(!0).cloneNode(!0).lastChild.checked,a.innerHTML="",a.style.width=a.style.paddingLeft="1px",m=c.getElementsByTagName("body")[0],o=c.createElement(m?"div":"body"),p={visibility:"hidden",width:0,height:0,border:0,margin:0,background:"none"},m&&f.extend(p,{position:"absolute",left:"-1000px",top:"-1000px"});for(t in p)o.style[t]=p[t];o.appendChild(a),n=m||b,n.insertBefore(o,n.firstChild),k.appendChecked=i.checked,k.boxModel=a.offsetWidth===2,"zoom"in a.style&&(a.style.display="inline",a.style.zoom=1,k.inlineBlockNeedsLayout=a.offsetWidth===2,a.style.display="",a.innerHTML="
",k.shrinkWrapBlocks=a.offsetWidth!==2),a.innerHTML="",q=a.getElementsByTagName("td"),u=q[0].offsetHeight===0,q[0].style.display="",q[1].style.display="none",k.reliableHiddenOffsets=u&&q[0].offsetHeight===0,a.innerHTML="",c.defaultView&&c.defaultView.getComputedStyle&&(j=c.createElement("div"),j.style.width="0",j.style.marginRight="0",a.appendChild(j),k.reliableMarginRight=(parseInt((c.defaultView.getComputedStyle(j,null)||{marginRight:0}).marginRight,10)||0)===0),o.innerHTML="",n.removeChild(o);if(a.attachEvent)for(t in{submit:1,change:1,focusin:1})s="on"+t,u=s in a,u||(a.setAttribute(s,"return;"),u=typeof a[s]=="function"),k[t+"Bubbles"]=u;o=l=g=h=m=j=a=i=null;return k}(),f.boxModel=f.support.boxModel;var i=/^(?:\{.*\}|\[.*\])$/,j=/([a-z])([A-Z])/g;f.extend({cache:{},uuid:0,expando:"jQuery"+(f.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!l(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g,h,i=f.expando,j=typeof c=="string",k=a.nodeType,l=k?f.cache:a,m=k?a[f.expando]:a[f.expando]&&f.expando;if((!m||e&&m&&l[m]&&!l[m][i])&&j&&d===b)return;m||(k?a[f.expando]=m=++f.uuid:m=f.expando),l[m]||(l[m]={},k||(l[m].toJSON=f.noop));if(typeof c=="object"||typeof c=="function")e?l[m][i]=f.extend(l[m][i],c):l[m]=f.extend(l[m],c);g=l[m],e&&(g[i]||(g[i]={}),g=g[i]),d!==b&&(g[f.camelCase(c)]=d);if(c==="events"&&!g[c])return g[i]&&g[i].events;j?(h=g[c],h==null&&(h=g[f.camelCase(c)])):h=g;return h}},removeData:function(a,b,c){if(!!f.acceptData(a)){var d,e=f.expando,g=a.nodeType,h=g?f.cache:a,i=g?a[f.expando]:f.expando;if(!h[i])return;if(b){d=c?h[i][e]:h[i];if(d){d[b]||(b=f.camelCase(b)),delete d[b];if(!l(d))return}}if(c){delete h[i][e];if(!l(h[i]))return}var j=h[i][e];f.support.deleteExpando||!h.setInterval?delete h[i]:h[i]=null,j?(h[i]={},g||(h[i].toJSON=f.noop),h[i][e]=j):g&&(f.support.deleteExpando?delete a[f.expando]:a.removeAttribute?a.removeAttribute(f.expando):a[f.expando]=null)}},_data:function(a,b,c){return f.data(a,b,c,!0)},acceptData:function(a){if(a.nodeName){var b=f.noData[a.nodeName.toLowerCase()];if(b)return b!==!0&&a.getAttribute("classid")===b}return!0}}),f.fn.extend({data:function(a,c){var d=null;if(typeof a=="undefined"){if(this.length){d=f.data(this[0]);if(this[0].nodeType===1){var e=this[0].attributes,g;for(var h=0,i=e.length;h-1)return!0;return!1},val:function(a){var c,d,e=this[0];if(!arguments.length){if(e){c=f.valHooks[e.nodeName.toLowerCase()]||f.valHooks[e.type];if(c&&"get"in c&&(d=c.get(e,"value"))!==b)return d;d=e.value;return typeof d=="string"?d.replace(p,""):d==null?"":d}return b}var g=f.isFunction(a);return this.each(function(d){var e=f(this),h;if(this.nodeType===1){g?h=a.call(this,d,e.val()):h=a,h==null?h="":typeof h=="number"?h+="":f.isArray(h)&&(h=f.map(h,function(a){return a==null?"":a+""})),c=f.valHooks[this.nodeName.toLowerCase()]||f.valHooks[this.type];if(!c||!("set"in c)||c.set(this,h,"value")===b)this.value=h}})}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c=a.selectedIndex,d=[],e=a.options,g=a.type==="select-one";if(c<0)return null;for(var h=g?c:0,i=g?c+1:e.length;h=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attrFix:{tabindex:"tabIndex"},attr:function(a,c,d,e){var g=a.nodeType;if(!a||g===3||g===8||g===2)return b;if(e&&c in f.attrFn)return f(a)[c](d);if(!("getAttribute"in a))return f.prop(a,c,d);var h,i,j=g!==1||!f.isXMLDoc(a);j&&(c=f.attrFix[c]||c,i=f.attrHooks[c],i||(t.test(c)?i=v:u&&(i=u)));if(d!==b){if(d===null){f.removeAttr(a,c);return b}if(i&&"set"in i&&j&&(h=i.set(a,d,c))!==b)return h;a.setAttribute(c,""+d);return d}if(i&&"get"in i&&j&&(h=i.get(a,c))!==null)return h;h=a.getAttribute(c);return h===null?b:h},removeAttr:function(a,b){var c;a.nodeType===1&&(b=f.attrFix[b]||b,f.attr(a,b,""),a.removeAttribute(b),t.test(b)&&(c=f.propFix[b]||b)in a&&(a[c]=!1))},attrHooks:{type:{set:function(a,b){if(q.test(a.nodeName)&&a.parentNode)f.error("type property can't be changed");else if(!f.support.radioValue&&b==="radio"&&f.nodeName(a,"input")){var c=a.value;a.setAttribute("type",b),c&&(a.value=c);return b}}},value:{get:function(a,b){if(u&&f.nodeName(a,"button"))return u.get(a,b);return b in a?a.value:null},set:function(a,b,c){if(u&&f.nodeName(a,"button"))return u.set(a,b,c);a.value=b}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(a,c,d){var e=a.nodeType;if(!a||e===3||e===8||e===2)return b;var g,h,i=e!==1||!f.isXMLDoc(a);i&&(c=f.propFix[c]||c,h=f.propHooks[c]);return d!==b?h&&"set"in h&&(g=h.set(a,d,c))!==b?g:a[c]=d:h&&"get"in h&&(g=h.get(a,c))!==null?g:a[c]},propHooks:{tabIndex:{get:function(a){var c=a.getAttributeNode("tabindex");return c&&c.specified?parseInt(c.value,10):r.test(a.nodeName)||s.test(a.nodeName)&&a.href?0:b}}}}),f.attrHooks.tabIndex=f.propHooks.tabIndex,v={get:function(a,c){var d;return f.prop(a,c)===!0||(d=a.getAttributeNode(c))&&d.nodeValue!==!1?c.toLowerCase():b},set:function(a,b,c){var d;b===!1?f.removeAttr(a,c):(d=f.propFix[c]||c,d in a&&(a[d]=!0),a.setAttribute(c,c.toLowerCase()));return c}},f.support.getSetAttribute||(u=f.valHooks.button={get:function(a,c){var d;d=a.getAttributeNode(c);return d&&d.nodeValue!==""?d.nodeValue:b},set:function(a,b,d){var e=a.getAttributeNode(d);e||(e=c.createAttribute(d),a.setAttributeNode(e));return e.nodeValue=b+""}},f.each(["width","height"],function(a,b){f.attrHooks[b]=f.extend(f.attrHooks[b],{set:function(a,c){if(c===""){a.setAttribute(b,"auto");return c}}})})),f.support.hrefNormalized||f.each(["href","src","width","height"],function(a,c){f.attrHooks[c]=f.extend(f.attrHooks[c],{get:function(a){var d=a.getAttribute(c,2);return d===null?b:d}})}),f.support.style||(f.attrHooks.style={get:function(a){return a.style.cssText.toLowerCase()||b},set:function(a,b){return a.style.cssText=""+b}}),f.support.optSelected||(f.propHooks.selected=f.extend(f.propHooks.selected,{get:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex);return null}})),f.support.checkOn||f.each(["radio","checkbox"],function(){f.valHooks[this]={get:function(a){return a.getAttribute("value")===null?"on":a.value}}}),f.each(["radio","checkbox"],function(){f.valHooks[this]=f.extend(f.valHooks[this],{set:function(a,b){if(f.isArray(b))return a.checked=f.inArray(f(a).val(),b)>=0}})});var w=/\.(.*)$/,x=/^(?:textarea|input|select)$/i,y=/\./g,z=/ /g,A=/[^\w\s.|`]/g,B=function(a){return a.replace(A,"\\$&")};f.event={add:function(a,c,d,e){if(a.nodeType!==3&&a.nodeType!==8){if(d===!1)d=C;else if(!d)return;var g,h;d.handler&&(g=d,d=g.handler),d.guid||(d.guid=f.guid++);var i=f._data(a);if(!i)return;var j=i.events,k=i.handle;j||(i.events=j={}),k||(i.handle=k=function(a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.handle.apply(k.elem,arguments):b}),k.elem=a,c=c.split(" ");var l,m=0,n;while(l=c[m++]){h=g?f.extend({},g):{handler:d,data:e},l.indexOf(".")>-1?(n=l.split("."),l=n.shift(),h.namespace=n.slice(0).sort().join(".")):(n=[],h.namespace=""),h.type=l,h.guid||(h.guid=d.guid);var o=j[l],p=f.event.special[l]||{};if(!o){o=j[l]=[];if(!p.setup||p.setup.call(a,e,n,k)===!1)a.addEventListener?a.addEventListener(l,k,!1):a.attachEvent&&a.attachEvent("on"+l,k)}p.add&&(p.add.call(a,h),h.handler.guid||(h.handler.guid=d.guid)),o.push(h),f.event.global[l]=!0}a=null}},global:{},remove:function(a,c,d,e){if(a.nodeType!==3&&a.nodeType!==8){d===!1&&(d=C);var g,h,i,j,k=0,l,m,n,o,p,q,r,s=f.hasData(a)&&f._data(a),t=s&&s.events;if(!s||!t)return;c&&c.type&&(d=c.handler,c=c.type);if(!c||typeof c=="string"&&c.charAt(0)==="."){c=c||"";for(h in t)f.event.remove(a,h+c);return}c=c.split(" ");while(h=c[k++]){r=h,q=null,l=h.indexOf(".")<0,m=[],l||(m=h.split("."),h=m.shift(),n=new RegExp("(^|\\.)"+f.map(m.slice(0).sort(),B).join("\\.(?:.*\\.)?")+"(\\.|$)")),p=t[h];if(!p)continue;if(!d){for(j=0;j =0&&(h=h.slice(0,-1),j=!0),h.indexOf(".")>=0&&(i=h.split("."),h=i.shift(),i.sort());if(!!e&&!f.event.customEvent[h]||!!f.event.global[h]){c=typeof c=="object"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.exclusive=j,c.namespace=i.join("."),c.namespace_re=new RegExp("(^|\\.)"+i.join("\\.(?:.*\\.)?")+"(\\.|$)");if(g||!e)c.preventDefault(),c.stopPropagation();if(!e){f.each(f.cache,function(){var a=f.expando,b=this[a];b&&b.events&&b.events[h]&&f.event.trigger(c,d,b.handle.elem)});return}if(e.nodeType===3||e.nodeType===8)return;c.result=b,c.target=e,d=d!=null?f.makeArray(d):[],d.unshift(c);var k=e,l=h.indexOf(":")<0?"on"+h:"";do{var m=f._data(k,"handle");c.currentTarget=k,m&&m.apply(k,d),l&&f.acceptData(k)&&k[l]&&k[l].apply(k,d)===!1&&(c.result=!1,c.preventDefault()),k=k.parentNode||k.ownerDocument||k===c.target.ownerDocument&&a}while(k&&!c.isPropagationStopped());if(!c.isDefaultPrevented()){var n,o=f.event.special[h]||{};if((!o._default||o._default.call(e.ownerDocument,c)===!1)&&(h!=="click"||!f.nodeName(e,"a"))&&f.acceptData(e)){try{l&&e[h]&&(n=e[l],n&&(e[l]=null),f.event.triggered=h,e[h]())}catch(p){}n&&(e[l]=n),f.event.triggered=b}}return c.result}},handle:function(c){c=f.event.fix(c||a.event);var d=((f._data(this,"events")||{})[c.type]||[]).slice(0),e=!c.exclusive&&!c.namespace,g=Array.prototype.slice.call(arguments,0);g[0]=c,c.currentTarget=this;for(var h=0,i=d.length;h-1?f.map(a.options,function(a){return a.selected}).join("-"):"":f.nodeName(a,"select")&&(c=a.selectedIndex);return c},I=function(c){var d=c.target,e,g;if(!!x.test(d.nodeName)&&!d.readOnly){e=f._data(d,"_change_data"),g=H(d),(c.type!=="focusout"||d.type!=="radio")&&f._data(d,"_change_data",g);if(e===b||g===e)return;if(e!=null||g)c.type="change",c.liveFired=b,f.event.trigger(c,arguments[1],d)}};f.event.special.change={filters:{focusout:I,beforedeactivate:I,click:function(a){var b=a.target,c=f.nodeName(b,"input")?b.type:"";(c==="radio"||c==="checkbox"||f.nodeName(b,"select"))&&I.call(this,a)},keydown:function(a){var b=a.target,c=f.nodeName(b,"input")?b.type:"";(a.keyCode===13&&!f.nodeName(b,"textarea")||a.keyCode===32&&(c==="checkbox"||c==="radio")||c==="select-multiple")&&I.call(this,a)},beforeactivate:function(a){var b=a.target;f._data(b,"_change_data",H(b))}},setup:function(a,b){if(this.type==="file")return!1;for(var c in G)f.event.add(this,c+".specialChange",G[c]);return x.test(this.nodeName)},teardown:function(a){f.event.remove(this,".specialChange");return x.test(this.nodeName)}},G=f.event.special.change.filters,G.focus=G.beforeactivate}f.support.focusinBubbles||f.each({focus:"focusin",blur:"focusout"},function(a,b){function e(a){var c=f.event.fix(a);c.type=b,c.originalEvent={},f.event.trigger(c,null,c.target),c.isDefaultPrevented()&&a.preventDefault()}var d=0;f.event.special[b]={setup:function(){d++===0&&c.addEventListener(a,e,!0)},teardown:function(){--d===0&&c.removeEventListener(a,e,!0)}}}),f.each(["bind","one"],function(a,c){f.fn[c]=function(a,d,e){var g;if(typeof a=="object"){for(var h in a)this[c](h,d,a[h],e);return this}if(arguments.length===2||d===!1)e=d,d=b;c==="one"?(g=function(a){f(this).unbind(a,g);return e.apply(this,arguments)},g.guid=e.guid||f.guid++):g=e;if(a==="unload"&&c!=="one")this.one(a,d,e);else for(var i=0,j=this.length;i0?this.bind(b,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0)}),function(){function u(a,b,c,d,e,f){for(var g=0,h=d.length;g0){j=i;break}}i=i[a]}d[g]=j}}}function t(a,b,c,d,e,f){for(var g=0,h=d.length;g+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,d=0,e=Object.prototype.toString,g=!1,h=!0,i=/\\/g,j=/\W/;[0,0].sort(function(){h=!1;return 0});var k=function(b,d,f,g){f=f||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!="string")return f;var i,j,n,o,q,r,s,t,u=!0,w=k.isXML(d),x=[],y=b;do{a.exec(""),i=a.exec(y);if(i){y=i[3],x.push(i[1]);if(i[2]){o=i[3];break}}}while(i);if(x.length>1&&m.exec(b))if(x.length===2&&l.relative[x[0]])j=v(x[0]+x[1],d);else{j=l.relative[x[0]]?[d]:k(x.shift(),d);while(x.length)b=x.shift(),l.relative[b]&&(b+=x.shift()),j=v(b,j)}else{!g&&x.length>1&&d.nodeType===9&&!w&&l.match.ID.test(x[0])&&!l.match.ID.test(x[x.length-1])&&(q=k.find(x.shift(),d,w),d=q.expr?k.filter(q.expr,q.set)[0]:q.set[0]);if(d){q=g?{expr:x.pop(),set:p(g)}:k.find(x.pop(),x.length===1&&(x[0]==="~"||x[0]==="+")&&d.parentNode?d.parentNode:d,w),j=q.expr?k.filter(q.expr,q.set):q.set,x.length>0?n=p(j):u=!1;while(x.length)r=x.pop(),s=r,l.relative[r]?s=x.pop():r="",s==null&&(s=d),l.relative[r](n,s,w)}else n=x=[]}n||(n=j),n||k.error(r||b);if(e.call(n)==="[object Array]")if(!u)f.push.apply(f,n);else if(d&&d.nodeType===1)for(t=0;n[t]!=null;t++)n[t]&&(n[t]===!0||n[t].nodeType===1&&k.contains(d,n[t]))&&f.push(j[t]);else for(t=0;n[t]!=null;t++)n[t]&&n[t].nodeType===1&&f.push(j[t]);else p(n,f);o&&(k(o,h,f,g),k.uniqueSort(f));return f};k.uniqueSort=function(a){if(r){g=h,a.sort(r);if(g)for(var b=1;b0},k.find=function(a,b,c){var d;if(!a)return[];for(var e=0,f=l.order.length;e":function(a,b){var c,d=typeof b=="string",e=0,f=a.length;if(d&&!j.test(b)){b=b.toLowerCase();for(;e=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(i,"")},TAG:function(a,b){return a[1].replace(i,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||k.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&k.error(a[0]);a[0]=d++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(i,"");!f&&l.attrMap[g]&&(a[1]=l.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(i,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=k(b[3],null,null,c);else{var g=k.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(l.match.POS.test(b[0])||l.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!k(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute("type"),c=a.type;return a.nodeName.toLowerCase()==="input"&&"text"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()==="input"&&"radio"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()==="input"&&"checkbox"===a.type},file:function(a){return a.nodeName.toLowerCase()==="input"&&"file"===a.type},password:function(a){return a.nodeName.toLowerCase()==="input"&&"password"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"submit"===a.type},image:function(a){return a.nodeName.toLowerCase()==="input"&&"image"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"reset"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&"button"===a.type||b==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return bc[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=l.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||k.getText([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=l.attrHandle[c]?l.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=l.setFilters[e];if(f)return f(a,c,b,d)}}},m=l.match.POS,n=function(a,b){return"\\"+(b-0+1)};for(var o in l.match)l.match[o]=new RegExp(l.match[o].source+/(?![^\[]*\])(?![^\(]*\))/.source),l.leftMatch[o]=new RegExp(/(^(?:.|\r|\n)*?)/.source+l.match[o].source.replace(/\\(\d+)/g,n));var p=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(q){p=function(a,b){var c=0,d=b||[];if(e.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length=="number")for(var f=a.length;c ",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(l.find.ID=function(a,c,d){if(typeof c.getElementById!="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},l.filter.ID=function(a,b){var c=typeof a.getAttributeNode!="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(l.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML=" ",a.firstChild&&typeof a.firstChild.getAttribute!="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(l.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=k,b=c.createElement("div"),d="__sizzle__";b.innerHTML="
";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){k=function(b,e,f,g){e=e||c;if(!g&&!k.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return p(e.getElementsByTagName(b),f);if(h[2]&&l.find.CLASS&&e.getElementsByClassName)return p(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return p([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return p([],f);if(i.id===h[3])return p([i],f)}try{return p(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var m=e,n=e.getAttribute("id"),o=n||d,q=e.parentNode,r=/^\s*[+~]/.test(b);n?o=o.replace(/'/g,"\\$&"):e.setAttribute("id",o),r&&q&&(e=e.parentNode);try{if(!r||q)return p(e.querySelectorAll("[id='"+o+"'] "+b),f)}catch(s){}finally{n||m.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)k[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement("div"),"div"),e=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(f){e=!0}k.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!k.isXML(a))try{if(e||!l.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return k(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement("div");a.innerHTML="
";if(!!a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;l.order.splice(1,0,"CLASS"),l.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?k.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?k.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:k.contains=function(){return!1},k.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var v=function(a,b){var c,d=[],e="",f=b.nodeType?[b]:b;while(c=l.match.PSEUDO.exec(a))e+=c[0],a=a.replace(l.match.PSEUDO,"");a=l.relative[a]?a+"*":a;for(var g=0,h=f.length;g0)for(h=g;h0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h,i,j={},k=1;if(g&&a.length){for(d=0,e=a.length;d-1:f(g).is(h))&&c.push({selector:i,elem:g,level:k});g=g.parentNode,k++}}return c}var l=S.test(a)||typeof a!="string"?f(a,b||this.context):0;for(d=0,e=this.length;d-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a)return this[0]&&this[0].parentNode?this.prevAll().length:-1;if(typeof a=="string")return f.inArray(this[0],f(a));return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a=="string"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(U(c[0])||U(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,"parentNode")},parentsUntil:function(a,b,c){return f.dir(a,"parentNode",c)},next:function(a){return f.nth(a,2,"nextSibling")},prev:function(a){return f.nth(a,2,"previousSibling")},nextAll:function(a){return f.dir(a,"nextSibling")},prevAll:function(a){return f.dir(a,"previousSibling")},nextUntil:function(a,b,c){return f.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return f.dir(a,"previousSibling",c)},siblings:function(a){return f.sibling(a.parentNode.firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c),g=R.call(arguments);N.test(a)||(d=c),d&&typeof d=="string"&&(e=f.filter(d,e)),e=this.length>1&&!T[a]?f.unique(e):e,(this.length>1||P.test(d))&&O.test(a)&&(e=e.reverse());return this.pushStack(e,a,g.join(","))}}),f.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var W=/ jQuery\d+="(?:\d+|null)"/g,X=/^\s+/,Y=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,Z=/<([\w:]+)/,$=/",""],legend:[1,""," "],thead:[1,""],tr:[2,""],td:[3,""],col:[2,""],area:[1,""," "],_default:[0,"",""]};be.optgroup=be.option,be.tbody=be.tfoot=be.colgroup=be.caption=be.thead,be.th=be.td,f.support.htmlSerialize||(be._default=[1,"div","
"]),f.fn.extend({text:function(a){if(f.isFunction(a))return this.each(function(b){var c=f(this);c.text(a.call(this,b,c.text()))});if(typeof a!="object"&&a!==b)return this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a));return f.text(this)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){f(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,"body")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,f(arguments[0]).toArray());return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName("*")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(W,""):null;if(typeof a=="string"&&!ba.test(a)&&(f.support.leadingWhitespace||!X.test(a))&&!be[(Z.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Y,"<$1>$2>");try{for(var c=0,d=this.length;c1&&l0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d=a.cloneNode(!0),e,g,h;if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bh(a,d),e=bi(a),g=bi(d);for(h=0;e[h];++h)g[h]&&bh(e[h],g[h])}if(b){bg(a,d);if(c){e=bi(a),g=bi(d);for(h=0;e[h];++h)bg(e[h],g[h])}}e=g=null;return d},clean:function(a,b,d,e){var g;b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);var h=[],i;for(var j=0,k;(k=a[j])!=null;j++){typeof k=="number"&&(k+="");if(!k)continue;if(typeof k=="string")if(!_.test(k))k=b.createTextNode(k);else{k=k.replace(Y,"<$1>$2>");var l=(Z.exec(k)||["",""])[1].toLowerCase(),m=be[l]||be._default,n=m[0],o=b.createElement("div");o.innerHTML=m[1]+k+m[2];while(n--)o=o.lastChild;if(!f.support.tbody){var p=$.test(k),q=l==="table"&&!p?o.firstChild&&o.firstChild.childNodes:m[1]===""&&!p?o.childNodes:[];for(i=q.length-1;i>=0;--i)f.nodeName(q[i],"tbody")&&!q[i].childNodes.length&&q[i].parentNode.removeChild(q[i])}!f.support.leadingWhitespace&&X.test(k)&&o.insertBefore(b.createTextNode(X.exec(k)[0]),o.firstChild),k=o.childNodes}var r;if(!f.support.appendChecked)if(k[0]&&typeof (r=k.length)=="number")for(i=0;i=0)return b+"px"}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return bn.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=f.isNaN(b)?"":"alpha(opacity="+b*100+")",g=d&&d.filter||c.filter||"";c.zoom=1;if(b>=1&&f.trim(g.replace(bm,""))===""){c.removeAttribute("filter");if(d&&!d.filter)return}c.filter=bm.test(g)?g.replace(bm,e):g+" "+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){var c;f.swap(a,{display:"inline-block"},function(){b?c=bv(a,"margin-right","marginRight"):c=a.style.marginRight});return c}})}),c.defaultView&&c.defaultView.getComputedStyle&&(bw=function(a,c){var d,e,g;c=c.replace(bo,"-$1").toLowerCase();if(!(e=a.ownerDocument.defaultView))return b;if(g=e.getComputedStyle(a,null))d=g.getPropertyValue(c),d===""&&!f.contains(a.ownerDocument.documentElement,a)&&(d=f.style(a,c));return d}),c.documentElement.currentStyle&&(bx=function(a,b){var c,d=a.currentStyle&&a.currentStyle[b],e=a.runtimeStyle&&a.runtimeStyle[b],f=a.style;!bp.test(d)&&bq.test(d)&&(c=f.left,e&&(a.runtimeStyle.left=a.currentStyle.left),f.left=b==="fontSize"?"1em":d||0,d=f.pixelLeft+"px",f.left=c,e&&(a.runtimeStyle.left=e));return d===""?"auto":d}),bv=bw||bx,f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style.display||f.css(a,"display"))==="none"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)});var bz=/%20/g,bA=/\[\]$/,bB=/\r?\n/g,bC=/#.*$/,bD=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bE=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bF=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,bG=/^(?:GET|HEAD)$/,bH=/^\/\//,bI=/\?/,bJ=/';
} else {
markup = ' ';
}
$('#uriHtml').val(markup);
$('#results').removeClass('hide');
},
/**
* Handler for the "Add file +" button
*/
addButtonClick : function () {
$('#results').addClass('hide');
MUB.addLi();
MUB.updateAllTestLinks();
$('#update').removeClass('hide').click(MUB.update);
$('#sources li:last input')[0].focus();
},
/**
* Runs on DOMready
*/
init : function () {
$('#jsDidntLoad').remove();
$('#app').removeClass('hide');
$('#sources').html('');
$('#add button').click(MUB.addButtonClick);
// make easier to copy text out of
$('#uriHtml, #groupConfig, #symlinkOpt').click(function () {
this.select();
}).focus(function () {
this.select();
});
$('a.ext').attr({target:'_blank'});
if (location.hash) {
// make links out of URIs from bookmarklet
$('#getBm').addClass('hide');
var i = 0, found = location.hash.substr(1).split(','), l = found.length;
$('#bmUris').html('Found by bookmarklet: /
');
var $p = $('#bmUris p');
for (; i < l; i++) {
$p.append($(' ').text(found[i])[0]);
if (i < (l - 1)) {
$p.append(', /');
}
}
$('#bmUris a').click(function () {
MUB.addButtonClick();
$('#sources li:last input').val(this.innerHTML);
MUB.liUpdateTestLink.call($('#sources li:last')[0]);
$('#results').addClass('hide');
return false;
}).attr({title:'Add file +'});
} else {
// setup bookmarklet 1
$.ajax({
url : '../?f=' + location.pathname.replace(/\/[^\/]*$/, '/bm.js').substr(1),
success : function (code) {
$('#bm')[0].href = code
.replace('%BUILDER_URL%', location.href)
.replace(/\n/g, ' ');
},
dataType : 'text'
});
if ($.browser.msie) {
$('#getBm p:last').append(' Sorry, not supported in MSIE!');
}
MUB.addButtonClick();
}
// setup bookmarklet 2
$.ajax({
url : '../?f=' + location.pathname.replace(/\/[^\/]*$/, '/bm2.js').substr(1),
success : function (code) {
$('#bm2')[0].href = code.replace(/\n/g, ' ');
},
dataType : 'text'
});
MUB.checkRewrite();
}
};
$(MUB.init);
builder/rewriteTest.js 0000666 00000000001 13634722572 0011057 0 ustar 00 1 builder/.htaccess 0000666 00000000165 13634722572 0010011 0 ustar 00
RewriteEngine on
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization},L]