[
  {
    "path": ".gitignore",
    "content": ".idea/\n"
  },
  {
    "path": ".travis.yml",
    "content": "language: php\n\nphp:\n  - 5.6\n  - 7.0\n  - 7.1\n  - 7.2\n\nbefore_script:\n  - travis_retry composer install --dev"
  },
  {
    "path": "LICENSE",
    "content": "Copyright (c) 2015 Slawomir Jasinski\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE."
  },
  {
    "path": "README.md",
    "content": "# CodeIgniter - minify [![Build Status](https://travis-ci.org/slav123/CodeIgniter-minify.svg?branch=master)](https://travis-ci.org/slav123/CodeIgniter-minify)\n\nSimple CodeIgniter library to compress **CSS and JavaScript** files on the fly.\n\nLibrary is based on few other scripts like <http://code.google.com/p/minify/> \nor <https://code.google.com/p/cssmin> to minify CSS and it uses\n[Google Closure compiler](https://developers.google.com/closure/compiler/) to \ncompress JavaScript\n\n## Installation\nJust put `Minify.php` file in libraries path, and create `minify.php` config file on config directory.\n\n## Using the library\n\n#### Configure the library:\nAll directories needs to be writable. Next you can set your own values for config file.\n\n```php\n// enable/disable library (default value: 'TRUE')\n$config['enabled'] = TRUE;\n\n// output path where the compiled files will be stored (default value: 'assets')\n$config['assets_dir'] = 'assets';\n\n// optional - path where the compiled css files will be stored (default value: '' - for backward compatibility)\n$config['assets_dir_css'] = ''; \n\n// optional - path where the compiled js files will be stored (default value: '' - for backward compatibility)\n$config['assets_dir_js'] = '';     \n\n// optional - handy when your assets are in a different domain than main website (default value: '')\n$config['base_url'] = '';\n\n// where to look for css files (default value: 'assets/css')\n$config['css_dir'] = 'assets/css';\n\n// where to look for js files (default value: 'assets/js')\n$config['js_dir'] = 'assets/js';\n\n// default file name for css (default value: 'style.css')\n$config['css_file'] = 'styles.css';\n\n// default file name for js (default value: 'scripts.js')\n$config['js_file'] = 'scripts.js';\n\n// default tag for css (default value: '<link href=\"%s\" rel=\"stylesheet\" type=\"text/css\" />')\n$config['css_tag'] = '<link href=\"%s\" rel=\"stylesheet\" type=\"text/css\" />';\n\n// default tag for js (default value: '<script type=\"text/javascript\" src=\"%s\"></script>')\n$config['js_tag'] = '<script type=\"text/javascript\" src=\"%s\"></script>';\n\n// use html tags on output and return as a string (default value: 'TRUE')\n// if html_tags === FALSE - array with links to assets is returned\n$config['html_tags'] = TRUE;\n\n// use automatic file names (default value: 'FALSE')\n$config['auto_names'] = FALSE;\n\n// use to enable versioning your assets (default value: 'FALSE')\n$config['versioning'] = FALSE;\n\n// automatically deploy when there are any changes in files (default value: 'TRUE')\n$config['deploy_on_change'] = TRUE;\n\n// compress files or not (default value: 'TRUE')\n$config['compress'] = TRUE;\n\n// compression engine setting (default values: 'minify' and 'closurecompiler')\n$config['compression_engine'] = array(\n\t'css' => 'minify', // minify || cssmin\n\t'js'  => 'closurecompiler' // closurecompiler || jsmin || jsminplus\n);\n\n// when you use closurecompiler as compression engine you can choose compression level (default value: 'SIMPLE_OPTIMIZATIONS')\n// avaliable options: \"WHITESPACE_ONLY\", \"SIMPLE_OPTIMIZATIONS\" or \"ADVANCED_OPTIMIZATIONS\"\n$config['closurecompiler']['compilation_level'] = 'SIMPLE_OPTIMIZATIONS';\n```\n\n#### Available engines\n* CSS - `minify` or `cssmin` - both of them are local, just try out which one is better for you,\n* JS - `closurecompiler` makes API call to external server, it's slower then regular inline engine, but it's super efficient with compression, `jsmin` and `jsminplus` are local\n\n#### Run the library\nIn the controller:\n```php\n// load the library\n$this->load->library('minify');\n// or load and assign custom config (will override values from config file)\n$this->load->library('minify', $config);\n// by default library's functionality is enabled, but in some cases you would like to return\n// assets without compilation and compression - when debugging or in development environment\n// in that case you can use config variable to disable it\n$config['enabled'] = FALSE;\n// or\n$this->minify->enabled = FALSE;\n\n```\nIn controller or view:\t\n```php\n// set css files - you can use array or string with commas\n// when using this method, you replaces previously added files\n$this->minify->css(array('reset.css', 'style.css', 'tinybox.css'));\n$this->minify->css('reset.css, style.css, tinybox.css');\n\n// add css files - you can use array or string with commas\n// when using this method, you're adding new files to previous ones\n$this->minify->add_css(array('reset.css'))->add_css('style.css, tinybox.css');\n\n// set js files - you can use array or string with commas\n// when using this method, you replaces previously added files\n$this->minify->js(array('html5.js', 'main.js'));\n$this->minify->js('html5.js, main.js');\n\n// set js files - you can use array or string with commas\n// when using this method, you're adding new files to previous ones\n$this->minify->add_js(array('html5.js'))->add_js('main.js');\n\n// with methods: css(), js(), add_css() and add_js()\n// you can pass group name for given files as second parameter\n// default group name is \"default\"\n$this->minify->js(array('html5.js', 'main.js'), 'extra');\n$this->minify->add_css('style.css, tinybox.css', 'another');\n\n// deploy css\n// bool argument for rebuild css - false means skip rebuilding (default value: TRUE) \necho $this->minify->deploy_css(TRUE);\n\n//Output: '<link href=\"path-to-compiled-css\" rel=\"stylesheet\" type=\"text/css\" />'\n\n// deploy js\n// bool argument for rebuild js  - false means skip rebuilding (default value: FALSE)\necho $this->minify->deploy_js(); \n\n//Output: '<script type=\"text/javascript\" src=\"path-to-compiled-js\"></script>'.\n\n// you can use automatic file name for particular deploy when you have $config['auto_names'] set to FALSE\n// to do so, you must set file name to 'auto' during deploy\necho $this->minify->deploy_css(TRUE, 'auto');\necho $this->minify->deploy_js(TRUE, 'auto');\n\n//Output: '<link href=\"path-to-compiled-css-with-auto-file-name\" rel=\"stylesheet\" type=\"text/css\" />'\n//Output: '<script type=\"text/javascript\" src=\"path-to-compiled-js-with-auto-file-name\"></script>'.\n\n// you can deploy only particular group of files\necho $this->minify->deploy_css(TRUE, NULL, 'another');\necho $this->minify->deploy_js(TRUE, 'auto', 'extra'); \n\n//Output: '<link href=\"path-to-compiled-css-group\" rel=\"stylesheet\" type=\"text/css\" />'\n//Output: '<script type=\"text/javascript\" src=\"path-to-compiled-js-group-with-auto-file-name\"></script>'.\n\n// you can enable versioning your your assets via config variable `$config['versioning']` or manually\n$this->minify->versioning = TRUE;\necho $this->minify->deploy_js(); \n\n//Output: '<script type=\"text/javascript\" src=\"path-to-compiled.js?v=hash-here\"></script>'.\n```\n    \n## Changelog\n\n01 Mar 2021\n* comments fixing\n* config checks only when deploy\n\n26 Jul 2019\n* added option to manually change version number for assets (thanks [screamingjungle](https://github.com/screamingjungle))\n\n11 Feb 2019\n* fixed an issue where not all config variables from the constructor were taken into account\n\n02 Feb 2019\n* new config variable to allow of use a custom domain/subdomain for your assets: `$config['base_url']` (default to '')\n\n25 Jul 2018\n* new config variable to disable default behavior - deploy when any file is changed: `$config['change_on_deploy']` (default to TRUE)\n\n24 Jul 2018\n* handle errors for closurecompiler engine\n\n26 Feb 2018\n* new config variable to determine if we want to return html tags (as string result) or only links to the assets (as array): `$config['html_tags']` (default to TRUE)\n* we can now specify what HTML tag will be used for CSS and JS through `$config['css_tag']` and `$config['js_tag']`\n\n17 Jun 2017\n* new config variable to enable versioning assets `$config['versioning']` (default to FALSE)\n* new config variable to enable/disable library - useful for debugging: `$config['enabled']` (default to TRUE)\n\n29 Dec 2016\n* introduce option to save compiled css and js files in different folders - new config variables: `$config['assets_dir_css']` and `$config['assets_dir_js']`.\n\n29 Apr 2015\n* allow using automatic file name for particular deploy when you have `$config['auto_names']` set to `FALSE`\n* documentation update\n\n20 Apr 2015\n* Closure compiler configuration extracted to config file \n\n22 Mar 2015\n* method chaining support\n* new methods: `add_css()` and `add_js()` - gives ability for adding files to existing files arrays\n* added support to run library with custom array config, assigned as second parameter (during loading) `$this->load->library('minify', $config);`\n* added support for *groups* in files arrays - as second (optional) parameter in methods: `css()`, `js()`, `add_css()` and `add_js()` (i.e. `$this->minify->js(array('script.js'), 'extra');` - default group name is *default*)\n* added support for strings as first parameter in methods: `css()`, `js()`, `add_css()` and `add_js()` (i.e. `$this->minify->js('first.js, second.js');`)\n* added support for automatic files names: `$config['auto_names'] = TRUE;`\n* external compression classes moved to *minify* folder\n* unit tests for new features\n\n10 Feb 2015\n* Unit testing\n\n09 Feb 2015\n* 2 new engines to compress JS files\n* documentation update\n\n13 Oct 2014\n* changed way of generating JS file\n\n14 July 2014\n* small bug fixes in JS compression\n\n4 July 2014\n* sample JavaScript files to see how it works \n* detection of empty JS file causes force refresh\n\n23 May 2014\n\n* you can chose your compression engine library in config file (CSS only)\n* speed optimisations\n* force CSS rewrite using $this->minify->deploy_css(TRUE);\n\n11 Mar 2014\n\n* completely rewrite CSS parser - uses cssmin compress CSS,\n* detects file modification time no longer force rewrites,\n* example usage now included withing app\n\n## Any questions?\n\nReport theme here: <https://github.com/slav123/CodeIgniter-minify/issues>\n"
  },
  {
    "path": "application/config/autoload.php",
    "content": "<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');\n/*\n| -------------------------------------------------------------------\n| AUTO-LOADER\n| -------------------------------------------------------------------\n| This file specifies which systems should be loaded by default.\n|\n| In order to keep the framework as light-weight as possible only the\n| absolute minimal resources are loaded by default. For example,\n| the database is not connected to automatically since no assumption\n| is made regarding whether you intend to use it.  This file lets\n| you globally define which systems you would like loaded with every\n| request.\n|\n| -------------------------------------------------------------------\n| Instructions\n| -------------------------------------------------------------------\n|\n| These are the things you can load automatically:\n|\n| 1. Packages\n| 2. Libraries\n| 3. Helper files\n| 4. Custom config files\n| 5. Language files\n| 6. Models\n|\n*/\n\n/*\n| -------------------------------------------------------------------\n|  Auto-load Packges\n| -------------------------------------------------------------------\n| Prototype:\n|\n|  $autoload['packages'] = array(APPPATH.'third_party', '/usr/local/shared');\n|\n*/\n\n$autoload['packages'] = array();\n\n\n/*\n| -------------------------------------------------------------------\n|  Auto-load Libraries\n| -------------------------------------------------------------------\n| These are the classes located in the system/libraries folder\n| or in your application/libraries folder.\n|\n| Prototype:\n|\n|\t$autoload['libraries'] = array('database', 'session', 'xmlrpc');\n*/\n\n$autoload['libraries'] = array();\n\n\n/*\n| -------------------------------------------------------------------\n|  Auto-load Helper Files\n| -------------------------------------------------------------------\n| Prototype:\n|\n|\t$autoload['helper'] = array('url', 'file');\n*/\n\n$autoload['helper'] = array();\n\n\n/*\n| -------------------------------------------------------------------\n|  Auto-load Config files\n| -------------------------------------------------------------------\n| Prototype:\n|\n|\t$autoload['config'] = array('config1', 'config2');\n|\n| NOTE: This item is intended for use ONLY if you have created custom\n| config files.  Otherwise, leave it blank.\n|\n*/\n\n$autoload['config'] = array();\n\n\n/*\n| -------------------------------------------------------------------\n|  Auto-load Language files\n| -------------------------------------------------------------------\n| Prototype:\n|\n|\t$autoload['language'] = array('lang1', 'lang2');\n|\n| NOTE: Do not include the \"_lang\" part of your file.  For example\n| \"codeigniter_lang.php\" would be referenced as array('codeigniter');\n|\n*/\n\n$autoload['language'] = array();\n\n\n/*\n| -------------------------------------------------------------------\n|  Auto-load Models\n| -------------------------------------------------------------------\n| Prototype:\n|\n|\t$autoload['model'] = array('model1', 'model2');\n|\n*/\n\n$autoload['model'] = array();\n\n\n/* End of file autoload.php */\n/* Location: ./application/config/autoload.php */"
  },
  {
    "path": "application/config/config.php",
    "content": "<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');\n\n/*\n|--------------------------------------------------------------------------\n| Base Site URL\n|--------------------------------------------------------------------------\n|\n| URL to your CodeIgniter root. Typically this will be your base URL,\n| WITH a trailing slash:\n|\n|\thttp://example.com/\n|\n| If this is not set then CodeIgniter will guess the protocol, domain and\n| path to your installation.\n|\n*/\n$config['base_url']\t= 'http://minify.localhost/';\n\n/*\n|--------------------------------------------------------------------------\n| Index File\n|--------------------------------------------------------------------------\n|\n| Typically this will be your index.php file, unless you've renamed it to\n| something else. If you are using mod_rewrite to remove the page set this\n| variable so that it is blank.\n|\n*/\n$config['index_page'] = 'index.php';\n\n/*\n|--------------------------------------------------------------------------\n| URI PROTOCOL\n|--------------------------------------------------------------------------\n|\n| This item determines which server global should be used to retrieve the\n| URI string.  The default setting of 'AUTO' works for most servers.\n| If your links do not seem to work, try one of the other delicious flavors:\n|\n| 'AUTO'\t\t\tDefault - auto detects\n| 'PATH_INFO'\t\tUses the PATH_INFO\n| 'QUERY_STRING'\tUses the QUERY_STRING\n| 'REQUEST_URI'\t\tUses the REQUEST_URI\n| 'ORIG_PATH_INFO'\tUses the ORIG_PATH_INFO\n|\n*/\n$config['uri_protocol']\t= 'AUTO';\n\n/*\n|--------------------------------------------------------------------------\n| URL suffix\n|--------------------------------------------------------------------------\n|\n| This option allows you to add a suffix to all URLs generated by CodeIgniter.\n| For more information please see the user guide:\n|\n| http://codeigniter.com/user_guide/general/urls.html\n*/\n\n$config['url_suffix'] = '';\n\n/*\n|--------------------------------------------------------------------------\n| Default Language\n|--------------------------------------------------------------------------\n|\n| This determines which set of language files should be used. Make sure\n| there is an available translation if you intend to use something other\n| than english.\n|\n*/\n$config['language']\t= 'english';\n\n/*\n|--------------------------------------------------------------------------\n| Default Character Set\n|--------------------------------------------------------------------------\n|\n| This determines which character set is used by default in various methods\n| that require a character set to be provided.\n|\n*/\n$config['charset'] = 'UTF-8';\n\n/*\n|--------------------------------------------------------------------------\n| Enable/Disable System Hooks\n|--------------------------------------------------------------------------\n|\n| If you would like to use the 'hooks' feature you must enable it by\n| setting this variable to TRUE (boolean).  See the user guide for details.\n|\n*/\n$config['enable_hooks'] = FALSE;\n\n\n/*\n|--------------------------------------------------------------------------\n| Class Extension Prefix\n|--------------------------------------------------------------------------\n|\n| This item allows you to set the filename/classname prefix when extending\n| native libraries.  For more information please see the user guide:\n|\n| http://codeigniter.com/user_guide/general/core_classes.html\n| http://codeigniter.com/user_guide/general/creating_libraries.html\n|\n*/\n$config['subclass_prefix'] = 'MY_';\n\n\n/*\n|--------------------------------------------------------------------------\n| Allowed URL Characters\n|--------------------------------------------------------------------------\n|\n| This lets you specify with a regular expression which characters are permitted\n| within your URLs.  When someone tries to submit a URL with disallowed\n| characters they will get a warning message.\n|\n| As a security measure you are STRONGLY encouraged to restrict URLs to\n| as few characters as possible.  By default only these are allowed: a-z 0-9~%.:_-\n|\n| Leave blank to allow all characters -- but only if you are insane.\n|\n| DO NOT CHANGE THIS UNLESS YOU FULLY UNDERSTAND THE REPERCUSSIONS!!\n|\n*/\n$config['permitted_uri_chars'] = 'a-z 0-9~%.:_\\-';\n\n\n/*\n|--------------------------------------------------------------------------\n| Enable Query Strings\n|--------------------------------------------------------------------------\n|\n| By default CodeIgniter uses search-engine friendly segment based URLs:\n| example.com/who/what/where/\n|\n| By default CodeIgniter enables access to the $_GET array.  If for some\n| reason you would like to disable it, set 'allow_get_array' to FALSE.\n|\n| You can optionally enable standard query string based URLs:\n| example.com?who=me&what=something&where=here\n|\n| Options are: TRUE or FALSE (boolean)\n|\n| The other items let you set the query string 'words' that will\n| invoke your controllers and its functions:\n| example.com/index.php?c=controller&m=function\n|\n| Please note that some of the helpers won't work as expected when\n| this feature is enabled, since CodeIgniter is designed primarily to\n| use segment based URLs.\n|\n*/\n$config['allow_get_array']\t\t= TRUE;\n$config['enable_query_strings'] = FALSE;\n$config['controller_trigger']\t= 'c';\n$config['function_trigger']\t\t= 'm';\n$config['directory_trigger']\t= 'd'; // experimental not currently in use\n\n/*\n|--------------------------------------------------------------------------\n| Error Logging Threshold\n|--------------------------------------------------------------------------\n|\n| If you have enabled error logging, you can set an error threshold to\n| determine what gets logged. Threshold options are:\n| You can enable error logging by setting a threshold over zero. The\n| threshold determines what gets logged. Threshold options are:\n|\n|\t0 = Disables logging, Error logging TURNED OFF\n|\t1 = Error Messages (including PHP errors)\n|\t2 = Debug Messages\n|\t3 = Informational Messages\n|\t4 = All Messages\n|\n| For a live site you'll usually only enable Errors (1) to be logged otherwise\n| your log files will fill up very fast.\n|\n*/\n$config['log_threshold'] = 0;\n\n/*\n|--------------------------------------------------------------------------\n| Error Logging Directory Path\n|--------------------------------------------------------------------------\n|\n| Leave this BLANK unless you would like to set something other than the default\n| application/logs/ folder. Use a full server path with trailing slash.\n|\n*/\n$config['log_path'] = '';\n\n/*\n|--------------------------------------------------------------------------\n| Date Format for Logs\n|--------------------------------------------------------------------------\n|\n| Each item that is logged has an associated date. You can use PHP date\n| codes to set your own date formatting\n|\n*/\n$config['log_date_format'] = 'Y-m-d H:i:s';\n\n/*\n|--------------------------------------------------------------------------\n| Cache Directory Path\n|--------------------------------------------------------------------------\n|\n| Leave this BLANK unless you would like to set something other than the default\n| system/cache/ folder.  Use a full server path with trailing slash.\n|\n*/\n$config['cache_path'] = '';\n\n/*\n|--------------------------------------------------------------------------\n| Encryption Key\n|--------------------------------------------------------------------------\n|\n| If you use the Encryption class or the Session class you\n| MUST set an encryption key.  See the user guide for info.\n|\n*/\n$config['encryption_key'] = '74dpbs2r';\n\n/*\n|--------------------------------------------------------------------------\n| Session Variables\n|--------------------------------------------------------------------------\n|\n| 'sess_cookie_name'\t\t= the name you want for the cookie\n| 'sess_expiration'\t\t\t= the number of SECONDS you want the session to last.\n|   by default sessions last 7200 seconds (two hours).  Set to zero for no expiration.\n| 'sess_expire_on_close'\t= Whether to cause the session to expire automatically\n|   when the browser window is closed\n| 'sess_encrypt_cookie'\t\t= Whether to encrypt the cookie\n| 'sess_use_database'\t\t= Whether to save the session data to a database\n| 'sess_table_name'\t\t\t= The name of the session database table\n| 'sess_match_ip'\t\t\t= Whether to match the user's IP address when reading the session data\n| 'sess_match_useragent'\t= Whether to match the User Agent when reading the session data\n| 'sess_time_to_update'\t\t= how many seconds between CI refreshing Session Information\n|\n*/\n$config['sess_cookie_name']\t\t= 'ci_session';\n$config['sess_expiration']\t\t= 7200;\n$config['sess_expire_on_close']\t= FALSE;\n$config['sess_encrypt_cookie']\t= FALSE;\n$config['sess_use_database']\t= FALSE;\n$config['sess_table_name']\t\t= 'ci_sessions';\n$config['sess_match_ip']\t\t= FALSE;\n$config['sess_match_useragent']\t= TRUE;\n$config['sess_time_to_update']\t= 300;\n\n/*\n|--------------------------------------------------------------------------\n| Cookie Related Variables\n|--------------------------------------------------------------------------\n|\n| 'cookie_prefix' = Set a prefix if you need to avoid collisions\n| 'cookie_domain' = Set to .your-domain.com for site-wide cookies\n| 'cookie_path'   =  Typically will be a forward slash\n| 'cookie_secure' =  Cookies will only be set if a secure HTTPS connection exists.\n|\n*/\n$config['cookie_prefix']\t= \"\";\n$config['cookie_domain']\t= \"\";\n$config['cookie_path']\t\t= \"/\";\n$config['cookie_secure']\t= FALSE;\n\n/*\n|--------------------------------------------------------------------------\n| Global XSS Filtering\n|--------------------------------------------------------------------------\n|\n| Determines whether the XSS filter is always active when GET, POST or\n| COOKIE data is encountered\n|\n*/\n$config['global_xss_filtering'] = FALSE;\n\n/*\n|--------------------------------------------------------------------------\n| Cross Site Request Forgery\n|--------------------------------------------------------------------------\n| Enables a CSRF cookie token to be set. When set to TRUE, token will be\n| checked on a submitted form. If you are accepting user data, it is strongly\n| recommended CSRF protection be enabled.\n|\n| 'csrf_token_name' = The token name\n| 'csrf_cookie_name' = The cookie name\n| 'csrf_expire' = The number in seconds the token should expire.\n*/\n$config['csrf_protection'] = FALSE;\n$config['csrf_token_name'] = 'csrf_test_name';\n$config['csrf_cookie_name'] = 'csrf_cookie_name';\n$config['csrf_expire'] = 7200;\n\n/*\n|--------------------------------------------------------------------------\n| Output Compression\n|--------------------------------------------------------------------------\n|\n| Enables Gzip output compression for faster page loads.  When enabled,\n| the output class will test whether your server supports Gzip.\n| Even if it does, however, not all browsers support compression\n| so enable only if you are reasonably sure your visitors can handle it.\n|\n| VERY IMPORTANT:  If you are getting a blank page when compression is enabled it\n| means you are prematurely outputting something to your browser. It could\n| even be a line of whitespace at the end of one of your scripts.  For\n| compression to work, nothing can be sent before the output buffer is called\n| by the output class.  Do not 'echo' any values with compression enabled.\n|\n*/\n$config['compress_output'] = FALSE;\n\n/*\n|--------------------------------------------------------------------------\n| Master Time Reference\n|--------------------------------------------------------------------------\n|\n| Options are 'local' or 'gmt'.  This pref tells the system whether to use\n| your server's local time as the master 'now' reference, or convert it to\n| GMT.  See the 'date helper' page of the user guide for information\n| regarding date handling.\n|\n*/\n$config['time_reference'] = 'local';\n\n\n/*\n|--------------------------------------------------------------------------\n| Rewrite PHP Short Tags\n|--------------------------------------------------------------------------\n|\n| If your PHP installation does not have short tag support enabled CI\n| can rewrite the tags on-the-fly, enabling you to utilize that syntax\n| in your view files.  Options are TRUE or FALSE (boolean)\n|\n*/\n$config['rewrite_short_tags'] = FALSE;\n\n\n/*\n|--------------------------------------------------------------------------\n| Reverse Proxy IPs\n|--------------------------------------------------------------------------\n|\n| If your server is behind a reverse proxy, you must whitelist the proxy IP\n| addresses from which CodeIgniter should trust the HTTP_X_FORWARDED_FOR\n| header in order to properly identify the visitor's IP address.\n| Comma-delimited, e.g. '10.0.1.200,10.0.1.201'\n|\n*/\n$config['proxy_ips'] = '';\n\n\n/* End of file config.php */\n/* Location: ./application/config/config.php */\n"
  },
  {
    "path": "application/config/constants.php",
    "content": "<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');\n\n/*\n|--------------------------------------------------------------------------\n| File and Directory Modes\n|--------------------------------------------------------------------------\n|\n| These prefs are used when checking and setting modes when working\n| with the file system.  The defaults are fine on servers with proper\n| security, but you may wish (or even need) to change the values in\n| certain environments (Apache running a separate process for each\n| user, PHP under CGI with Apache suEXEC, etc.).  Octal values should\n| always be used to set the mode correctly.\n|\n*/\ndefine('FILE_READ_MODE', 0644);\ndefine('FILE_WRITE_MODE', 0666);\ndefine('DIR_READ_MODE', 0755);\ndefine('DIR_WRITE_MODE', 0777);\n\n/*\n|--------------------------------------------------------------------------\n| File Stream Modes\n|--------------------------------------------------------------------------\n|\n| These modes are used when working with fopen()/popen()\n|\n*/\n\ndefine('FOPEN_READ',\t\t\t\t\t\t\t'rb');\ndefine('FOPEN_READ_WRITE',\t\t\t\t\t\t'r+b');\ndefine('FOPEN_WRITE_CREATE_DESTRUCTIVE',\t\t'wb'); // truncates existing file data, use with care\ndefine('FOPEN_READ_WRITE_CREATE_DESTRUCTIVE',\t'w+b'); // truncates existing file data, use with care\ndefine('FOPEN_WRITE_CREATE',\t\t\t\t\t'ab');\ndefine('FOPEN_READ_WRITE_CREATE',\t\t\t\t'a+b');\ndefine('FOPEN_WRITE_CREATE_STRICT',\t\t\t\t'xb');\ndefine('FOPEN_READ_WRITE_CREATE_STRICT',\t\t'x+b');\n\n\n/* End of file constants.php */\n/* Location: ./application/config/constants.php */"
  },
  {
    "path": "application/config/mimes.php",
    "content": "<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');\n/*\n| -------------------------------------------------------------------\n| MIME TYPES\n| -------------------------------------------------------------------\n| This file contains an array of mime types.  It is used by the\n| Upload class to help identify allowed file types.\n|\n*/\n\n$mimes = array(\t'hqx'\t=>\t'application/mac-binhex40',\n\t\t\t\t'cpt'\t=>\t'application/mac-compactpro',\n\t\t\t\t'csv'\t=>\tarray('text/x-comma-separated-values', 'text/comma-separated-values', 'application/octet-stream', 'application/vnd.ms-excel', 'application/x-csv', 'text/x-csv', 'text/csv', 'application/csv', 'application/excel', 'application/vnd.msexcel'),\n\t\t\t\t'bin'\t=>\t'application/macbinary',\n\t\t\t\t'dms'\t=>\t'application/octet-stream',\n\t\t\t\t'lha'\t=>\t'application/octet-stream',\n\t\t\t\t'lzh'\t=>\t'application/octet-stream',\n\t\t\t\t'exe'\t=>\tarray('application/octet-stream', 'application/x-msdownload'),\n\t\t\t\t'class'\t=>\t'application/octet-stream',\n\t\t\t\t'psd'\t=>\t'application/x-photoshop',\n\t\t\t\t'so'\t=>\t'application/octet-stream',\n\t\t\t\t'sea'\t=>\t'application/octet-stream',\n\t\t\t\t'dll'\t=>\t'application/octet-stream',\n\t\t\t\t'oda'\t=>\t'application/oda',\n\t\t\t\t'pdf'\t=>\tarray('application/pdf', 'application/x-download'),\n\t\t\t\t'ai'\t=>\t'application/postscript',\n\t\t\t\t'eps'\t=>\t'application/postscript',\n\t\t\t\t'ps'\t=>\t'application/postscript',\n\t\t\t\t'smi'\t=>\t'application/smil',\n\t\t\t\t'smil'\t=>\t'application/smil',\n\t\t\t\t'mif'\t=>\t'application/vnd.mif',\n\t\t\t\t'xls'\t=>\tarray('application/excel', 'application/vnd.ms-excel', 'application/msexcel'),\n\t\t\t\t'ppt'\t=>\tarray('application/powerpoint', 'application/vnd.ms-powerpoint'),\n\t\t\t\t'wbxml'\t=>\t'application/wbxml',\n\t\t\t\t'wmlc'\t=>\t'application/wmlc',\n\t\t\t\t'dcr'\t=>\t'application/x-director',\n\t\t\t\t'dir'\t=>\t'application/x-director',\n\t\t\t\t'dxr'\t=>\t'application/x-director',\n\t\t\t\t'dvi'\t=>\t'application/x-dvi',\n\t\t\t\t'gtar'\t=>\t'application/x-gtar',\n\t\t\t\t'gz'\t=>\t'application/x-gzip',\n\t\t\t\t'php'\t=>\t'application/x-httpd-php',\n\t\t\t\t'php4'\t=>\t'application/x-httpd-php',\n\t\t\t\t'php3'\t=>\t'application/x-httpd-php',\n\t\t\t\t'phtml'\t=>\t'application/x-httpd-php',\n\t\t\t\t'phps'\t=>\t'application/x-httpd-php-source',\n\t\t\t\t'js'\t=>\t'application/x-javascript',\n\t\t\t\t'swf'\t=>\t'application/x-shockwave-flash',\n\t\t\t\t'sit'\t=>\t'application/x-stuffit',\n\t\t\t\t'tar'\t=>\t'application/x-tar',\n\t\t\t\t'tgz'\t=>\tarray('application/x-tar', 'application/x-gzip-compressed'),\n\t\t\t\t'xhtml'\t=>\t'application/xhtml+xml',\n\t\t\t\t'xht'\t=>\t'application/xhtml+xml',\n\t\t\t\t'zip'\t=>  array('application/x-zip', 'application/zip', 'application/x-zip-compressed'),\n\t\t\t\t'mid'\t=>\t'audio/midi',\n\t\t\t\t'midi'\t=>\t'audio/midi',\n\t\t\t\t'mpga'\t=>\t'audio/mpeg',\n\t\t\t\t'mp2'\t=>\t'audio/mpeg',\n\t\t\t\t'mp3'\t=>\tarray('audio/mpeg', 'audio/mpg', 'audio/mpeg3', 'audio/mp3'),\n\t\t\t\t'aif'\t=>\t'audio/x-aiff',\n\t\t\t\t'aiff'\t=>\t'audio/x-aiff',\n\t\t\t\t'aifc'\t=>\t'audio/x-aiff',\n\t\t\t\t'ram'\t=>\t'audio/x-pn-realaudio',\n\t\t\t\t'rm'\t=>\t'audio/x-pn-realaudio',\n\t\t\t\t'rpm'\t=>\t'audio/x-pn-realaudio-plugin',\n\t\t\t\t'ra'\t=>\t'audio/x-realaudio',\n\t\t\t\t'rv'\t=>\t'video/vnd.rn-realvideo',\n\t\t\t\t'wav'\t=>\tarray('audio/x-wav', 'audio/wave', 'audio/wav'),\n\t\t\t\t'bmp'\t=>\tarray('image/bmp', 'image/x-windows-bmp'),\n\t\t\t\t'gif'\t=>\t'image/gif',\n\t\t\t\t'jpeg'\t=>\tarray('image/jpeg', 'image/pjpeg'),\n\t\t\t\t'jpg'\t=>\tarray('image/jpeg', 'image/pjpeg'),\n\t\t\t\t'jpe'\t=>\tarray('image/jpeg', 'image/pjpeg'),\n\t\t\t\t'png'\t=>\tarray('image/png',  'image/x-png'),\n\t\t\t\t'tiff'\t=>\t'image/tiff',\n\t\t\t\t'tif'\t=>\t'image/tiff',\n\t\t\t\t'css'\t=>\t'text/css',\n\t\t\t\t'html'\t=>\t'text/html',\n\t\t\t\t'htm'\t=>\t'text/html',\n\t\t\t\t'shtml'\t=>\t'text/html',\n\t\t\t\t'txt'\t=>\t'text/plain',\n\t\t\t\t'text'\t=>\t'text/plain',\n\t\t\t\t'log'\t=>\tarray('text/plain', 'text/x-log'),\n\t\t\t\t'rtx'\t=>\t'text/richtext',\n\t\t\t\t'rtf'\t=>\t'text/rtf',\n\t\t\t\t'xml'\t=>\t'text/xml',\n\t\t\t\t'xsl'\t=>\t'text/xml',\n\t\t\t\t'mpeg'\t=>\t'video/mpeg',\n\t\t\t\t'mpg'\t=>\t'video/mpeg',\n\t\t\t\t'mpe'\t=>\t'video/mpeg',\n\t\t\t\t'qt'\t=>\t'video/quicktime',\n\t\t\t\t'mov'\t=>\t'video/quicktime',\n\t\t\t\t'avi'\t=>\t'video/x-msvideo',\n\t\t\t\t'movie'\t=>\t'video/x-sgi-movie',\n\t\t\t\t'doc'\t=>\t'application/msword',\n\t\t\t\t'docx'\t=>\tarray('application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/zip'),\n\t\t\t\t'xlsx'\t=>\tarray('application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'application/zip'),\n\t\t\t\t'word'\t=>\tarray('application/msword', 'application/octet-stream'),\n\t\t\t\t'xl'\t=>\t'application/excel',\n\t\t\t\t'eml'\t=>\t'message/rfc822',\n\t\t\t\t'json' => array('application/json', 'text/json')\n\t\t\t);\n\n\n/* End of file mimes.php */\n/* Location: ./application/config/mimes.php */\n"
  },
  {
    "path": "application/config/minify.php",
    "content": "<?php\n/**\n * Minify config Class\n *\n * PHP Version 5.3\n *\n * @category  PHP\n * @package   Controller\n * @author    Slawomir Jasinski <slav123@gmail.com>\n * @copyright 2015 All Rights Reserved SpiderSoft\n * @license   Copyright 2015 All Rights Reserved SpiderSoft\n * @link      http://www.spidersoft.com.au/projects/codeigniter-minify/\n */\n\ndefined('BASEPATH') OR exit('No direct script access allowed');\n\n\n/**\n * Minify config file\n *\n * @category  PHP\n * @package   Controller\n * @author    Slawomir Jasinski <slav123@gmail.com>\n * @copyright 2015 All Rights Reserved SpiderSoft\n * @license   Copyright 2015 All Rights Reserved SpiderSoft\n * @link      http://www.spidersoft.com.au/projects/codeigniter-minify/\n */\n\n// enable/disable library (default value: 'TRUE')\n// when enabled === FALSE library return assets without compilation and compression \n// usefull when debugging or in development environment\n$config['enabled'] = TRUE;\n\n// output path where the compiled files will be stored (default value: 'assets')\n$config['assets_dir'] = 'assets';\n\n// optional - path where the compiled css files will be stored (default value: '' - for backward compatibility)\n$config['assets_dir_css'] = ''; \n\n// optional - path where the compiled js files will be stored (default value: '' - for backward compatibility)\n$config['assets_dir_js'] = ''; \n\n// optional - handy when your assets are in a different domain than main website (default value: '')\n$config['base_url'] = '';    \n\n// where to look for css files (default value: 'assets/css')\n$config['css_dir'] = 'assets/css';\n\n// where to look for js files (default value: 'assets/js')\n$config['js_dir'] = 'assets/js';\n\n// default file name for css (default value: 'style.css')\n$config['css_file'] = 'styles.css';\n\n// default file name for js (default value: 'scripts.js')\n$config['js_file'] = 'scripts.js';\n\n// default tag for css (default value: '<link href=\"%s\" rel=\"stylesheet\" type=\"text/css\" />')\n$config['css_tag'] = '<link href=\"%s\" rel=\"stylesheet\" type=\"text/css\" />';\n\n// default tag for js (default value: '<script type=\"text/javascript\" src=\"%s\"></script>')\n$config['js_tag'] = '<script type=\"text/javascript\" src=\"%s\"></script>';\n\n// use html tags on output and return as a string (default value: 'TRUE')\n// if html_tags === FALSE - array with links to assets is returned\n$config['html_tags'] = TRUE;\n\n// use automatic file names (default value: 'FALSE')\n$config['auto_names'] = FALSE;\n\n// use to enable versioning your assets (default value: 'FALSE')\n$config['versioning'] = FALSE;\n\n// override version md5 with a number (default value: 'NULL')\n$config['version_number'] = NULL;\n\n// automatically deploy when there are any changes in files (default value: 'TRUE')\n$config['deploy_on_change'] = TRUE;\n\n// compress files or not (default value: 'TRUE')\n$config['compress'] = TRUE;\n\n// compression engine setting (default values: 'minify' and 'closurecompiler')\n$config['compression_engine'] = array(\n\t'css' => 'cssmin', // minify || cssmin\n\t'js'  => 'closurecompiler' // closurecompiler || jsmin || jsminplus\n);\n\n// when you use closurecompiler as compression engine you can choose compression level (default value: 'SIMPLE_OPTIMIZATIONS')\n// avaliable options: \"WHITESPACE_ONLY\", \"SIMPLE_OPTIMIZATIONS\" or \"ADVANCED_OPTIMIZATIONS\"\n$config['closurecompiler']['compilation_level'] = 'SIMPLE_OPTIMIZATIONS';\n\n\n// End of file minify.php\n// Location: ./application/config/minify.php\n"
  },
  {
    "path": "application/config/routes.php",
    "content": "<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');\n/*\n| -------------------------------------------------------------------------\n| URI ROUTING\n| -------------------------------------------------------------------------\n| This file lets you re-map URI requests to specific controller functions.\n|\n| Typically there is a one-to-one relationship between a URL string\n| and its corresponding controller class/method. The segments in a\n| URL normally follow this pattern:\n|\n|\texample.com/class/method/id/\n|\n| In some instances, however, you may want to remap this relationship\n| so that a different class/function is called than the one\n| corresponding to the URL.\n|\n| Please see the user guide for complete details:\n|\n|\thttp://codeigniter.com/user_guide/general/routing.html\n|\n| -------------------------------------------------------------------------\n| RESERVED ROUTES\n| -------------------------------------------------------------------------\n|\n| There area two reserved routes:\n|\n|\t$route['default_controller'] = 'welcome';\n|\n| This route indicates which controller class should be loaded if the\n| URI contains no data. In the above example, the \"welcome\" class\n| would be loaded.\n|\n|\t$route['404_override'] = 'errors/page_missing';\n|\n| This route will tell the Router what URI segments to use if those provided\n| in the URL cannot be matched to a valid route.\n|\n*/\n\n$route['default_controller'] = \"welcome\";\n$route['404_override'] = '';\n\n\n/* End of file routes.php */\n/* Location: ./application/config/routes.php */"
  },
  {
    "path": "application/controllers/index.html",
    "content": "<html>\n<head>\n\t<title>403 Forbidden</title>\n</head>\n<body>\n\n<p>Directory access is forbidden.</p>\n\n</body>\n</html>"
  },
  {
    "path": "application/controllers/welcome.php",
    "content": "<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');\n\nclass Welcome extends CI_Controller {\n\n\t/**\n\t * Index Page for this controller.\n\t *\n\t * Maps to the following URL\n\t * \t\thttp://example.com/index.php/welcome\n\t *\t- or -  \n\t * \t\thttp://example.com/index.php/welcome/index\n\t *\t- or -\n\t * Since this controller is set as the default controller in \n\t * config/routes.php, it's displayed at http://example.com/\n\t *\n\t * So any other public methods not prefixed with an underscore will\n\t * map to /index.php/welcome/<method_name>\n\t * @see http://codeigniter.com/user_guide/general/urls.html\n\t */\n\tpublic function index()\n\t{\n\t\t$this->load->library('minify');\n\t\t$this->load->helper('url');\n\t\t$this->load->view('welcome_message');\n\t}\n}\n\n/* End of file welcome.php */\n/* Location: ./application/controllers/welcome.php */"
  },
  {
    "path": "application/errors/error_404.php",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<title>404 Page Not Found</title>\n<style type=\"text/css\">\n\n::selection{ background-color: #E13300; color: white; }\n::moz-selection{ background-color: #E13300; color: white; }\n::webkit-selection{ background-color: #E13300; color: white; }\n\nbody {\n\tbackground-color: #fff;\n\tmargin: 40px;\n\tfont: 13px/20px normal Helvetica, Arial, sans-serif;\n\tcolor: #4F5155;\n}\n\na {\n\tcolor: #003399;\n\tbackground-color: transparent;\n\tfont-weight: normal;\n}\n\nh1 {\n\tcolor: #444;\n\tbackground-color: transparent;\n\tborder-bottom: 1px solid #D0D0D0;\n\tfont-size: 19px;\n\tfont-weight: normal;\n\tmargin: 0 0 14px 0;\n\tpadding: 14px 15px 10px 15px;\n}\n\ncode {\n\tfont-family: Consolas, Monaco, Courier New, Courier, monospace;\n\tfont-size: 12px;\n\tbackground-color: #f9f9f9;\n\tborder: 1px solid #D0D0D0;\n\tcolor: #002166;\n\tdisplay: block;\n\tmargin: 14px 0 14px 0;\n\tpadding: 12px 10px 12px 10px;\n}\n\n#container {\n\tmargin: 10px;\n\tborder: 1px solid #D0D0D0;\n\t-webkit-box-shadow: 0 0 8px #D0D0D0;\n}\n\np {\n\tmargin: 12px 15px 12px 15px;\n}\n</style>\n</head>\n<body>\n\t<div id=\"container\">\n\t\t<h1><?php echo $heading; ?></h1>\n\t\t<?php echo $message; ?>\n\t</div>\n</body>\n</html>"
  },
  {
    "path": "application/errors/error_db.php",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<title>Database Error</title>\n<style type=\"text/css\">\n\n::selection{ background-color: #E13300; color: white; }\n::moz-selection{ background-color: #E13300; color: white; }\n::webkit-selection{ background-color: #E13300; color: white; }\n\nbody {\n\tbackground-color: #fff;\n\tmargin: 40px;\n\tfont: 13px/20px normal Helvetica, Arial, sans-serif;\n\tcolor: #4F5155;\n}\n\na {\n\tcolor: #003399;\n\tbackground-color: transparent;\n\tfont-weight: normal;\n}\n\nh1 {\n\tcolor: #444;\n\tbackground-color: transparent;\n\tborder-bottom: 1px solid #D0D0D0;\n\tfont-size: 19px;\n\tfont-weight: normal;\n\tmargin: 0 0 14px 0;\n\tpadding: 14px 15px 10px 15px;\n}\n\ncode {\n\tfont-family: Consolas, Monaco, Courier New, Courier, monospace;\n\tfont-size: 12px;\n\tbackground-color: #f9f9f9;\n\tborder: 1px solid #D0D0D0;\n\tcolor: #002166;\n\tdisplay: block;\n\tmargin: 14px 0 14px 0;\n\tpadding: 12px 10px 12px 10px;\n}\n\n#container {\n\tmargin: 10px;\n\tborder: 1px solid #D0D0D0;\n\t-webkit-box-shadow: 0 0 8px #D0D0D0;\n}\n\np {\n\tmargin: 12px 15px 12px 15px;\n}\n</style>\n</head>\n<body>\n\t<div id=\"container\">\n\t\t<h1><?php echo $heading; ?></h1>\n\t\t<?php echo $message; ?>\n\t</div>\n</body>\n</html>"
  },
  {
    "path": "application/errors/error_general.php",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<title>Error</title>\n<style type=\"text/css\">\n\n::selection{ background-color: #E13300; color: white; }\n::moz-selection{ background-color: #E13300; color: white; }\n::webkit-selection{ background-color: #E13300; color: white; }\n\nbody {\n\tbackground-color: #fff;\n\tmargin: 40px;\n\tfont: 13px/20px normal Helvetica, Arial, sans-serif;\n\tcolor: #4F5155;\n}\n\na {\n\tcolor: #003399;\n\tbackground-color: transparent;\n\tfont-weight: normal;\n}\n\nh1 {\n\tcolor: #444;\n\tbackground-color: transparent;\n\tborder-bottom: 1px solid #D0D0D0;\n\tfont-size: 19px;\n\tfont-weight: normal;\n\tmargin: 0 0 14px 0;\n\tpadding: 14px 15px 10px 15px;\n}\n\ncode {\n\tfont-family: Consolas, Monaco, Courier New, Courier, monospace;\n\tfont-size: 12px;\n\tbackground-color: #f9f9f9;\n\tborder: 1px solid #D0D0D0;\n\tcolor: #002166;\n\tdisplay: block;\n\tmargin: 14px 0 14px 0;\n\tpadding: 12px 10px 12px 10px;\n}\n\n#container {\n\tmargin: 10px;\n\tborder: 1px solid #D0D0D0;\n\t-webkit-box-shadow: 0 0 8px #D0D0D0;\n}\n\np {\n\tmargin: 12px 15px 12px 15px;\n}\n</style>\n</head>\n<body>\n\t<div id=\"container\">\n\t\t<h1><?php echo $heading; ?></h1>\n\t\t<?php echo $message; ?>\n\t</div>\n</body>\n</html>"
  },
  {
    "path": "application/errors/error_php.php",
    "content": "<div style=\"border:1px solid #990000;padding-left:20px;margin:0 0 10px 0;\">\n\n<h4>A PHP Error was encountered</h4>\n\n<p>Severity: <?php echo $severity; ?></p>\n<p>Message:  <?php echo $message; ?></p>\n<p>Filename: <?php echo $filepath; ?></p>\n<p>Line Number: <?php echo $line; ?></p>\n\n</div>"
  },
  {
    "path": "application/errors/index.html",
    "content": "<html>\n<head>\n\t<title>403 Forbidden</title>\n</head>\n<body>\n\n<p>Directory access is forbidden.</p>\n\n</body>\n</html>"
  },
  {
    "path": "application/libraries/Minify.php",
    "content": "<?php\n/**\n * Minify Library Class\n *\n * PHP Version 5.3\n *\n * @category  PHP\n * @package   Library\n * @author    Slawomir Jasinski <slav123@gmail.com>\n * @copyright 2015 All Rights Reserved SpiderSoft\n * @license   Copyright 2015 All Rights Reserved SpiderSoft\n * @link      Location: http://github.com/slav123/CodeIgniter-Minify\n */\n\ndefined('BASEPATH') or exit('No direct script access allowed');\n\n/**\n * the Minify LibraryClass\n *\n * @category  PHP\n * @package   Controller\n * @author    Slawomir Jasinski <slav123@gmail.com>\n * @copyright 2016 All Rights Reserved SpiderSoft\n * @license   Copyright 2015 All Rights Reserved SpiderSoft\n * @link      http://www.spidersoft.com.au\n */\nclass Minify {\n\t/**\n\t * CodeIgniter global.\n\t *\n\t * @var object\n\t */\n\tprotected $ci;\n\n\t/**\n\t * Css files array.\n\t *\n\t * @var array\n\t */\n\tprotected $css_array = array();\n\n\t/**\n\t * Js files array.\n\t *\n\t * @var array\n\t */\n\tprotected $js_array = array();\n\n\t/**\n\t * Enable/disable.\n\t *\n\t * @var bool\n\t */\n\tpublic $enabled = TRUE;\n\n\t/**\n\t * Assets dir.\n\t *\n\t * @var string\n\t */\n\tpublic $assets_dir = 'assets';\n\n\t/**\n\t * Assets dir for css (optional).\n\t *\n\t * @var string\n\t */\n\tpublic $assets_dir_css = '';\n\n\t/**\n\t * Assets dir for js (optional).\n\t *\n\t * @var string\n\t */\n\tpublic $assets_dir_js = '';\n\n\t/**\n\t * Base URL.\n\t *\n\t * @var string\n\t */\n\tpublic $base_url = '';\n\n\t/**\n\t * Css dir.\n\t *\n\t * @var string\n\t */\n\tpublic $css_dir = 'assets/css';\n\n\t/**\n\t * Js dir.\n\t *\n\t * @var string\n\t */\n\tpublic $js_dir = 'assets/js';\n\n\t/**\n\t * Output css file name.\n\t *\n\t * @var string\n\t */\n\tpublic $css_file = 'styles.css';\n\n\t/**\n\t * Output js file name.\n\t *\n\t * @var string\n\t */\n\tpublic $js_file = 'scripts.js';\n\n\t/**\n\t * Output css tag template.\n\t *\n\t * @var string\n\t */\n\tpublic $css_tag = '<link href=\"%s\" rel=\"stylesheet\" type=\"text/css\" />';\n\n\t/**\n\t * Output js tag template.\n\t *\n\t * @var string\n\t */\n\tpublic $js_tag = '<script type=\"text/javascript\" src=\"%s\"></script>';\n\n\t/**\n\t * Use html tags on output.\n\t *\n\t * @var string\n\t */\n\tpublic $html_tags = TRUE;\n\n\t/**\n\t * Automatic file names.\n\t *\n\t * @var bool\n\t */\n\tpublic $auto_names = FALSE;\n\n\t/**\n\t * Automatic deploy on change.\n\t *\n\t * @var bool\n\t */\n\tpublic $deploy_on_change = TRUE;\n\n\t/**\n\t * File versioning.\n\t *\n\t * @var bool\n\t */\n\tpublic $versioning = FALSE;\n\n\t/**\n\t * File version number override.\n\t *\n\t * @var string\n\t */\n\tpublic $version_number = NULL;\n\n\t/**\n\t * Compress files or not.\n\t *\n\t * @var bool\n\t */\n\tpublic $compress = TRUE;\n\n\t/**\n\t * Compression engines.\n\t *\n\t * @var array\n\t */\n\tpublic $compression_engine = array('css' => 'minify', 'js' => 'closurecompiler');\n\n\t/**\n\t * Closurecompiler settings.\n\t *\n\t * @var array\n\t */\n\tpublic $closurecompiler = array('compilation_level' => 'SIMPLE_OPTIMIZATIONS');\n\n\t/**\n\t * Css file name with path.\n\t *\n\t * @var string\n\t */\n\tprivate $_css_file = '';\n\n\t/**\n\t * Js file name with path.\n\t *\n\t * @var string\n\t */\n\tprivate $_js_file = '';\n\n\t/**\n\t * Last modification.\n\t *\n\t * @var array\n\t */\n\tprivate $_lmod = array('css' => 0, 'js' => 0);\n\n\t/**\n\t * Constructor\n\t *\n\t * @param array $config Config array\n\t */\n\tpublic function __construct($config = array())\n\t{\n\t\t$this->ci = get_instance();\n\t\t$this->ci->load->config('minify', TRUE, TRUE);\n\n\t\t// user specified settings from config file\n\t\t$this->enabled            = $this->ci->config->item('enabled', 'minify') ?: $this->enabled;\n\t\t$this->assets_dir         = $this->ci->config->item('assets_dir', 'minify') ?: $this->assets_dir;\n\t\t$this->assets_dir_css     = $this->ci->config->item('assets_dir_css', 'minify') ?: $this->assets_dir_css;\n\t\t$this->assets_dir_js      = $this->ci->config->item('assets_dir_js', 'minify') ?: $this->assets_dir_js;\n\t\t$this->base_url           = $this->ci->config->item('base_url', 'minify') ?: $this->base_url;\n\t\t$this->css_dir            = $this->ci->config->item('css_dir', 'minify') ?: $this->css_dir;\n\t\t$this->js_dir             = $this->ci->config->item('js_dir', 'minify') ?: $this->js_dir;\n\t\t$this->css_file           = $this->ci->config->item('css_file', 'minify') ?: $this->css_file;\n\t\t$this->js_file            = $this->ci->config->item('js_file', 'minify') ?: $this->js_file;\n\t\t$this->css_tag            = $this->ci->config->item('css_tag', 'minify') ?: $this->css_tag;\n\t\t$this->js_tag             = $this->ci->config->item('js_tag', 'minify') ?: $this->js_tag;\n\t\t$this->html_tags          = $this->ci->config->item('html_tags', 'minify') ?: $this->html_tags;\n\t\t$this->auto_names         = $this->ci->config->item('auto_names', 'minify') ?: $this->auto_names;\n\t\t$this->deploy_on_change   = $this->ci->config->item('deploy_on_change', 'minify') ?: $this->deploy_on_change;\n\t\t$this->versioning         = $this->ci->config->item('versioning', 'minify') ?: $this->versioning;\n\t\t$this->version_number     = $this->ci->config->item('version_number', 'minify') ?: $this->version_number;\n\t\t$this->compress           = $this->ci->config->item('compress', 'minify') ?: $this->compress;\n\t\t$this->compression_engine = $this->ci->config->item('compression_engine',\n\t\t                                                    'minify') ?: $this->compression_engine;\n\t\t$this->closurecompiler    = $this->ci->config->item('closurecompiler', 'minify') ?: $this->closurecompiler;\n\n\t\tif (count($config) > 0)\n\t\t{\n\t\t\t// custom config array\n\t\t\tforeach ($config as $key => $val)\n\t\t\t{\n\t\t\t\tif (isset($this->$key))\n\t\t\t\t{\n\t\t\t\t\t$this->$key = $val;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// save default names for later use/reset\n\t\t$this->css_file_default = $this->css_file;\n\t\t$this->js_file_default  = $this->js_file;\n\n\n\t\tlog_message('debug', \"Minify Class Initialized\");\n\t}\n\n\t/**\n\t * Declare css files list\n\t *\n\t * @param mixed $css   File or files names\n\t * @param bool  $group Set group for files\n\t *\n\t * @return Minify\n\t */\n\tpublic function css($css, $group = 'default')\n\t{\n\t\tif (is_array($css))\n\t\t{\n\t\t\t$this->css_array[$group] = $css;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t$this->css_array[$group] = array_map('trim', explode(',', $css));\n\t\t}\n\n\t\treturn $this;\n\t}\n\n\t/**\n\t * Declare js files list\n\t *\n\t * @param mixed $js    File or files names\n\t * @param bool  $group Set group for files\n\t *\n\t * @return Minify\n\t */\n\tpublic function js($js, $group = 'default')\n\t{\n\t\tif (is_array($js))\n\t\t{\n\t\t\t$this->js_array[$group] = $js;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t$this->js_array[$group] = array_map('trim', explode(',', $js));\n\t\t}\n\n\t\treturn $this;\n\t}\n\n\t/**\n\t * Declare css files list\n\t *\n\t * @param mixed $css   File or files names\n\t * @param bool  $group Set group for files\n\t *\n\t * @return Minify\n\t */\n\tpublic function add_css($css, $group = 'default')\n\t{\n\t\tif ( ! isset($this->css_array[$group]))\n\t\t{\n\t\t\t$this->css_array[$group] = array();\n\t\t}\n\n\t\tif (is_array($css))\n\t\t{\n\t\t\t$this->css_array[$group] = array_unique(array_merge($this->css_array[$group], $css));\n\t\t}\n\t\telse\n\t\t{\n\t\t\t$this->css_array[$group] = array_unique(array_merge($this->css_array[$group],\n\t\t\t                                                    array_map('trim', explode(',', $css))));\n\t\t}\n\n\t\treturn $this;\n\t}\n\n\t/**\n\t * Declare js files list\n\t *\n\t * @param mixed $js    File or files names\n\t * @param bool  $group Set group for files\n\t *\n\t * @return Minify\n\t */\n\tpublic function add_js($js, $group = 'default')\n\t{\n\t\tif ( ! isset($this->js_array[$group]))\n\t\t{\n\t\t\t$this->js_array[$group] = array();\n\t\t}\n\n\t\tif (is_array($js))\n\t\t{\n\t\t\t$this->js_array[$group] = array_unique(array_merge($this->js_array[$group], $js));\n\t\t}\n\t\telse\n\t\t{\n\t\t\t$this->js_array[$group] = array_unique(array_merge($this->js_array[$group],\n\t\t\t                                                   array_map('trim', explode(',', $js))));\n\t\t}\n\n\t\treturn $this;\n\t}\n\n\t/**\n\t * Deploy and minify CSS\n\t *\n\t * @param bool $force     Force to rewrite file\n\t * @param null $file_name File name to create\n\t * @param null $group     Group name\n\t *\n\t * @return string|array\n\t */\n\tpublic function deploy_css($force = TRUE, $file_name = NULL, $group = NULL)\n\t{\n\t\t// perform checks\n\t\t$this->_config_checks('css');\n\n\t\t$return = array();\n\n\t\tif (is_null($file_name))\n\t\t{\n\t\t\t$file_name = $this->css_file_default;\n\t\t}\n\n\t\tif (is_null($group))\n\t\t{\n\t\t\tforeach ($this->css_array as $group_name => $group_array)\n\t\t\t{\n\t\t\t\t$return = array_merge($return, $this->_deploy_css($force, $file_name, $group_name));\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t$return = array_merge($return, $this->_deploy_css($force, $file_name, $group));\n\t\t}\n\n\t\treturn $this->_output($return, 'css');\n\t}\n\n\t/**\n\t * Deploy and minify js\n\t *\n\t * @param bool $force     Force rewriting js file\n\t * @param null $file_name File name\n\t * @param null $group     Group name\n\t *\n\t * @return string|array\n\t */\n\tpublic function deploy_js($force = FALSE, $file_name = NULL, $group = NULL)\n\t{\n\t\t// perform checks\n\t\t$this->_config_checks('js');\n\n\t\t$return = array();\n\n\t\tif (is_null($file_name))\n\t\t{\n\t\t\t$file_name = $this->js_file_default;\n\t\t}\n\n\t\tif (is_null($group))\n\t\t{\n\t\t\tforeach ($this->js_array as $group_name => $group_array)\n\t\t\t{\n\t\t\t\t$return = array_merge($return, $this->_deploy_js($force, $file_name, $group_name));\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t$return = array_merge($return, $this->_deploy_js($force, $file_name, $group));\n\t\t}\n\n\t\treturn $this->_output($return, 'js');\n\t}\n\n\t/**\n\t * Build and minify CSS\n\t *\n\t * @param bool $force     Force to rewrite file\n\t * @param null $file_name File name to create\n\t * @param null $group     Group name\n\t *\n\t * @return array\n\t */\n\tprivate function _deploy_css($force = TRUE, $file_name = NULL, $group = NULL)\n\t{\n\t\tif ($this->enabled === FALSE)\n\t\t{\n\t\t\treturn $this->_simple_output('css', $group);\n\t\t}\n\n\t\tif ($this->auto_names or $file_name === 'auto')\n\t\t{\n\t\t\t$file_name = md5(serialize($this->css_array[$group])) . '.css';\n\t\t}\n\t\telse\n\t\t{\n\t\t\t$file_name = ($group === 'default') ? $file_name : $group . '_' . $file_name;\n\t\t}\n\n\t\t$this->_set('css_file', $file_name);\n\n\t\t$this->_scan_files('css', $force, $group);\n\n\t\tif ($this->versioning)\n\t\t{\n\t\t\t$this->_css_file = $this->_css_file . '?v=' . $this->_version_number($this->_css_file);\n\t\t}\n\n\t\treturn [$this->_css_file];\n\t}\n\n\t/**\n\t * Build and minify js\n\t *\n\t * @param bool $force     Force rewriting js file\n\t * @param null $file_name File name\n\t * @param null $group     Group name\n\t *\n\t * @return array\n\t */\n\tprivate function _deploy_js($force = FALSE, $file_name = NULL, $group = NULL)\n\t{\n\t\tif ($this->enabled === FALSE)\n\t\t{\n\t\t\treturn $this->_simple_output('js', $group);\n\t\t}\n\n\t\tif ($this->auto_names or $file_name === 'auto')\n\t\t{\n\t\t\t$file_name = md5(serialize($this->js_array[$group])) . '.js';\n\t\t}\n\t\telse\n\t\t{\n\t\t\t$file_name = ($group === 'default') ? $file_name : $group . '_' . $file_name;\n\t\t}\n\n\t\t$this->_set('js_file', $file_name);\n\n\t\t$this->_scan_files('js', $force, $group);\n\n\t\tif ($this->versioning)\n\t\t{\n\t\t\t$this->_js_file = $this->_js_file . '?v=' . $this->_version_number($this->_js_file);\n\t\t}\n\n\t\treturn [$this->_js_file];\n\t}\n\n\t/**\n\t * construct js_file and css_file\n\t *\n\t * @param string $name  File type\n\t * @param string $value File name\n\t *\n\t * @return void\n\t */\n\tprivate function _set($name, $value)\n\t{\n\t\tswitch ($name)\n\t\t{\n\t\t\tcase 'js_file':\n\n\t\t\t\tif ($this->compress)\n\t\t\t\t{\n\t\t\t\t\tif ( ! preg_match(\"/\\.min\\.js$/\", $value))\n\t\t\t\t\t{\n\t\t\t\t\t\t$value = str_replace('.js', '.min.js', $value);\n\t\t\t\t\t}\n\n\t\t\t\t\t$this->js_file = $value;\n\t\t\t\t}\n\n\t\t\t\t// determine if we have special dir for js specified\n\t\t\t\t$assets_dir     = empty($this->assets_dir_js) ? $this->assets_dir : $this->assets_dir_js;\n\t\t\t\t$this->_js_file = $assets_dir . '/' . $value;\n\n\t\t\t\tif ( ! file_exists($this->_js_file) && ! touch($this->_js_file))\n\t\t\t\t{\n\t\t\t\t\tthrow new Exception('Can not create file ' . $this->_js_file);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t$this->_lmod['js'] = filemtime($this->_js_file);\n\t\t\t\t}\n\n\t\t\tbreak;\n\t\t\tcase 'css_file':\n\n\t\t\t\tif ($this->compress)\n\t\t\t\t{\n\t\t\t\t\tif ( ! preg_match(\"/\\.min\\.css$/\", $value))\n\t\t\t\t\t{\n\t\t\t\t\t\t$value = str_replace('.css', '.min.css', $value);\n\t\t\t\t\t}\n\n\t\t\t\t\t$this->css_file = $value;\n\t\t\t\t}\n\n\t\t\t\t// determine if we have special dir for css specified\n\t\t\t\t$assets_dir      = empty($this->assets_dir_css) ? $this->assets_dir : $this->assets_dir_css;\n\t\t\t\t$this->_css_file = $assets_dir . '/' . $value;\n\n\t\t\t\tif ( ! file_exists($this->_css_file) && ! touch($this->_css_file))\n\t\t\t\t{\n\t\t\t\t\tthrow new Exception('Can not create file ' . $this->_css_file);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t$this->_lmod['css'] = filemtime($this->_css_file);\n\t\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t}\n\n\n\t/**\n\t * scan CSS directory and look for changes\n\t *\n\t * @param string $type  Type (css | js)\n\t * @param bool   $force Rewrite no mather what\n\t * @param string $group Group name\n\t */\n\tprivate function _scan_files($type, $force, $group)\n\t{\n\t\tswitch ($type)\n\t\t{\n\t\t\tcase 'css':\n\t\t\t\t$files_array = $this->css_array[$group];\n\t\t\t\t$directory   = $this->css_dir;\n\t\t\t\t$out_file    = $this->_css_file;\n\t\t\tbreak;\n\t\t\tcase 'js':\n\t\t\t\t$files_array = $this->js_array[$group];\n\t\t\t\t$directory   = $this->js_dir;\n\t\t\t\t$out_file    = $this->_js_file;\n\t\t}\n\n\t\t// if multiple files\n\t\tif (is_array($files_array))\n\t\t{\n\t\t\t$compile = FALSE;\n\t\t\tforeach ($files_array as $file)\n\t\t\t{\n\t\t\t\t$filename = $directory . '/' . $file;\n\n\t\t\t\tif (file_exists($filename))\n\t\t\t\t{\n\t\t\t\t\tif ($this->deploy_on_change && filemtime($filename) > $this->_lmod[$type])\n\t\t\t\t\t{\n\t\t\t\t\t\t$compile = TRUE;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tthrow new Exception('File ' . $filename . ' is missing');\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// check if this is init build\n\t\t\tif (file_exists($out_file) && filesize($out_file) === 0)\n\t\t\t{\n\t\t\t\t$force = TRUE;\n\t\t\t}\n\n\t\t\tif ($compile or $force)\n\t\t\t{\n\t\t\t\t$this->_concat_files($files_array, $directory, $out_file);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * output files with proper template for html_tags\n\t * or without as array\n\t *\n\t * @param array  $files Files array\n\t * @param string $type  Type (css | js)\n\t *\n\t * @return string|array\n\t */\n\tprivate function _output($files, $type)\n\t{\n\t\tswitch ($type)\n\t\t{\n\t\t\tcase 'css':\n\t\t\t\t$template = $this->css_tag;\n\t\t\tbreak;\n\t\t\tcase 'js':\n\t\t\t\t$template = $this->js_tag;\n\t\t}\n\n\t\t$output = array();\n\n\t\tforeach ($files as $file)\n\t\t{\n\t\t\t$output[] = $this->html_tags ? sprintf($template, $this->_base_url($file)) : $this->_base_url($file);\n\t\t}\n\n\t\tif ( ! empty($output))\n\t\t{\n\t\t\treturn $this->html_tags ? implode(PHP_EOL, $output) : $output;\n\t\t}\n\n\t\treturn $this->html_tags ? '' : array();\n\t}\n\n\t/**\n\t * simple output files - no compress, no compile (files in = files out)\n\t * good for debugging or development env\n\t *\n\t * @param string $type  Type (css | js)\n\t * @param string $group Group name\n\t *\n\t * @return array\n\t */\n\tprivate function _simple_output($type, $group)\n\t{\n\t\tswitch ($type)\n\t\t{\n\t\t\tcase 'css':\n\t\t\t\t$files     = $this->css_array[$group];\n\t\t\t\t$directory = $this->css_dir;\n\t\t\t\t$template  = $this->css_tag;\n\t\t\tbreak;\n\t\t\tcase 'js':\n\t\t\t\t$files     = $this->js_array[$group];\n\t\t\t\t$directory = $this->js_dir;\n\t\t\t\t$template  = $this->js_tag;\n\t\t}\n\n\t\t$output = array();\n\n\t\tforeach ($files as $file)\n\t\t{\n\t\t\t$filename = $directory . '/' . $file;\n\n\t\t\tif ($this->versioning)\n\t\t\t{\n\t\t\t\t$filename .= '?v=' . $this->_version_number($filename);\n\t\t\t}\n\n\t\t\t$output[] = $filename;\n\t\t}\n\n\t\treturn $output;\n\t}\n\n\t/**\n\t * add merge files\n\t *\n\t * @param string $file_array Input file array\n\t * @param string $directory  Directory\n\t * @param string $out_file   Output file\n\t *\n\t * @return void\n\t */\n\tprivate function _concat_files($file_array, $directory, $out_file)\n\t{\n\n\t\tif ($fh = fopen($out_file, 'w'))\n\t\t{\n\t\t\tforeach ($file_array as $file_name)\n\t\t\t{\n\t\t\t\t$file_name = $directory . '/' . $file_name;\n\t\t\t\t$contents  = file_get_contents($file_name);\n\n\t\t\t\t// if this is javascript file, check if we have ; at the end\n\t\t\t\tif (preg_match(\"/.js$/i\", $out_file))\n\t\t\t\t{\n\t\t\t\t\tif (substr(rtrim($contents), - 1) !== ';')\n\t\t\t\t\t{\n\t\t\t\t\t\t$contents .= ';';\n\t\t\t\t\t}\n\n\t\t\t\t\t$contents .= \"\\n\";\n\t\t\t\t}\n\t\t\t\tfwrite($fh, $contents);\n\t\t\t}\n\t\t\tfclose($fh);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tthrow new Exception('Can\\'t write to ' . $out_file);\n\t\t}\n\n\t\tif ($this->compress)\n\t\t{\n\t\t\t// read output file contest (already concated)\n\t\t\t$contents = file_get_contents($out_file);\n\n\t\t\t// recreate file\n\t\t\t$handle = fopen($out_file, 'w');\n\n\t\t\tif (preg_match(\"/.css$/i\", $out_file))\n\t\t\t{\n\t\t\t\t$engine = '_' . $this->compression_engine['css'];\n\t\t\t}\n\n\t\t\tif (preg_match(\"/.js$/i\", $out_file))\n\t\t\t{\n\t\t\t\t$engine = '_' . $this->compression_engine['js'];\n\t\t\t}\n\n\t\t\t// call function name to compress file\n\t\t\tfwrite($handle, call_user_func(array($this, $engine), $contents));\n\t\t\tfclose($handle);\n\t\t}\n\t}\n\n\t/**\n\t * Compress javascript using closure compiler service\n\t *\n\t * @param string $data Source to compress\n\t *\n\t * @return mixed\n\t */\n\tprivate function _closurecompiler($data)\n\t{\n\t\t$config = $this->closurecompiler;\n\n\t\t$ch = curl_init('https://closure-compiler.appspot.com/compile');\n\t\t\n\t\t//if server is not https\n\t\tif (empty($_SERVER['HTTPS']) || $_SERVER['HTTPS'] == 'off')\n\t\t{\n\t\t\tcurl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);\n\t\t}\n\t\tcurl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);\n\t\tcurl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);\n\t\tcurl_setopt($ch, CURLOPT_HEADER, 0);\n\t\tcurl_setopt($ch, CURLOPT_POST, 1);\n\t\tcurl_setopt($ch, CURLOPT_POSTFIELDS,\n\t\t            'output_info=compiled_code&output_info=errors&output_format=text&compilation_level=' . $config['compilation_level'] . '&js_code=' . urlencode($data));\n\t\t$output = curl_exec($ch);\n\t\tcurl_close($ch);\n\n\t\tif (preg_match('/Input_0:[0-9]+: ERROR/', $output))\n\t\t{\n\t\t\tthrow new Exception('Closure Compiler error: ' . $output);\n\t\t}\n\n\t\treturn $output;\n\t}\n\n\t/**\n\t * Implements jsmin as alternative to closure compiler\n\t *\n\t * @param string $data Source to compress\n\t *\n\t * @return string\n\t */\n\tprivate function _jsmin($data)\n\t{\n\t\trequire_once(APPPATH . 'libraries/minify/JSMin.php');\n\n\t\treturn JSMin::minify($data);\n\t}\n\n\t/**\n\t * Implements jsminplus as alternative to closure compiler\n\t *\n\t * @param string $data Source to compress\n\t *\n\t * @return string\n\t */\n\tprivate function _jsminplus($data)\n\t{\n\t\trequire_once(APPPATH . 'libraries/minify/JSMinPlus.php');\n\n\t\treturn JSMinPlus::minify($data);\n\t}\n\n\t/**\n\t * Implements cssmin compression engine\n\t *\n\t * @param string $data Source to compress\n\t *\n\t * @return string\n\t */\n\tprivate function _cssmin($data)\n\t{\n\t\trequire_once(APPPATH . 'libraries/minify/cssmin-v3.0.1.php');\n\n\t\treturn CssMin::minify($data);\n\t}\n\n\t/**\n\t * Implements cssminify compression engine\n\t *\n\t * @param string $data Source to compress\n\t *\n\t * @return string\n\t */\n\tprivate function _minify($data)\n\t{\n\t\trequire_once(APPPATH . 'libraries/minify/cssminify.php');\n\t\t$cssminify = new cssminify();\n\n\t\treturn $cssminify->compress($data);\n\t}\n\n\t/**\n\t * Build correct URL for file\n\t *\n\t * @param string $file File with path\n\t *\n\t * @return string\n\t */\n\tprivate function _base_url($file)\n\t{\n\t\tif ($this->base_url === '')\n\t\t{\n\t\t\treturn base_url($file);\n\t\t}\n\n\t\treturn rtrim($this->base_url, '/') . '/' . $file;\n\t}\n\n\t/**\n\t * Perform config checks\n\t *\n\t * @param $type string CSS / JS check\n\t *\n\t * @return void\n\t * @throws Exception\n\t */\n\tprivate function _config_checks($type)\n\t{\n\n\t\tswitch ($type)\n\t\t{\n\t\t\tcase 'css':\n\t\t\t\tif (empty($this->assets_dir_css) && ! is_writable($this->assets_dir))\n\t\t\t\t{\n\t\t\t\t\tthrow new Exception('Assets directory ' . $this->assets_dir . ' is not writable');\n\t\t\t\t}\n\t\t\t\tif ( ! empty($this->assets_dir_css) && ! is_writable($this->assets_dir_css))\n\t\t\t\t{\n\t\t\t\t\tthrow new Exception('Assets directory for css ' . $this->assets_dir_css . ' is not writable');\n\t\t\t\t}\n\t\t\t\tif (empty($this->css_dir))\n\t\t\t\t{\n\t\t\t\t\tthrow new Exception('CSS directory must be set');\n\t\t\t\t}\n\t\t\t\tif ($this->html_tags === TRUE && empty($this->css_tag))\n\t\t\t\t{\n\t\t\t\t\tthrow new Exception('CSS tag template must be set');\n\t\t\t\t}\n\t\t\t\tif ( ! $this->auto_names)\n\t\t\t\t{\n\t\t\t\t\tif (empty($this->css_file))\n\t\t\t\t\t{\n\t\t\t\t\t\tthrow new Exception('CSS file name can\\'t be empty');\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif ($this->compress)\n\t\t\t\t{\n\t\t\t\t\tif ( ! isset($this->compression_engine['css']) or empty($this->compression_engine['css']))\n\t\t\t\t\t{\n\t\t\t\t\t\tthrow new Exception('Compression engine for CSS is required');\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\tbreak;\n\t\t\tcase 'js':\n\t\t\t\tif (empty($this->assets_dir_js) && ! is_writable($this->assets_dir))\n\t\t\t\t{\n\t\t\t\t\tthrow new Exception('Assets directory ' . $this->assets_dir . ' is not writable');\n\t\t\t\t}\n\t\t\t\tif ( ! empty($this->assets_dir_js) && ! is_writable($this->assets_dir_js))\n\t\t\t\t{\n\t\t\t\t\tthrow new Exception('Assets directory for js ' . $this->assets_dir_js . ' is not writable');\n\t\t\t\t}\n\t\t\t\tif (empty($this->js_dir))\n\t\t\t\t{\n\t\t\t\t\tthrow new Exception('JS directory must be set');\n\t\t\t\t}\n\t\t\t\tif ($this->html_tags === TRUE && empty($this->js_tag))\n\t\t\t\t{\n\t\t\t\t\tthrow new Exception('JS tag template must be set');\n\t\t\t\t}\n\t\t\t\tif ( ! $this->auto_names)\n\t\t\t\t{\n\n\t\t\t\t\tif (empty($this->js_file))\n\t\t\t\t\t{\n\t\t\t\t\t\tthrow new Exception('JS file name can\\'t be empty');\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif ($this->compress)\n\t\t\t\t{\n\t\t\t\t\tif ( ! isset($this->compression_engine['js']) or empty($this->compression_engine['js']))\n\t\t\t\t\t{\n\t\t\t\t\t\tthrow new Exception('Compression engine for JS is required');\n\t\t\t\t\t}\n\n\t\t\t\t\tif ($this->compression_engine['js'] === 'closurecompiler' && ( ! isset($this->closurecompiler['compilation_level']) or empty($this->closurecompiler['compilation_level'])))\n\t\t\t\t\t{\n\t\t\t\t\t\tthrow new Exception('Compilation level for closurecompiler is needed');\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t}\n\n\t/**\n\t * Get Version Number for file\n\t *\n\t * @param string $file File with path\n\t *\n\t * @return string\n\t */\n\tprivate function _version_number($file)\n\t{\n\t\tif ( ! empty($this->version_number))\n\t\t{\n\t\t\treturn $this->version_number;\n\t\t}\n\n\t\treturn md5_file($file);\n\t}\n\n}\n/* End of file Minify.php */\n/* Location: ./libraries/Minify.php */\n"
  },
  {
    "path": "application/libraries/minify/JSMin.php",
    "content": "<?php\n/**\n * JSMin.php - modified PHP implementation of Douglas Crockford's JSMin.\n *\n * <code>\n * $minifiedJs = JSMin::minify($js);\n * </code>\n *\n * This is a modified port of jsmin.c. Improvements:\n *\n * Does not choke on some regexp literals containing quote characters. E.g. /'/\n *\n * Spaces are preserved after some add/sub operators, so they are not mistakenly\n * converted to post-inc/dec. E.g. a + ++b -> a+ ++b\n *\n * Preserves multi-line comments that begin with /*!\n *\n * PHP 5 or higher is required.\n *\n * Permission is hereby granted to use this version of the library under the\n * same terms as jsmin.c, which has the following license:\n *\n * --\n * Copyright (c) 2002 Douglas Crockford  (www.crockford.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy of\n * this software and associated documentation files (the \"Software\"), to deal in\n * the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies\n * of the Software, and to permit persons to whom the Software is furnished to do\n * so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * The Software shall be used for Good, not Evil.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n * --\n *\n * @package JSMin\n * @author Ryan Grove <ryan@wonko.com> (PHP port)\n * @author Steve Clay <steve@mrclay.org> (modifications + cleanup)\n * @author Andrea Giammarchi <http://www.3site.eu> (spaceBeforeRegExp)\n * @copyright 2002 Douglas Crockford <douglas@crockford.com> (jsmin.c)\n * @copyright 2008 Ryan Grove <ryan@wonko.com> (PHP port)\n * @license http://opensource.org/licenses/mit-license.php MIT License\n * @link http://code.google.com/p/jsmin-php/\n */\n\nclass JSMin {\n    const ORD_LF            = 10;\n    const ORD_SPACE         = 32;\n    const ACTION_KEEP_A     = 1;\n    const ACTION_DELETE_A   = 2;\n    const ACTION_DELETE_A_B = 3;\n\n    protected $a           = \"\\n\";\n    protected $b           = '';\n    protected $input       = '';\n    protected $inputIndex  = 0;\n    protected $inputLength = 0;\n    protected $lookAhead   = null;\n    protected $output      = '';\n    protected $lastByteOut  = '';\n    protected $keptComment = '';\n\n    /**\n     * Minify Javascript.\n     *\n     * @param string $js Javascript to be minified\n     *\n     * @return string\n     */\n    public static function minify($js)\n    {\n        $jsmin = new JSMin($js);\n        return $jsmin->min();\n    }\n\n    /**\n     * @param string $input\n     */\n    public function __construct($input)\n    {\n        $this->input = $input;\n    }\n\n    /**\n     * Perform minification, return result\n     *\n     * @return string\n     */\n    public function min()\n    {\n        if ($this->output !== '') { // min already run\n            return $this->output;\n        }\n\n        $mbIntEnc = null;\n        if (function_exists('mb_strlen') && ((int)ini_get('mbstring.func_overload') & 2)) {\n            $mbIntEnc = mb_internal_encoding();\n            mb_internal_encoding('8bit');\n        }\n        $this->input = str_replace(\"\\r\\n\", \"\\n\", $this->input);\n        $this->inputLength = strlen($this->input);\n\n        $this->action(self::ACTION_DELETE_A_B);\n\n        while ($this->a !== null) {\n            // determine next command\n            $command = self::ACTION_KEEP_A; // default\n            if ($this->a === ' ') {\n                if (($this->lastByteOut === '+' || $this->lastByteOut === '-')\n                        && ($this->b === $this->lastByteOut)) {\n                    // Don't delete this space. If we do, the addition/subtraction\n                    // could be parsed as a post-increment\n                } elseif (! $this->isAlphaNum($this->b)) {\n                    $command = self::ACTION_DELETE_A;\n                }\n            } elseif ($this->a === \"\\n\") {\n                if ($this->b === ' ') {\n                    $command = self::ACTION_DELETE_A_B;\n\n                    // in case of mbstring.func_overload & 2, must check for null b,\n                    // otherwise mb_strpos will give WARNING\n                } elseif ($this->b === null\n                          || (false === strpos('{[(+-!~', $this->b)\n                              && ! $this->isAlphaNum($this->b))) {\n                    $command = self::ACTION_DELETE_A;\n                }\n            } elseif (! $this->isAlphaNum($this->a)) {\n                if ($this->b === ' '\n                    || ($this->b === \"\\n\"\n                        && (false === strpos('}])+-\"\\'', $this->a)))) {\n                    $command = self::ACTION_DELETE_A_B;\n                }\n            }\n            $this->action($command);\n        }\n        $this->output = trim($this->output);\n\n        if ($mbIntEnc !== null) {\n            mb_internal_encoding($mbIntEnc);\n        }\n        return $this->output;\n    }\n\n    /**\n     * ACTION_KEEP_A = Output A. Copy B to A. Get the next B.\n     * ACTION_DELETE_A = Copy B to A. Get the next B.\n     * ACTION_DELETE_A_B = Get the next B.\n     *\n     * @param int $command\n     * @throws JSMin_UnterminatedRegExpException|JSMin_UnterminatedStringException\n     */\n    protected function action($command)\n    {\n        // make sure we don't compress \"a + ++b\" to \"a+++b\", etc.\n        if ($command === self::ACTION_DELETE_A_B\n            && $this->b === ' '\n            && ($this->a === '+' || $this->a === '-')) {\n            // Note: we're at an addition/substraction operator; the inputIndex\n            // will certainly be a valid index\n            if ($this->input[$this->inputIndex] === $this->a) {\n                // This is \"+ +\" or \"- -\". Don't delete the space.\n                $command = self::ACTION_KEEP_A;\n            }\n        }\n\n        switch ($command) {\n            case self::ACTION_KEEP_A: // 1\n                $this->output .= $this->a;\n\n                if ($this->keptComment) {\n                    $this->output = rtrim($this->output, \"\\n\");\n                    $this->output .= $this->keptComment;\n                    $this->keptComment = '';\n                }\n\n                $this->lastByteOut = $this->a;\n\n                // fallthrough intentional\n            case self::ACTION_DELETE_A: // 2\n                $this->a = $this->b;\n                if ($this->a === \"'\" || $this->a === '\"') { // string literal\n                    $str = $this->a; // in case needed for exception\n                    for(;;) {\n                        $this->output .= $this->a;\n                        $this->lastByteOut = $this->a;\n\n                        $this->a = $this->get();\n                        if ($this->a === $this->b) { // end quote\n                            break;\n                        }\n                        if ($this->isEOF($this->a)) {\n                            throw new JSMin_UnterminatedStringException(\n                                \"JSMin: Unterminated String at byte {$this->inputIndex}: {$str}\");\n                        }\n                        $str .= $this->a;\n                        if ($this->a === '\\\\') {\n                            $this->output .= $this->a;\n                            $this->lastByteOut = $this->a;\n\n                            $this->a       = $this->get();\n                            $str .= $this->a;\n                        }\n                    }\n                }\n\n                // fallthrough intentional\n            case self::ACTION_DELETE_A_B: // 3\n                $this->b = $this->next();\n                if ($this->b === '/' && $this->isRegexpLiteral()) {\n                    $this->output .= $this->a . $this->b;\n                    $pattern = '/'; // keep entire pattern in case we need to report it in the exception\n                    for(;;) {\n                        $this->a = $this->get();\n                        $pattern .= $this->a;\n                        if ($this->a === '[') {\n                            for(;;) {\n                                $this->output .= $this->a;\n                                $this->a = $this->get();\n                                $pattern .= $this->a;\n                                if ($this->a === ']') {\n                                    break;\n                                }\n                                if ($this->a === '\\\\') {\n                                    $this->output .= $this->a;\n                                    $this->a = $this->get();\n                                    $pattern .= $this->a;\n                                }\n                                if ($this->isEOF($this->a)) {\n                                    throw new JSMin_UnterminatedRegExpException(\n                                        \"JSMin: Unterminated set in RegExp at byte \"\n                                            . $this->inputIndex .\": {$pattern}\");\n                                }\n                            }\n                        }\n\n                        if ($this->a === '/') { // end pattern\n                            break; // while (true)\n                        } elseif ($this->a === '\\\\') {\n                            $this->output .= $this->a;\n                            $this->a = $this->get();\n                            $pattern .= $this->a;\n                        } elseif ($this->isEOF($this->a)) {\n                            throw new JSMin_UnterminatedRegExpException(\n                                \"JSMin: Unterminated RegExp at byte {$this->inputIndex}: {$pattern}\");\n                        }\n                        $this->output .= $this->a;\n                        $this->lastByteOut = $this->a;\n                    }\n                    $this->b = $this->next();\n                }\n            // end case ACTION_DELETE_A_B\n        }\n    }\n\n    /**\n     * @return bool\n     */\n    protected function isRegexpLiteral()\n    {\n        if (false !== strpos(\"(,=:[!&|?+-~*{;\", $this->a)) {\n            // we obviously aren't dividing\n            return true;\n        }\n        if ($this->a === ' ' || $this->a === \"\\n\") {\n            $length = strlen($this->output);\n            if ($length < 2) { // weird edge case\n                return true;\n            }\n            // you can't divide a keyword\n            if (preg_match('/(?:case|else|in|return|typeof)$/', $this->output, $m)) {\n                if ($this->output === $m[0]) { // odd but could happen\n                    return true;\n                }\n                // make sure it's a keyword, not end of an identifier\n                $charBeforeKeyword = substr($this->output, $length - strlen($m[0]) - 1, 1);\n                if (! $this->isAlphaNum($charBeforeKeyword)) {\n                    return true;\n                }\n            }\n        }\n        return false;\n    }\n\n    /**\n     * Return the next character from stdin. Watch out for lookahead. If the character is a control character,\n     * translate it to a space or linefeed.\n     *\n     * @return string\n     */\n    protected function get()\n    {\n        $c = $this->lookAhead;\n        $this->lookAhead = null;\n        if ($c === null) {\n            // getc(stdin)\n            if ($this->inputIndex < $this->inputLength) {\n                $c = $this->input[$this->inputIndex];\n                $this->inputIndex += 1;\n            } else {\n                $c = null;\n            }\n        }\n        if (ord($c) >= self::ORD_SPACE || $c === \"\\n\" || $c === null) {\n            return $c;\n        }\n        if ($c === \"\\r\") {\n            return \"\\n\";\n        }\n        return ' ';\n    }\n\n    /**\n     * Does $a indicate end of input?\n     *\n     * @param string $a\n     * @return bool\n     */\n    protected function isEOF($a)\n    {\n        return ord($a) <= self::ORD_LF;\n    }\n\n    /**\n     * Get next char (without getting it). If is ctrl character, translate to a space or newline.\n     *\n     * @return string\n     */\n    protected function peek()\n    {\n        $this->lookAhead = $this->get();\n        return $this->lookAhead;\n    }\n\n    /**\n     * Return true if the character is a letter, digit, underscore, dollar sign, or non-ASCII character.\n     *\n     * @param string $c\n     *\n     * @return bool\n     */\n    protected function isAlphaNum($c)\n    {\n        return (preg_match('/^[a-z0-9A-Z_\\\\$\\\\\\\\]$/', $c) || ord($c) > 126);\n    }\n\n    /**\n     * Consume a single line comment from input (possibly retaining it)\n     */\n    protected function consumeSingleLineComment()\n    {\n        $comment = '';\n        while (true) {\n            $get = $this->get();\n            $comment .= $get;\n            if (ord($get) <= self::ORD_LF) { // end of line reached\n                // if IE conditional comment\n                if (preg_match('/^\\\\/@(?:cc_on|if|elif|else|end)\\\\b/', $comment)) {\n                    $this->keptComment .= \"/{$comment}\";\n                }\n                return;\n            }\n        }\n    }\n\n    /**\n     * Consume a multiple line comment from input (possibly retaining it)\n     *\n     * @throws JSMin_UnterminatedCommentException\n     */\n    protected function consumeMultipleLineComment()\n    {\n        $this->get();\n        $comment = '';\n        for(;;) {\n            $get = $this->get();\n            if ($get === '*') {\n                if ($this->peek() === '/') { // end of comment reached\n                    $this->get();\n                    if (0 === strpos($comment, '!')) {\n                        // preserved by YUI Compressor\n                        if (!$this->keptComment) {\n                            // don't prepend a newline if two comments right after one another\n                            $this->keptComment = \"\\n\";\n                        }\n                        $this->keptComment .= \"/*!\" . substr($comment, 1) . \"*/\\n\";\n                    } else if (preg_match('/^@(?:cc_on|if|elif|else|end)\\\\b/', $comment)) {\n                        // IE conditional\n                        $this->keptComment .= \"/*{$comment}*/\";\n                    }\n                    return;\n                }\n            } elseif ($get === null) {\n                throw new JSMin_UnterminatedCommentException(\n                    \"JSMin: Unterminated comment at byte {$this->inputIndex}: /*{$comment}\");\n            }\n            $comment .= $get;\n        }\n    }\n\n    /**\n     * Get the next character, skipping over comments. Some comments may be preserved.\n     *\n     * @return string\n     */\n    protected function next()\n    {\n        $get = $this->get();\n        if ($get === '/') {\n            switch ($this->peek()) {\n                case '/':\n                    $this->consumeSingleLineComment();\n                    $get = \"\\n\";\n                    break;\n                case '*':\n                    $this->consumeMultipleLineComment();\n                    $get = ' ';\n                    break;\n            }\n        }\n        return $get;\n    }\n}\n\nclass JSMin_UnterminatedStringException extends Exception {}\nclass JSMin_UnterminatedCommentException extends Exception {}\nclass JSMin_UnterminatedRegExpException extends Exception {}\n"
  },
  {
    "path": "application/libraries/minify/JSMinPlus.php",
    "content": "<?php\n\n/**\n * JSMinPlus version 1.4\n *\n * Minifies a javascript file using a javascript parser\n *\n * This implements a PHP port of Brendan Eich's Narcissus open source javascript engine (in javascript)\n * References: http://en.wikipedia.org/wiki/Narcissus_(JavaScript_engine)\n * Narcissus sourcecode: http://mxr.mozilla.org/mozilla/source/js/narcissus/\n * JSMinPlus weblog: http://crisp.tweakblogs.net/blog/cat/716\n *\n * Tino Zijdel <crisp@tweakers.net>\n *\n * Usage: $minified = JSMinPlus::minify($script [, $filename])\n *\n * Versionlog (see also changelog.txt):\n * 23-07-2011 - remove dynamic creation of OP_* and KEYWORD_* defines and declare them on top\n *              reduce memory footprint by minifying by block-scope\n *              some small byte-saving and performance improvements\n * 12-05-2009 - fixed hook:colon precedence, fixed empty body in loop and if-constructs\n * 18-04-2009 - fixed crashbug in PHP 5.2.9 and several other bugfixes\n * 12-04-2009 - some small bugfixes and performance improvements\n * 09-04-2009 - initial open sourced version 1.0\n *\n * Latest version of this script: http://files.tweakers.net/jsminplus/jsminplus.zip\n *\n */\n\n/* ***** BEGIN LICENSE BLOCK *****\n * Version: MPL 1.1/GPL 2.0/LGPL 2.1\n *\n * The contents of this file are subject to the Mozilla Public License Version\n * 1.1 (the \"License\"); you may not use this file except in compliance with\n * the License. You may obtain a copy of the License at\n * http://www.mozilla.org/MPL/\n *\n * Software distributed under the License is distributed on an \"AS IS\" basis,\n * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\n * for the specific language governing rights and limitations under the\n * License.\n *\n * The Original Code is the Narcissus JavaScript engine.\n *\n * The Initial Developer of the Original Code is\n * Brendan Eich <brendan@mozilla.org>.\n * Portions created by the Initial Developer are Copyright (C) 2004\n * the Initial Developer. All Rights Reserved.\n *\n * Contributor(s): Tino Zijdel <crisp@tweakers.net>\n * PHP port, modifications and minifier routine are (C) 2009-2011\n *\n * Alternatively, the contents of this file may be used under the terms of\n * either the GNU General Public License Version 2 or later (the \"GPL\"), or\n * the GNU Lesser General Public License Version 2.1 or later (the \"LGPL\"),\n * in which case the provisions of the GPL or the LGPL are applicable instead\n * of those above. If you wish to allow use of your version of this file only\n * under the terms of either the GPL or the LGPL, and not to allow others to\n * use your version of this file under the terms of the MPL, indicate your\n * decision by deleting the provisions above and replace them with the notice\n * and other provisions required by the GPL or the LGPL. If you do not delete\n * the provisions above, a recipient may use your version of this file under\n * the terms of any one of the MPL, the GPL or the LGPL.\n *\n * ***** END LICENSE BLOCK ***** */\n\ndefine('TOKEN_END', 1);\ndefine('TOKEN_NUMBER', 2);\ndefine('TOKEN_IDENTIFIER', 3);\ndefine('TOKEN_STRING', 4);\ndefine('TOKEN_REGEXP', 5);\ndefine('TOKEN_NEWLINE', 6);\ndefine('TOKEN_CONDCOMMENT_START', 7);\ndefine('TOKEN_CONDCOMMENT_END', 8);\n\ndefine('JS_SCRIPT', 100);\ndefine('JS_BLOCK', 101);\ndefine('JS_LABEL', 102);\ndefine('JS_FOR_IN', 103);\ndefine('JS_CALL', 104);\ndefine('JS_NEW_WITH_ARGS', 105);\ndefine('JS_INDEX', 106);\ndefine('JS_ARRAY_INIT', 107);\ndefine('JS_OBJECT_INIT', 108);\ndefine('JS_PROPERTY_INIT', 109);\ndefine('JS_GETTER', 110);\ndefine('JS_SETTER', 111);\ndefine('JS_GROUP', 112);\ndefine('JS_LIST', 113);\n\ndefine('JS_MINIFIED', 999);\n\ndefine('DECLARED_FORM', 0);\ndefine('EXPRESSED_FORM', 1);\ndefine('STATEMENT_FORM', 2);\n\n/* Operators */\ndefine('OP_SEMICOLON', ';');\ndefine('OP_COMMA', ',');\ndefine('OP_HOOK', '?');\ndefine('OP_COLON', ':');\ndefine('OP_OR', '||');\ndefine('OP_AND', '&&');\ndefine('OP_BITWISE_OR', '|');\ndefine('OP_BITWISE_XOR', '^');\ndefine('OP_BITWISE_AND', '&');\ndefine('OP_STRICT_EQ', '===');\ndefine('OP_EQ', '==');\ndefine('OP_ASSIGN', '=');\ndefine('OP_STRICT_NE', '!==');\ndefine('OP_NE', '!=');\ndefine('OP_LSH', '<<');\ndefine('OP_LE', '<=');\ndefine('OP_LT', '<');\ndefine('OP_URSH', '>>>');\ndefine('OP_RSH', '>>');\ndefine('OP_GE', '>=');\ndefine('OP_GT', '>');\ndefine('OP_INCREMENT', '++');\ndefine('OP_DECREMENT', '--');\ndefine('OP_PLUS', '+');\ndefine('OP_MINUS', '-');\ndefine('OP_MUL', '*');\ndefine('OP_DIV', '/');\ndefine('OP_MOD', '%');\ndefine('OP_NOT', '!');\ndefine('OP_BITWISE_NOT', '~');\ndefine('OP_DOT', '.');\ndefine('OP_LEFT_BRACKET', '[');\ndefine('OP_RIGHT_BRACKET', ']');\ndefine('OP_LEFT_CURLY', '{');\ndefine('OP_RIGHT_CURLY', '}');\ndefine('OP_LEFT_PAREN', '(');\ndefine('OP_RIGHT_PAREN', ')');\ndefine('OP_CONDCOMMENT_END', '@*/');\n\ndefine('OP_UNARY_PLUS', 'U+');\ndefine('OP_UNARY_MINUS', 'U-');\n\n/* Keywords */\ndefine('KEYWORD_BREAK', 'break');\ndefine('KEYWORD_CASE', 'case');\ndefine('KEYWORD_CATCH', 'catch');\ndefine('KEYWORD_CONST', 'const');\ndefine('KEYWORD_CONTINUE', 'continue');\ndefine('KEYWORD_DEBUGGER', 'debugger');\ndefine('KEYWORD_DEFAULT', 'default');\ndefine('KEYWORD_DELETE', 'delete');\ndefine('KEYWORD_DO', 'do');\ndefine('KEYWORD_ELSE', 'else');\ndefine('KEYWORD_ENUM', 'enum');\ndefine('KEYWORD_FALSE', 'false');\ndefine('KEYWORD_FINALLY', 'finally');\ndefine('KEYWORD_FOR', 'for');\ndefine('KEYWORD_FUNCTION', 'function');\ndefine('KEYWORD_IF', 'if');\ndefine('KEYWORD_IN', 'in');\ndefine('KEYWORD_INSTANCEOF', 'instanceof');\ndefine('KEYWORD_NEW', 'new');\ndefine('KEYWORD_NULL', 'null');\ndefine('KEYWORD_RETURN', 'return');\ndefine('KEYWORD_SWITCH', 'switch');\ndefine('KEYWORD_THIS', 'this');\ndefine('KEYWORD_THROW', 'throw');\ndefine('KEYWORD_TRUE', 'true');\ndefine('KEYWORD_TRY', 'try');\ndefine('KEYWORD_TYPEOF', 'typeof');\ndefine('KEYWORD_VAR', 'var');\ndefine('KEYWORD_VOID', 'void');\ndefine('KEYWORD_WHILE', 'while');\ndefine('KEYWORD_WITH', 'with');\n\n\nclass JSMinPlus\n{\n\tprivate $parser;\n\tprivate $reserved = array(\n\t\t'break', 'case', 'catch', 'continue', 'default', 'delete', 'do',\n\t\t'else', 'finally', 'for', 'function', 'if', 'in', 'instanceof',\n\t\t'new', 'return', 'switch', 'this', 'throw', 'try', 'typeof', 'var',\n\t\t'void', 'while', 'with',\n\t\t// Words reserved for future use\n\t\t'abstract', 'boolean', 'byte', 'char', 'class', 'const', 'debugger',\n\t\t'double', 'enum', 'export', 'extends', 'final', 'float', 'goto',\n\t\t'implements', 'import', 'int', 'interface', 'long', 'native',\n\t\t'package', 'private', 'protected', 'public', 'short', 'static',\n\t\t'super', 'synchronized', 'throws', 'transient', 'volatile',\n\t\t// These are not reserved, but should be taken into account\n\t\t// in isValidIdentifier (See jslint source code)\n\t\t'arguments', 'eval', 'true', 'false', 'Infinity', 'NaN', 'null', 'undefined'\n\t);\n\n\tprivate function __construct()\n\t{\n\t\t$this->parser = new JSParser($this);\n\t}\n\n\tpublic static function minify($js, $filename='')\n\t{\n\t\tstatic $instance;\n\n\t\t// this is a singleton\n\t\tif(!$instance)\n\t\t\t$instance = new JSMinPlus();\n\n\t\treturn $instance->min($js, $filename);\n\t}\n\n\tprivate function min($js, $filename)\n\t{\n\t\ttry\n\t\t{\n\t\t\t$n = $this->parser->parse($js, $filename, 1);\n\t\t\treturn $this->parseTree($n);\n\t\t}\n\t\tcatch(Exception $e)\n\t\t{\n\t\t\techo $e->getMessage() . \"\\n\";\n\t\t}\n\n\t\treturn false;\n\t}\n\n\tpublic function parseTree($n, $noBlockGrouping = false)\n\t{\n\t\t$s = '';\n\n\t\tswitch ($n->type)\n\t\t{\n\t\t\tcase JS_MINIFIED:\n\t\t\t\t$s = $n->value;\n\t\t\tbreak;\n\n\t\t\tcase JS_SCRIPT:\n\t\t\t\t// we do nothing yet with funDecls or varDecls\n\t\t\t\t$noBlockGrouping = true;\n\t\t\t// FALL THROUGH\n\n\t\t\tcase JS_BLOCK:\n\t\t\t\t$childs = $n->treeNodes;\n\t\t\t\t$lastType = 0;\n\t\t\t\tfor ($c = 0, $i = 0, $j = count($childs); $i < $j; $i++)\n\t\t\t\t{\n\t\t\t\t\t$type = $childs[$i]->type;\n\t\t\t\t\t$t = $this->parseTree($childs[$i]);\n\t\t\t\t\tif (strlen($t))\n\t\t\t\t\t{\n\t\t\t\t\t\tif ($c)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$s = rtrim($s, ';');\n\n\t\t\t\t\t\t\tif ($type == KEYWORD_FUNCTION && $childs[$i]->functionForm == DECLARED_FORM)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// put declared functions on a new line\n\t\t\t\t\t\t\t\t$s .= \"\\n\";\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telseif ($type == KEYWORD_VAR && $type == $lastType)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// mutiple var-statements can go into one\n\t\t\t\t\t\t\t\t$t = ',' . substr($t, 4);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// add terminator\n\t\t\t\t\t\t\t\t$s .= ';';\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t$s .= $t;\n\n\t\t\t\t\t\t$c++;\n\t\t\t\t\t\t$lastType = $type;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif ($c > 1 && !$noBlockGrouping)\n\t\t\t\t{\n\t\t\t\t\t$s = '{' . $s . '}';\n\t\t\t\t}\n\t\t\tbreak;\n\n\t\t\tcase KEYWORD_FUNCTION:\n\t\t\t\t$s .= 'function' . ($n->name ? ' ' . $n->name : '') . '(';\n\t\t\t\t$params = $n->params;\n\t\t\t\tfor ($i = 0, $j = count($params); $i < $j; $i++)\n\t\t\t\t\t$s .= ($i ? ',' : '') . $params[$i];\n\t\t\t\t$s .= '){' . $this->parseTree($n->body, true) . '}';\n\t\t\tbreak;\n\n\t\t\tcase KEYWORD_IF:\n\t\t\t\t$s = 'if(' . $this->parseTree($n->condition) . ')';\n\t\t\t\t$thenPart = $this->parseTree($n->thenPart);\n\t\t\t\t$elsePart = $n->elsePart ? $this->parseTree($n->elsePart) : null;\n\n\t\t\t\t// empty if-statement\n\t\t\t\tif ($thenPart == '')\n\t\t\t\t\t$thenPart = ';';\n\n\t\t\t\tif ($elsePart)\n\t\t\t\t{\n\t\t\t\t\t// be carefull and always make a block out of the thenPart; could be more optimized but is a lot of trouble\n\t\t\t\t\tif ($thenPart != ';' && $thenPart[0] != '{')\n\t\t\t\t\t\t$thenPart = '{' . $thenPart . '}';\n\n\t\t\t\t\t$s .= $thenPart . 'else';\n\n\t\t\t\t\t// we could check for more, but that hardly ever applies so go for performance\n\t\t\t\t\tif ($elsePart[0] != '{')\n\t\t\t\t\t\t$s .= ' ';\n\n\t\t\t\t\t$s .= $elsePart;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t$s .= $thenPart;\n\t\t\t\t}\n\t\t\tbreak;\n\n\t\t\tcase KEYWORD_SWITCH:\n\t\t\t\t$s = 'switch(' . $this->parseTree($n->discriminant) . '){';\n\t\t\t\t$cases = $n->cases;\n\t\t\t\tfor ($i = 0, $j = count($cases); $i < $j; $i++)\n\t\t\t\t{\n\t\t\t\t\t$case = $cases[$i];\n\t\t\t\t\tif ($case->type == KEYWORD_CASE)\n\t\t\t\t\t\t$s .= 'case' . ($case->caseLabel->type != TOKEN_STRING ? ' ' : '') . $this->parseTree($case->caseLabel) . ':';\n\t\t\t\t\telse\n\t\t\t\t\t\t$s .= 'default:';\n\n\t\t\t\t\t$statement = $this->parseTree($case->statements, true);\n\t\t\t\t\tif ($statement)\n\t\t\t\t\t{\n\t\t\t\t\t\t$s .= $statement;\n\t\t\t\t\t\t// no terminator for last statement\n\t\t\t\t\t\tif ($i + 1 < $j)\n\t\t\t\t\t\t\t$s .= ';';\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t$s .= '}';\n\t\t\tbreak;\n\n\t\t\tcase KEYWORD_FOR:\n\t\t\t\t$s = 'for(' . ($n->setup ? $this->parseTree($n->setup) : '')\n\t\t\t\t\t. ';' . ($n->condition ? $this->parseTree($n->condition) : '')\n\t\t\t\t\t. ';' . ($n->update ? $this->parseTree($n->update) : '') . ')';\n\n\t\t\t\t$body  = $this->parseTree($n->body);\n\t\t\t\tif ($body == '')\n\t\t\t\t\t$body = ';';\n\n\t\t\t\t$s .= $body;\n\t\t\tbreak;\n\n\t\t\tcase KEYWORD_WHILE:\n\t\t\t\t$s = 'while(' . $this->parseTree($n->condition) . ')';\n\n\t\t\t\t$body  = $this->parseTree($n->body);\n\t\t\t\tif ($body == '')\n\t\t\t\t\t$body = ';';\n\n\t\t\t\t$s .= $body;\n\t\t\tbreak;\n\n\t\t\tcase JS_FOR_IN:\n\t\t\t\t$s = 'for(' . ($n->varDecl ? $this->parseTree($n->varDecl) : $this->parseTree($n->iterator)) . ' in ' . $this->parseTree($n->object) . ')';\n\n\t\t\t\t$body  = $this->parseTree($n->body);\n\t\t\t\tif ($body == '')\n\t\t\t\t\t$body = ';';\n\n\t\t\t\t$s .= $body;\n\t\t\tbreak;\n\n\t\t\tcase KEYWORD_DO:\n\t\t\t\t$s = 'do{' . $this->parseTree($n->body, true) . '}while(' . $this->parseTree($n->condition) . ')';\n\t\t\tbreak;\n\n\t\t\tcase KEYWORD_BREAK:\n\t\t\tcase KEYWORD_CONTINUE:\n\t\t\t\t$s = $n->value . ($n->label ? ' ' . $n->label : '');\n\t\t\tbreak;\n\n\t\t\tcase KEYWORD_TRY:\n\t\t\t\t$s = 'try{' . $this->parseTree($n->tryBlock, true) . '}';\n\t\t\t\t$catchClauses = $n->catchClauses;\n\t\t\t\tfor ($i = 0, $j = count($catchClauses); $i < $j; $i++)\n\t\t\t\t{\n\t\t\t\t\t$t = $catchClauses[$i];\n\t\t\t\t\t$s .= 'catch(' . $t->varName . ($t->guard ? ' if ' . $this->parseTree($t->guard) : '') . '){' . $this->parseTree($t->block, true) . '}';\n\t\t\t\t}\n\t\t\t\tif ($n->finallyBlock)\n\t\t\t\t\t$s .= 'finally{' . $this->parseTree($n->finallyBlock, true) . '}';\n\t\t\tbreak;\n\n\t\t\tcase KEYWORD_THROW:\n\t\t\tcase KEYWORD_RETURN:\n\t\t\t\t$s = $n->type;\n\t\t\t\tif ($n->value)\n\t\t\t\t{\n\t\t\t\t\t$t = $this->parseTree($n->value);\n\t\t\t\t\tif (strlen($t))\n\t\t\t\t\t{\n\t\t\t\t\t\tif ($this->isWordChar($t[0]) || $t[0] == '\\\\')\n\t\t\t\t\t\t\t$s .= ' ';\n\n\t\t\t\t\t\t$s .= $t;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\tbreak;\n\n\t\t\tcase KEYWORD_WITH:\n\t\t\t\t$s = 'with(' . $this->parseTree($n->object) . ')' . $this->parseTree($n->body);\n\t\t\tbreak;\n\n\t\t\tcase KEYWORD_VAR:\n\t\t\tcase KEYWORD_CONST:\n\t\t\t\t$s = $n->value . ' ';\n\t\t\t\t$childs = $n->treeNodes;\n\t\t\t\tfor ($i = 0, $j = count($childs); $i < $j; $i++)\n\t\t\t\t{\n\t\t\t\t\t$t = $childs[$i];\n\t\t\t\t\t$s .= ($i ? ',' : '') . $t->name;\n\t\t\t\t\t$u = $t->initializer;\n\t\t\t\t\tif ($u)\n\t\t\t\t\t\t$s .= '=' . $this->parseTree($u);\n\t\t\t\t}\n\t\t\tbreak;\n\n\t\t\tcase KEYWORD_IN:\n\t\t\tcase KEYWORD_INSTANCEOF:\n\t\t\t\t$left = $this->parseTree($n->treeNodes[0]);\n\t\t\t\t$right = $this->parseTree($n->treeNodes[1]);\n\n\t\t\t\t$s = $left;\n\n\t\t\t\tif ($this->isWordChar(substr($left, -1)))\n\t\t\t\t\t$s .= ' ';\n\n\t\t\t\t$s .= $n->type;\n\n\t\t\t\tif ($this->isWordChar($right[0]) || $right[0] == '\\\\')\n\t\t\t\t\t$s .= ' ';\n\n\t\t\t\t$s .= $right;\n\t\t\tbreak;\n\n\t\t\tcase KEYWORD_DELETE:\n\t\t\tcase KEYWORD_TYPEOF:\n\t\t\t\t$right = $this->parseTree($n->treeNodes[0]);\n\n\t\t\t\t$s = $n->type;\n\n\t\t\t\tif ($this->isWordChar($right[0]) || $right[0] == '\\\\')\n\t\t\t\t\t$s .= ' ';\n\n\t\t\t\t$s .= $right;\n\t\t\tbreak;\n\n\t\t\tcase KEYWORD_VOID:\n\t\t\t\t$s = 'void(' . $this->parseTree($n->treeNodes[0]) . ')';\n\t\t\tbreak;\n\n\t\t\tcase KEYWORD_DEBUGGER:\n\t\t\t\tthrow new Exception('NOT IMPLEMENTED: DEBUGGER');\n\t\t\tbreak;\n\n\t\t\tcase TOKEN_CONDCOMMENT_START:\n\t\t\tcase TOKEN_CONDCOMMENT_END:\n\t\t\t\t$s = $n->value . ($n->type == TOKEN_CONDCOMMENT_START ? ' ' : '');\n\t\t\t\t$childs = $n->treeNodes;\n\t\t\t\tfor ($i = 0, $j = count($childs); $i < $j; $i++)\n\t\t\t\t\t$s .= $this->parseTree($childs[$i]);\n\t\t\tbreak;\n\n\t\t\tcase OP_SEMICOLON:\n\t\t\t\tif ($expression = $n->expression)\n\t\t\t\t\t$s = $this->parseTree($expression);\n\t\t\tbreak;\n\n\t\t\tcase JS_LABEL:\n\t\t\t\t$s = $n->label . ':' . $this->parseTree($n->statement);\n\t\t\tbreak;\n\n\t\t\tcase OP_COMMA:\n\t\t\t\t$childs = $n->treeNodes;\n\t\t\t\tfor ($i = 0, $j = count($childs); $i < $j; $i++)\n\t\t\t\t\t$s .= ($i ? ',' : '') . $this->parseTree($childs[$i]);\n\t\t\tbreak;\n\n\t\t\tcase OP_ASSIGN:\n\t\t\t\t$s = $this->parseTree($n->treeNodes[0]) . $n->value . $this->parseTree($n->treeNodes[1]);\n\t\t\tbreak;\n\n\t\t\tcase OP_HOOK:\n\t\t\t\t$s = $this->parseTree($n->treeNodes[0]) . '?' . $this->parseTree($n->treeNodes[1]) . ':' . $this->parseTree($n->treeNodes[2]);\n\t\t\tbreak;\n\n\t\t\tcase OP_OR: case OP_AND:\n\t\t\tcase OP_BITWISE_OR: case OP_BITWISE_XOR: case OP_BITWISE_AND:\n\t\t\tcase OP_EQ: case OP_NE: case OP_STRICT_EQ: case OP_STRICT_NE:\n\t\t\tcase OP_LT: case OP_LE: case OP_GE: case OP_GT:\n\t\t\tcase OP_LSH: case OP_RSH: case OP_URSH:\n\t\t\tcase OP_MUL: case OP_DIV: case OP_MOD:\n\t\t\t\t$s = $this->parseTree($n->treeNodes[0]) . $n->type . $this->parseTree($n->treeNodes[1]);\n\t\t\tbreak;\n\n\t\t\tcase OP_PLUS:\n\t\t\tcase OP_MINUS:\n\t\t\t\t$left = $this->parseTree($n->treeNodes[0]);\n\t\t\t\t$right = $this->parseTree($n->treeNodes[1]);\n\n\t\t\t\tswitch ($n->treeNodes[1]->type)\n\t\t\t\t{\n\t\t\t\t\tcase OP_PLUS:\n\t\t\t\t\tcase OP_MINUS:\n\t\t\t\t\tcase OP_INCREMENT:\n\t\t\t\t\tcase OP_DECREMENT:\n\t\t\t\t\tcase OP_UNARY_PLUS:\n\t\t\t\t\tcase OP_UNARY_MINUS:\n\t\t\t\t\t\t$s = $left . $n->type . ' ' . $right;\n\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase TOKEN_STRING:\n\t\t\t\t\t\t//combine concatted strings with same quotestyle\n\t\t\t\t\t\tif ($n->type == OP_PLUS && substr($left, -1) == $right[0])\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$s = substr($left, 0, -1) . substr($right, 1);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t// FALL THROUGH\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\t$s = $left . $n->type . $right;\n\t\t\t\t}\n\t\t\tbreak;\n\n\t\t\tcase OP_NOT:\n\t\t\tcase OP_BITWISE_NOT:\n\t\t\tcase OP_UNARY_PLUS:\n\t\t\tcase OP_UNARY_MINUS:\n\t\t\t\t$s = $n->value . $this->parseTree($n->treeNodes[0]);\n\t\t\tbreak;\n\n\t\t\tcase OP_INCREMENT:\n\t\t\tcase OP_DECREMENT:\n\t\t\t\tif ($n->postfix)\n\t\t\t\t\t$s = $this->parseTree($n->treeNodes[0]) . $n->value;\n\t\t\t\telse\n\t\t\t\t\t$s = $n->value . $this->parseTree($n->treeNodes[0]);\n\t\t\tbreak;\n\n\t\t\tcase OP_DOT:\n\t\t\t\t$s = $this->parseTree($n->treeNodes[0]) . '.' . $this->parseTree($n->treeNodes[1]);\n\t\t\tbreak;\n\n\t\t\tcase JS_INDEX:\n\t\t\t\t$s = $this->parseTree($n->treeNodes[0]);\n\t\t\t\t// See if we can replace named index with a dot saving 3 bytes\n\t\t\t\tif (\t$n->treeNodes[0]->type == TOKEN_IDENTIFIER &&\n\t\t\t\t\t$n->treeNodes[1]->type == TOKEN_STRING &&\n\t\t\t\t\t$this->isValidIdentifier(substr($n->treeNodes[1]->value, 1, -1))\n\t\t\t\t)\n\t\t\t\t\t$s .= '.' . substr($n->treeNodes[1]->value, 1, -1);\n\t\t\t\telse\n\t\t\t\t\t$s .= '[' . $this->parseTree($n->treeNodes[1]) . ']';\n\t\t\tbreak;\n\n\t\t\tcase JS_LIST:\n\t\t\t\t$childs = $n->treeNodes;\n\t\t\t\tfor ($i = 0, $j = count($childs); $i < $j; $i++)\n\t\t\t\t\t$s .= ($i ? ',' : '') . $this->parseTree($childs[$i]);\n\t\t\tbreak;\n\n\t\t\tcase JS_CALL:\n\t\t\t\t$s = $this->parseTree($n->treeNodes[0]) . '(' . $this->parseTree($n->treeNodes[1]) . ')';\n\t\t\tbreak;\n\n\t\t\tcase KEYWORD_NEW:\n\t\t\tcase JS_NEW_WITH_ARGS:\n\t\t\t\t$s = 'new ' . $this->parseTree($n->treeNodes[0]) . '(' . ($n->type == JS_NEW_WITH_ARGS ? $this->parseTree($n->treeNodes[1]) : '') . ')';\n\t\t\tbreak;\n\n\t\t\tcase JS_ARRAY_INIT:\n\t\t\t\t$s = '[';\n\t\t\t\t$childs = $n->treeNodes;\n\t\t\t\tfor ($i = 0, $j = count($childs); $i < $j; $i++)\n\t\t\t\t{\n\t\t\t\t\t$s .= ($i ? ',' : '') . $this->parseTree($childs[$i]);\n\t\t\t\t}\n\t\t\t\t$s .= ']';\n\t\t\tbreak;\n\n\t\t\tcase JS_OBJECT_INIT:\n\t\t\t\t$s = '{';\n\t\t\t\t$childs = $n->treeNodes;\n\t\t\t\tfor ($i = 0, $j = count($childs); $i < $j; $i++)\n\t\t\t\t{\n\t\t\t\t\t$t = $childs[$i];\n\t\t\t\t\tif ($i)\n\t\t\t\t\t\t$s .= ',';\n\t\t\t\t\tif ($t->type == JS_PROPERTY_INIT)\n\t\t\t\t\t{\n\t\t\t\t\t\t// Ditch the quotes when the index is a valid identifier\n\t\t\t\t\t\tif (\t$t->treeNodes[0]->type == TOKEN_STRING &&\n\t\t\t\t\t\t\t$this->isValidIdentifier(substr($t->treeNodes[0]->value, 1, -1))\n\t\t\t\t\t\t)\n\t\t\t\t\t\t\t$s .= substr($t->treeNodes[0]->value, 1, -1);\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\t$s .= $t->treeNodes[0]->value;\n\n\t\t\t\t\t\t$s .= ':' . $this->parseTree($t->treeNodes[1]);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t$s .= $t->type == JS_GETTER ? 'get' : 'set';\n\t\t\t\t\t\t$s .= ' ' . $t->name . '(';\n\t\t\t\t\t\t$params = $t->params;\n\t\t\t\t\t\tfor ($i = 0, $j = count($params); $i < $j; $i++)\n\t\t\t\t\t\t\t$s .= ($i ? ',' : '') . $params[$i];\n\t\t\t\t\t\t$s .= '){' . $this->parseTree($t->body, true) . '}';\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t$s .= '}';\n\t\t\tbreak;\n\n\t\t\tcase TOKEN_NUMBER:\n\t\t\t\t$s = $n->value;\n\t\t\t\tif (preg_match('/^([1-9]+)(0{3,})$/', $s, $m))\n\t\t\t\t\t$s = $m[1] . 'e' . strlen($m[2]);\n\t\t\tbreak;\n\n\t\t\tcase KEYWORD_NULL: case KEYWORD_THIS: case KEYWORD_TRUE: case KEYWORD_FALSE:\n\t\t\tcase TOKEN_IDENTIFIER: case TOKEN_STRING: case TOKEN_REGEXP:\n\t\t\t\t$s = $n->value;\n\t\t\tbreak;\n\n\t\t\tcase JS_GROUP:\n\t\t\t\tif (in_array(\n\t\t\t\t\t$n->treeNodes[0]->type,\n\t\t\t\t\tarray(\n\t\t\t\t\t\tJS_ARRAY_INIT, JS_OBJECT_INIT, JS_GROUP,\n\t\t\t\t\t\tTOKEN_NUMBER, TOKEN_STRING, TOKEN_REGEXP, TOKEN_IDENTIFIER,\n\t\t\t\t\t\tKEYWORD_NULL, KEYWORD_THIS, KEYWORD_TRUE, KEYWORD_FALSE\n\t\t\t\t\t)\n\t\t\t\t))\n\t\t\t\t{\n\t\t\t\t\t$s = $this->parseTree($n->treeNodes[0]);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t$s = '(' . $this->parseTree($n->treeNodes[0]) . ')';\n\t\t\t\t}\n\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\tthrow new Exception('UNKNOWN TOKEN TYPE: ' . $n->type);\n\t\t}\n\n\t\treturn $s;\n\t}\n\n\tprivate function isValidIdentifier($string)\n\t{\n\t\treturn preg_match('/^[a-zA-Z_][a-zA-Z0-9_]*$/', $string) && !in_array($string, $this->reserved);\n\t}\n\n\tprivate function isWordChar($char)\n\t{\n\t\treturn $char == '_' || $char == '$' || ctype_alnum($char);\n\t}\n}\n\nclass JSParser\n{\n\tprivate $t;\n\tprivate $minifier;\n\n\tprivate $opPrecedence = array(\n\t\t';' => 0,\n\t\t',' => 1,\n\t\t'=' => 2, '?' => 2, ':' => 2,\n\t\t// The above all have to have the same precedence, see bug 330975\n\t\t'||' => 4,\n\t\t'&&' => 5,\n\t\t'|' => 6,\n\t\t'^' => 7,\n\t\t'&' => 8,\n\t\t'==' => 9, '!=' => 9, '===' => 9, '!==' => 9,\n\t\t'<' => 10, '<=' => 10, '>=' => 10, '>' => 10, 'in' => 10, 'instanceof' => 10,\n\t\t'<<' => 11, '>>' => 11, '>>>' => 11,\n\t\t'+' => 12, '-' => 12,\n\t\t'*' => 13, '/' => 13, '%' => 13,\n\t\t'delete' => 14, 'void' => 14, 'typeof' => 14,\n\t\t'!' => 14, '~' => 14, 'U+' => 14, 'U-' => 14,\n\t\t'++' => 15, '--' => 15,\n\t\t'new' => 16,\n\t\t'.' => 17,\n\t\tJS_NEW_WITH_ARGS => 0, JS_INDEX => 0, JS_CALL => 0,\n\t\tJS_ARRAY_INIT => 0, JS_OBJECT_INIT => 0, JS_GROUP => 0\n\t);\n\n\tprivate $opArity = array(\n\t\t',' => -2,\n\t\t'=' => 2,\n\t\t'?' => 3,\n\t\t'||' => 2,\n\t\t'&&' => 2,\n\t\t'|' => 2,\n\t\t'^' => 2,\n\t\t'&' => 2,\n\t\t'==' => 2, '!=' => 2, '===' => 2, '!==' => 2,\n\t\t'<' => 2, '<=' => 2, '>=' => 2, '>' => 2, 'in' => 2, 'instanceof' => 2,\n\t\t'<<' => 2, '>>' => 2, '>>>' => 2,\n\t\t'+' => 2, '-' => 2,\n\t\t'*' => 2, '/' => 2, '%' => 2,\n\t\t'delete' => 1, 'void' => 1, 'typeof' => 1,\n\t\t'!' => 1, '~' => 1, 'U+' => 1, 'U-' => 1,\n\t\t'++' => 1, '--' => 1,\n\t\t'new' => 1,\n\t\t'.' => 2,\n\t\tJS_NEW_WITH_ARGS => 2, JS_INDEX => 2, JS_CALL => 2,\n\t\tJS_ARRAY_INIT => 1, JS_OBJECT_INIT => 1, JS_GROUP => 1,\n\t\tTOKEN_CONDCOMMENT_START => 1, TOKEN_CONDCOMMENT_END => 1\n\t);\n\n\tpublic function __construct($minifier=null)\n\t{\n\t\t$this->minifier = $minifier;\n\t\t$this->t = new JSTokenizer();\n\t}\n\n\tpublic function parse($s, $f, $l)\n\t{\n\t\t// initialize tokenizer\n\t\t$this->t->init($s, $f, $l);\n\n\t\t$x = new JSCompilerContext(false);\n\t\t$n = $this->Script($x);\n\t\tif (!$this->t->isDone())\n\t\t\tthrow $this->t->newSyntaxError('Syntax error');\n\n\t\treturn $n;\n\t}\n\n\tprivate function Script($x)\n\t{\n\t\t$n = $this->Statements($x);\n\t\t$n->type = JS_SCRIPT;\n\t\t$n->funDecls = $x->funDecls;\n\t\t$n->varDecls = $x->varDecls;\n\n\t\t// minify by scope\n\t\tif ($this->minifier)\n\t\t{\n\t\t\t$n->value = $this->minifier->parseTree($n);\n\n\t\t\t// clear tree from node to save memory\n\t\t\t$n->treeNodes = null;\n\t\t\t$n->funDecls = null;\n\t\t\t$n->varDecls = null;\n\n\t\t\t$n->type = JS_MINIFIED;\n\t\t}\n\n\t\treturn $n;\n\t}\n\n\tprivate function Statements($x)\n\t{\n\t\t$n = new JSNode($this->t, JS_BLOCK);\n\t\tarray_push($x->stmtStack, $n);\n\n\t\twhile (!$this->t->isDone() && $this->t->peek() != OP_RIGHT_CURLY)\n\t\t\t$n->addNode($this->Statement($x));\n\n\t\tarray_pop($x->stmtStack);\n\n\t\treturn $n;\n\t}\n\n\tprivate function Block($x)\n\t{\n\t\t$this->t->mustMatch(OP_LEFT_CURLY);\n\t\t$n = $this->Statements($x);\n\t\t$this->t->mustMatch(OP_RIGHT_CURLY);\n\n\t\treturn $n;\n\t}\n\n\tprivate function Statement($x)\n\t{\n\t\t$tt = $this->t->get();\n\t\t$n2 = null;\n\n\t\t// Cases for statements ending in a right curly return early, avoiding the\n\t\t// common semicolon insertion magic after this switch.\n\t\tswitch ($tt)\n\t\t{\n\t\t\tcase KEYWORD_FUNCTION:\n\t\t\t\treturn $this->FunctionDefinition(\n\t\t\t\t\t$x,\n\t\t\t\t\ttrue,\n\t\t\t\t\tcount($x->stmtStack) > 1 ? STATEMENT_FORM : DECLARED_FORM\n\t\t\t\t);\n\t\t\tbreak;\n\n\t\t\tcase OP_LEFT_CURLY:\n\t\t\t\t$n = $this->Statements($x);\n\t\t\t\t$this->t->mustMatch(OP_RIGHT_CURLY);\n\t\t\treturn $n;\n\n\t\t\tcase KEYWORD_IF:\n\t\t\t\t$n = new JSNode($this->t);\n\t\t\t\t$n->condition = $this->ParenExpression($x);\n\t\t\t\tarray_push($x->stmtStack, $n);\n\t\t\t\t$n->thenPart = $this->Statement($x);\n\t\t\t\t$n->elsePart = $this->t->match(KEYWORD_ELSE) ? $this->Statement($x) : null;\n\t\t\t\tarray_pop($x->stmtStack);\n\t\t\treturn $n;\n\n\t\t\tcase KEYWORD_SWITCH:\n\t\t\t\t$n = new JSNode($this->t);\n\t\t\t\t$this->t->mustMatch(OP_LEFT_PAREN);\n\t\t\t\t$n->discriminant = $this->Expression($x);\n\t\t\t\t$this->t->mustMatch(OP_RIGHT_PAREN);\n\t\t\t\t$n->cases = array();\n\t\t\t\t$n->defaultIndex = -1;\n\n\t\t\t\tarray_push($x->stmtStack, $n);\n\n\t\t\t\t$this->t->mustMatch(OP_LEFT_CURLY);\n\n\t\t\t\twhile (($tt = $this->t->get()) != OP_RIGHT_CURLY)\n\t\t\t\t{\n\t\t\t\t\tswitch ($tt)\n\t\t\t\t\t{\n\t\t\t\t\t\tcase KEYWORD_DEFAULT:\n\t\t\t\t\t\t\tif ($n->defaultIndex >= 0)\n\t\t\t\t\t\t\t\tthrow $this->t->newSyntaxError('More than one switch default');\n\t\t\t\t\t\t\t// FALL THROUGH\n\t\t\t\t\t\tcase KEYWORD_CASE:\n\t\t\t\t\t\t\t$n2 = new JSNode($this->t);\n\t\t\t\t\t\t\tif ($tt == KEYWORD_DEFAULT)\n\t\t\t\t\t\t\t\t$n->defaultIndex = count($n->cases);\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t$n2->caseLabel = $this->Expression($x, OP_COLON);\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\tthrow $this->t->newSyntaxError('Invalid switch case');\n\t\t\t\t\t}\n\n\t\t\t\t\t$this->t->mustMatch(OP_COLON);\n\t\t\t\t\t$n2->statements = new JSNode($this->t, JS_BLOCK);\n\t\t\t\t\twhile (($tt = $this->t->peek()) != KEYWORD_CASE && $tt != KEYWORD_DEFAULT && $tt != OP_RIGHT_CURLY)\n\t\t\t\t\t\t$n2->statements->addNode($this->Statement($x));\n\n\t\t\t\t\tarray_push($n->cases, $n2);\n\t\t\t\t}\n\n\t\t\t\tarray_pop($x->stmtStack);\n\t\t\treturn $n;\n\n\t\t\tcase KEYWORD_FOR:\n\t\t\t\t$n = new JSNode($this->t);\n\t\t\t\t$n->isLoop = true;\n\t\t\t\t$this->t->mustMatch(OP_LEFT_PAREN);\n\n\t\t\t\tif (($tt = $this->t->peek()) != OP_SEMICOLON)\n\t\t\t\t{\n\t\t\t\t\t$x->inForLoopInit = true;\n\t\t\t\t\tif ($tt == KEYWORD_VAR || $tt == KEYWORD_CONST)\n\t\t\t\t\t{\n\t\t\t\t\t\t$this->t->get();\n\t\t\t\t\t\t$n2 = $this->Variables($x);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t$n2 = $this->Expression($x);\n\t\t\t\t\t}\n\t\t\t\t\t$x->inForLoopInit = false;\n\t\t\t\t}\n\n\t\t\t\tif ($n2 && $this->t->match(KEYWORD_IN))\n\t\t\t\t{\n\t\t\t\t\t$n->type = JS_FOR_IN;\n\t\t\t\t\tif ($n2->type == KEYWORD_VAR)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (count($n2->treeNodes) != 1)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tthrow $this->t->SyntaxError(\n\t\t\t\t\t\t\t\t'Invalid for..in left-hand side',\n\t\t\t\t\t\t\t\t$this->t->filename,\n\t\t\t\t\t\t\t\t$n2->lineno\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// NB: n2[0].type == IDENTIFIER and n2[0].value == n2[0].name.\n\t\t\t\t\t\t$n->iterator = $n2->treeNodes[0];\n\t\t\t\t\t\t$n->varDecl = $n2;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t$n->iterator = $n2;\n\t\t\t\t\t\t$n->varDecl = null;\n\t\t\t\t\t}\n\n\t\t\t\t\t$n->object = $this->Expression($x);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t$n->setup = $n2 ? $n2 : null;\n\t\t\t\t\t$this->t->mustMatch(OP_SEMICOLON);\n\t\t\t\t\t$n->condition = $this->t->peek() == OP_SEMICOLON ? null : $this->Expression($x);\n\t\t\t\t\t$this->t->mustMatch(OP_SEMICOLON);\n\t\t\t\t\t$n->update = $this->t->peek() == OP_RIGHT_PAREN ? null : $this->Expression($x);\n\t\t\t\t}\n\n\t\t\t\t$this->t->mustMatch(OP_RIGHT_PAREN);\n\t\t\t\t$n->body = $this->nest($x, $n);\n\t\t\treturn $n;\n\n\t\t\tcase KEYWORD_WHILE:\n\t\t\t        $n = new JSNode($this->t);\n\t\t\t        $n->isLoop = true;\n\t\t\t        $n->condition = $this->ParenExpression($x);\n\t\t\t        $n->body = $this->nest($x, $n);\n\t\t\treturn $n;\n\n\t\t\tcase KEYWORD_DO:\n\t\t\t\t$n = new JSNode($this->t);\n\t\t\t\t$n->isLoop = true;\n\t\t\t\t$n->body = $this->nest($x, $n, KEYWORD_WHILE);\n\t\t\t\t$n->condition = $this->ParenExpression($x);\n\t\t\t\tif (!$x->ecmaStrictMode)\n\t\t\t\t{\n\t\t\t\t\t// <script language=\"JavaScript\"> (without version hints) may need\n\t\t\t\t\t// automatic semicolon insertion without a newline after do-while.\n\t\t\t\t\t// See http://bugzilla.mozilla.org/show_bug.cgi?id=238945.\n\t\t\t\t\t$this->t->match(OP_SEMICOLON);\n\t\t\t\t\treturn $n;\n\t\t\t\t}\n\t\t\tbreak;\n\n\t\t\tcase KEYWORD_BREAK:\n\t\t\tcase KEYWORD_CONTINUE:\n\t\t\t\t$n = new JSNode($this->t);\n\n\t\t\t\tif ($this->t->peekOnSameLine() == TOKEN_IDENTIFIER)\n\t\t\t\t{\n\t\t\t\t\t$this->t->get();\n\t\t\t\t\t$n->label = $this->t->currentToken()->value;\n\t\t\t\t}\n\n\t\t\t\t$ss = $x->stmtStack;\n\t\t\t\t$i = count($ss);\n\t\t\t\t$label = $n->label;\n\t\t\t\tif ($label)\n\t\t\t\t{\n\t\t\t\t\tdo\n\t\t\t\t\t{\n\t\t\t\t\t\tif (--$i < 0)\n\t\t\t\t\t\t\tthrow $this->t->newSyntaxError('Label not found');\n\t\t\t\t\t}\n\t\t\t\t\twhile ($ss[$i]->label != $label);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tdo\n\t\t\t\t\t{\n\t\t\t\t\t\tif (--$i < 0)\n\t\t\t\t\t\t\tthrow $this->t->newSyntaxError('Invalid ' . $tt);\n\t\t\t\t\t}\n\t\t\t\t\twhile (!$ss[$i]->isLoop && ($tt != KEYWORD_BREAK || $ss[$i]->type != KEYWORD_SWITCH));\n\t\t\t\t}\n\n\t\t\t\t$n->target = $ss[$i];\n\t\t\tbreak;\n\n\t\t\tcase KEYWORD_TRY:\n\t\t\t\t$n = new JSNode($this->t);\n\t\t\t\t$n->tryBlock = $this->Block($x);\n\t\t\t\t$n->catchClauses = array();\n\n\t\t\t\twhile ($this->t->match(KEYWORD_CATCH))\n\t\t\t\t{\n\t\t\t\t\t$n2 = new JSNode($this->t);\n\t\t\t\t\t$this->t->mustMatch(OP_LEFT_PAREN);\n\t\t\t\t\t$n2->varName = $this->t->mustMatch(TOKEN_IDENTIFIER)->value;\n\n\t\t\t\t\tif ($this->t->match(KEYWORD_IF))\n\t\t\t\t\t{\n\t\t\t\t\t\tif ($x->ecmaStrictMode)\n\t\t\t\t\t\t\tthrow $this->t->newSyntaxError('Illegal catch guard');\n\n\t\t\t\t\t\tif (count($n->catchClauses) && !end($n->catchClauses)->guard)\n\t\t\t\t\t\t\tthrow $this->t->newSyntaxError('Guarded catch after unguarded');\n\n\t\t\t\t\t\t$n2->guard = $this->Expression($x);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t$n2->guard = null;\n\t\t\t\t\t}\n\n\t\t\t\t\t$this->t->mustMatch(OP_RIGHT_PAREN);\n\t\t\t\t\t$n2->block = $this->Block($x);\n\t\t\t\t\tarray_push($n->catchClauses, $n2);\n\t\t\t\t}\n\n\t\t\t\tif ($this->t->match(KEYWORD_FINALLY))\n\t\t\t\t\t$n->finallyBlock = $this->Block($x);\n\n\t\t\t\tif (!count($n->catchClauses) && !$n->finallyBlock)\n\t\t\t\t\tthrow $this->t->newSyntaxError('Invalid try statement');\n\t\t\treturn $n;\n\n\t\t\tcase KEYWORD_CATCH:\n\t\t\tcase KEYWORD_FINALLY:\n\t\t\t\tthrow $this->t->newSyntaxError($tt + ' without preceding try');\n\n\t\t\tcase KEYWORD_THROW:\n\t\t\t\t$n = new JSNode($this->t);\n\t\t\t\t$n->value = $this->Expression($x);\n\t\t\tbreak;\n\n\t\t\tcase KEYWORD_RETURN:\n\t\t\t\tif (!$x->inFunction)\n\t\t\t\t\tthrow $this->t->newSyntaxError('Invalid return');\n\n\t\t\t\t$n = new JSNode($this->t);\n\t\t\t\t$tt = $this->t->peekOnSameLine();\n\t\t\t\tif ($tt != TOKEN_END && $tt != TOKEN_NEWLINE && $tt != OP_SEMICOLON && $tt != OP_RIGHT_CURLY)\n\t\t\t\t\t$n->value = $this->Expression($x);\n\t\t\t\telse\n\t\t\t\t\t$n->value = null;\n\t\t\tbreak;\n\n\t\t\tcase KEYWORD_WITH:\n\t\t\t\t$n = new JSNode($this->t);\n\t\t\t\t$n->object = $this->ParenExpression($x);\n\t\t\t\t$n->body = $this->nest($x, $n);\n\t\t\treturn $n;\n\n\t\t\tcase KEYWORD_VAR:\n\t\t\tcase KEYWORD_CONST:\n\t\t\t        $n = $this->Variables($x);\n\t\t\tbreak;\n\n\t\t\tcase TOKEN_CONDCOMMENT_START:\n\t\t\tcase TOKEN_CONDCOMMENT_END:\n\t\t\t\t$n = new JSNode($this->t);\n\t\t\treturn $n;\n\n\t\t\tcase KEYWORD_DEBUGGER:\n\t\t\t\t$n = new JSNode($this->t);\n\t\t\tbreak;\n\n\t\t\tcase TOKEN_NEWLINE:\n\t\t\tcase OP_SEMICOLON:\n\t\t\t\t$n = new JSNode($this->t, OP_SEMICOLON);\n\t\t\t\t$n->expression = null;\n\t\t\treturn $n;\n\n\t\t\tdefault:\n\t\t\t\tif ($tt == TOKEN_IDENTIFIER)\n\t\t\t\t{\n\t\t\t\t\t$this->t->scanOperand = false;\n\t\t\t\t\t$tt = $this->t->peek();\n\t\t\t\t\t$this->t->scanOperand = true;\n\t\t\t\t\tif ($tt == OP_COLON)\n\t\t\t\t\t{\n\t\t\t\t\t\t$label = $this->t->currentToken()->value;\n\t\t\t\t\t\t$ss = $x->stmtStack;\n\t\t\t\t\t\tfor ($i = count($ss) - 1; $i >= 0; --$i)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif ($ss[$i]->label == $label)\n\t\t\t\t\t\t\t\tthrow $this->t->newSyntaxError('Duplicate label');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t$this->t->get();\n\t\t\t\t\t\t$n = new JSNode($this->t, JS_LABEL);\n\t\t\t\t\t\t$n->label = $label;\n\t\t\t\t\t\t$n->statement = $this->nest($x, $n);\n\n\t\t\t\t\t\treturn $n;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t$n = new JSNode($this->t, OP_SEMICOLON);\n\t\t\t\t$this->t->unget();\n\t\t\t\t$n->expression = $this->Expression($x);\n\t\t\t\t$n->end = $n->expression->end;\n\t\t\tbreak;\n\t\t}\n\n\t\tif ($this->t->lineno == $this->t->currentToken()->lineno)\n\t\t{\n\t\t\t$tt = $this->t->peekOnSameLine();\n\t\t\tif ($tt != TOKEN_END && $tt != TOKEN_NEWLINE && $tt != OP_SEMICOLON && $tt != OP_RIGHT_CURLY)\n\t\t\t\tthrow $this->t->newSyntaxError('Missing ; before statement');\n\t\t}\n\n\t\t$this->t->match(OP_SEMICOLON);\n\n\t\treturn $n;\n\t}\n\n\tprivate function FunctionDefinition($x, $requireName, $functionForm)\n\t{\n\t\t$f = new JSNode($this->t);\n\n\t\tif ($f->type != KEYWORD_FUNCTION)\n\t\t\t$f->type = ($f->value == 'get') ? JS_GETTER : JS_SETTER;\n\n\t\tif ($this->t->match(TOKEN_IDENTIFIER))\n\t\t\t$f->name = $this->t->currentToken()->value;\n\t\telseif ($requireName)\n\t\t\tthrow $this->t->newSyntaxError('Missing function identifier');\n\n\t\t$this->t->mustMatch(OP_LEFT_PAREN);\n\t\t\t$f->params = array();\n\n\t\twhile (($tt = $this->t->get()) != OP_RIGHT_PAREN)\n\t\t{\n\t\t\tif ($tt != TOKEN_IDENTIFIER)\n\t\t\t\tthrow $this->t->newSyntaxError('Missing formal parameter');\n\n\t\t\tarray_push($f->params, $this->t->currentToken()->value);\n\n\t\t\tif ($this->t->peek() != OP_RIGHT_PAREN)\n\t\t\t\t$this->t->mustMatch(OP_COMMA);\n\t\t}\n\n\t\t$this->t->mustMatch(OP_LEFT_CURLY);\n\n\t\t$x2 = new JSCompilerContext(true);\n\t\t$f->body = $this->Script($x2);\n\n\t\t$this->t->mustMatch(OP_RIGHT_CURLY);\n\t\t$f->end = $this->t->currentToken()->end;\n\n\t\t$f->functionForm = $functionForm;\n\t\tif ($functionForm == DECLARED_FORM)\n\t\t\tarray_push($x->funDecls, $f);\n\n\t\treturn $f;\n\t}\n\n\tprivate function Variables($x)\n\t{\n\t\t$n = new JSNode($this->t);\n\n\t\tdo\n\t\t{\n\t\t\t$this->t->mustMatch(TOKEN_IDENTIFIER);\n\n\t\t\t$n2 = new JSNode($this->t);\n\t\t\t$n2->name = $n2->value;\n\n\t\t\tif ($this->t->match(OP_ASSIGN))\n\t\t\t{\n\t\t\t\tif ($this->t->currentToken()->assignOp)\n\t\t\t\t\tthrow $this->t->newSyntaxError('Invalid variable initialization');\n\n\t\t\t\t$n2->initializer = $this->Expression($x, OP_COMMA);\n\t\t\t}\n\n\t\t\t$n2->readOnly = $n->type == KEYWORD_CONST;\n\n\t\t\t$n->addNode($n2);\n\t\t\tarray_push($x->varDecls, $n2);\n\t\t}\n\t\twhile ($this->t->match(OP_COMMA));\n\n\t\treturn $n;\n\t}\n\n\tprivate function Expression($x, $stop=false)\n\t{\n\t\t$operators = array();\n\t\t$operands = array();\n\t\t$n = false;\n\n\t\t$bl = $x->bracketLevel;\n\t\t$cl = $x->curlyLevel;\n\t\t$pl = $x->parenLevel;\n\t\t$hl = $x->hookLevel;\n\n\t\twhile (($tt = $this->t->get()) != TOKEN_END)\n\t\t{\n\t\t\tif ($tt == $stop &&\n\t\t\t\t$x->bracketLevel == $bl &&\n\t\t\t\t$x->curlyLevel == $cl &&\n\t\t\t\t$x->parenLevel == $pl &&\n\t\t\t\t$x->hookLevel == $hl\n\t\t\t)\n\t\t\t{\n\t\t\t\t// Stop only if tt matches the optional stop parameter, and that\n\t\t\t\t// token is not quoted by some kind of bracket.\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tswitch ($tt)\n\t\t\t{\n\t\t\t\tcase OP_SEMICOLON:\n\t\t\t\t\t// NB: cannot be empty, Statement handled that.\n\t\t\t\t\tbreak 2;\n\n\t\t\t\tcase OP_HOOK:\n\t\t\t\t\tif ($this->t->scanOperand)\n\t\t\t\t\t\tbreak 2;\n\n\t\t\t\t\twhile (\t!empty($operators) &&\n\t\t\t\t\t\t$this->opPrecedence[end($operators)->type] > $this->opPrecedence[$tt]\n\t\t\t\t\t)\n\t\t\t\t\t\t$this->reduce($operators, $operands);\n\n\t\t\t\t\tarray_push($operators, new JSNode($this->t));\n\n\t\t\t\t\t++$x->hookLevel;\n\t\t\t\t\t$this->t->scanOperand = true;\n\t\t\t\t\t$n = $this->Expression($x);\n\n\t\t\t\t\tif (!$this->t->match(OP_COLON))\n\t\t\t\t\t\tbreak 2;\n\n\t\t\t\t\t--$x->hookLevel;\n\t\t\t\t\tarray_push($operands, $n);\n\t\t\t\tbreak;\n\n\t\t\t\tcase OP_COLON:\n\t\t\t\t\tif ($x->hookLevel)\n\t\t\t\t\t\tbreak 2;\n\n\t\t\t\t\tthrow $this->t->newSyntaxError('Invalid label');\n\t\t\t\tbreak;\n\n\t\t\t\tcase OP_ASSIGN:\n\t\t\t\t\tif ($this->t->scanOperand)\n\t\t\t\t\t\tbreak 2;\n\n\t\t\t\t\t// Use >, not >=, for right-associative ASSIGN\n\t\t\t\t\twhile (\t!empty($operators) &&\n\t\t\t\t\t\t$this->opPrecedence[end($operators)->type] > $this->opPrecedence[$tt]\n\t\t\t\t\t)\n\t\t\t\t\t\t$this->reduce($operators, $operands);\n\n\t\t\t\t\tarray_push($operators, new JSNode($this->t));\n\t\t\t\t\tend($operands)->assignOp = $this->t->currentToken()->assignOp;\n\t\t\t\t\t$this->t->scanOperand = true;\n\t\t\t\tbreak;\n\n\t\t\t\tcase KEYWORD_IN:\n\t\t\t\t\t// An in operator should not be parsed if we're parsing the head of\n\t\t\t\t\t// a for (...) loop, unless it is in the then part of a conditional\n\t\t\t\t\t// expression, or parenthesized somehow.\n\t\t\t\t\tif ($x->inForLoopInit && !$x->hookLevel &&\n\t\t\t\t\t\t!$x->bracketLevel && !$x->curlyLevel &&\n\t\t\t\t\t\t!$x->parenLevel\n\t\t\t\t\t)\n\t\t\t\t\t\tbreak 2;\n\t\t\t\t// FALL THROUGH\n\t\t\t\tcase OP_COMMA:\n\t\t\t\t\t// A comma operator should not be parsed if we're parsing the then part\n\t\t\t\t\t// of a conditional expression unless it's parenthesized somehow.\n\t\t\t\t\tif ($tt == OP_COMMA && $x->hookLevel &&\n\t\t\t\t\t\t!$x->bracketLevel && !$x->curlyLevel &&\n\t\t\t\t\t\t!$x->parenLevel\n\t\t\t\t\t)\n\t\t\t\t\t\tbreak 2;\n\t\t\t\t// Treat comma as left-associative so reduce can fold left-heavy\n\t\t\t\t// COMMA trees into a single array.\n\t\t\t\t// FALL THROUGH\n\t\t\t\tcase OP_OR:\n\t\t\t\tcase OP_AND:\n\t\t\t\tcase OP_BITWISE_OR:\n\t\t\t\tcase OP_BITWISE_XOR:\n\t\t\t\tcase OP_BITWISE_AND:\n\t\t\t\tcase OP_EQ: case OP_NE: case OP_STRICT_EQ: case OP_STRICT_NE:\n\t\t\t\tcase OP_LT: case OP_LE: case OP_GE: case OP_GT:\n\t\t\t\tcase KEYWORD_INSTANCEOF:\n\t\t\t\tcase OP_LSH: case OP_RSH: case OP_URSH:\n\t\t\t\tcase OP_PLUS: case OP_MINUS:\n\t\t\t\tcase OP_MUL: case OP_DIV: case OP_MOD:\n\t\t\t\tcase OP_DOT:\n\t\t\t\t\tif ($this->t->scanOperand)\n\t\t\t\t\t\tbreak 2;\n\n\t\t\t\t\twhile (\t!empty($operators) &&\n\t\t\t\t\t\t$this->opPrecedence[end($operators)->type] >= $this->opPrecedence[$tt]\n\t\t\t\t\t)\n\t\t\t\t\t\t$this->reduce($operators, $operands);\n\n\t\t\t\t\tif ($tt == OP_DOT)\n\t\t\t\t\t{\n\t\t\t\t\t\t$this->t->mustMatch(TOKEN_IDENTIFIER);\n\t\t\t\t\t\tarray_push($operands, new JSNode($this->t, OP_DOT, array_pop($operands), new JSNode($this->t)));\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tarray_push($operators, new JSNode($this->t));\n\t\t\t\t\t\t$this->t->scanOperand = true;\n\t\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\t\tcase KEYWORD_DELETE: case KEYWORD_VOID: case KEYWORD_TYPEOF:\n\t\t\t\tcase OP_NOT: case OP_BITWISE_NOT: case OP_UNARY_PLUS: case OP_UNARY_MINUS:\n\t\t\t\tcase KEYWORD_NEW:\n\t\t\t\t\tif (!$this->t->scanOperand)\n\t\t\t\t\t\tbreak 2;\n\n\t\t\t\t\tarray_push($operators, new JSNode($this->t));\n\t\t\t\tbreak;\n\n\t\t\t\tcase OP_INCREMENT: case OP_DECREMENT:\n\t\t\t\t\tif ($this->t->scanOperand)\n\t\t\t\t\t{\n\t\t\t\t\t\tarray_push($operators, new JSNode($this->t));  // prefix increment or decrement\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// Don't cross a line boundary for postfix {in,de}crement.\n\t\t\t\t\t\t$t = $this->t->tokens[($this->t->tokenIndex + $this->t->lookahead - 1) & 3];\n\t\t\t\t\t\tif ($t && $t->lineno != $this->t->lineno)\n\t\t\t\t\t\t\tbreak 2;\n\n\t\t\t\t\t\tif (!empty($operators))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// Use >, not >=, so postfix has higher precedence than prefix.\n\t\t\t\t\t\t\twhile ($this->opPrecedence[end($operators)->type] > $this->opPrecedence[$tt])\n\t\t\t\t\t\t\t\t$this->reduce($operators, $operands);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t$n = new JSNode($this->t, $tt, array_pop($operands));\n\t\t\t\t\t\t$n->postfix = true;\n\t\t\t\t\t\tarray_push($operands, $n);\n\t\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\t\tcase KEYWORD_FUNCTION:\n\t\t\t\t\tif (!$this->t->scanOperand)\n\t\t\t\t\t\tbreak 2;\n\n\t\t\t\t\tarray_push($operands, $this->FunctionDefinition($x, false, EXPRESSED_FORM));\n\t\t\t\t\t$this->t->scanOperand = false;\n\t\t\t\tbreak;\n\n\t\t\t\tcase KEYWORD_NULL: case KEYWORD_THIS: case KEYWORD_TRUE: case KEYWORD_FALSE:\n\t\t\t\tcase TOKEN_IDENTIFIER: case TOKEN_NUMBER: case TOKEN_STRING: case TOKEN_REGEXP:\n\t\t\t\t\tif (!$this->t->scanOperand)\n\t\t\t\t\t\tbreak 2;\n\n\t\t\t\t\tarray_push($operands, new JSNode($this->t));\n\t\t\t\t\t$this->t->scanOperand = false;\n\t\t\t\tbreak;\n\n\t\t\t\tcase TOKEN_CONDCOMMENT_START:\n\t\t\t\tcase TOKEN_CONDCOMMENT_END:\n\t\t\t\t\tif ($this->t->scanOperand)\n\t\t\t\t\t\tarray_push($operators, new JSNode($this->t));\n\t\t\t\t\telse\n\t\t\t\t\t\tarray_push($operands, new JSNode($this->t));\n\t\t\t\tbreak;\n\n\t\t\t\tcase OP_LEFT_BRACKET:\n\t\t\t\t\tif ($this->t->scanOperand)\n\t\t\t\t\t{\n\t\t\t\t\t\t// Array initialiser.  Parse using recursive descent, as the\n\t\t\t\t\t\t// sub-grammar here is not an operator grammar.\n\t\t\t\t\t\t$n = new JSNode($this->t, JS_ARRAY_INIT);\n\t\t\t\t\t\twhile (($tt = $this->t->peek()) != OP_RIGHT_BRACKET)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif ($tt == OP_COMMA)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t$this->t->get();\n\t\t\t\t\t\t\t\t$n->addNode(null);\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t$n->addNode($this->Expression($x, OP_COMMA));\n\t\t\t\t\t\t\tif (!$this->t->match(OP_COMMA))\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t$this->t->mustMatch(OP_RIGHT_BRACKET);\n\t\t\t\t\t\tarray_push($operands, $n);\n\t\t\t\t\t\t$this->t->scanOperand = false;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// Property indexing operator.\n\t\t\t\t\t\tarray_push($operators, new JSNode($this->t, JS_INDEX));\n\t\t\t\t\t\t$this->t->scanOperand = true;\n\t\t\t\t\t\t++$x->bracketLevel;\n\t\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\t\tcase OP_RIGHT_BRACKET:\n\t\t\t\t\tif ($this->t->scanOperand || $x->bracketLevel == $bl)\n\t\t\t\t\t\tbreak 2;\n\n\t\t\t\t\twhile ($this->reduce($operators, $operands)->type != JS_INDEX)\n\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\t--$x->bracketLevel;\n\t\t\t\tbreak;\n\n\t\t\t\tcase OP_LEFT_CURLY:\n\t\t\t\t\tif (!$this->t->scanOperand)\n\t\t\t\t\t\tbreak 2;\n\n\t\t\t\t\t// Object initialiser.  As for array initialisers (see above),\n\t\t\t\t\t// parse using recursive descent.\n\t\t\t\t\t++$x->curlyLevel;\n\t\t\t\t\t$n = new JSNode($this->t, JS_OBJECT_INIT);\n\t\t\t\t\twhile (!$this->t->match(OP_RIGHT_CURLY))\n\t\t\t\t\t{\n\t\t\t\t\t\tdo\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$tt = $this->t->get();\n\t\t\t\t\t\t\t$tv = $this->t->currentToken()->value;\n\t\t\t\t\t\t\tif (($tv == 'get' || $tv == 'set') && $this->t->peek() == TOKEN_IDENTIFIER)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tif ($x->ecmaStrictMode)\n\t\t\t\t\t\t\t\t\tthrow $this->t->newSyntaxError('Illegal property accessor');\n\n\t\t\t\t\t\t\t\t$n->addNode($this->FunctionDefinition($x, true, EXPRESSED_FORM));\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tswitch ($tt)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tcase TOKEN_IDENTIFIER:\n\t\t\t\t\t\t\t\t\tcase TOKEN_NUMBER:\n\t\t\t\t\t\t\t\t\tcase TOKEN_STRING:\n\t\t\t\t\t\t\t\t\t\t$id = new JSNode($this->t);\n\t\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t\t\tcase OP_RIGHT_CURLY:\n\t\t\t\t\t\t\t\t\t\tif ($x->ecmaStrictMode)\n\t\t\t\t\t\t\t\t\t\t\tthrow $this->t->newSyntaxError('Illegal trailing ,');\n\t\t\t\t\t\t\t\t\tbreak 3;\n\n\t\t\t\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\t\t\t\tthrow $this->t->newSyntaxError('Invalid property name');\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t$this->t->mustMatch(OP_COLON);\n\t\t\t\t\t\t\t\t$n->addNode(new JSNode($this->t, JS_PROPERTY_INIT, $id, $this->Expression($x, OP_COMMA)));\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\twhile ($this->t->match(OP_COMMA));\n\n\t\t\t\t\t\t$this->t->mustMatch(OP_RIGHT_CURLY);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tarray_push($operands, $n);\n\t\t\t\t\t$this->t->scanOperand = false;\n\t\t\t\t\t--$x->curlyLevel;\n\t\t\t\tbreak;\n\n\t\t\t\tcase OP_RIGHT_CURLY:\n\t\t\t\t\tif (!$this->t->scanOperand && $x->curlyLevel != $cl)\n\t\t\t\t\t\tthrow new Exception('PANIC: right curly botch');\n\t\t\t\tbreak 2;\n\n\t\t\t\tcase OP_LEFT_PAREN:\n\t\t\t\t\tif ($this->t->scanOperand)\n\t\t\t\t\t{\n\t\t\t\t\t\tarray_push($operators, new JSNode($this->t, JS_GROUP));\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\twhile (\t!empty($operators) &&\n\t\t\t\t\t\t\t$this->opPrecedence[end($operators)->type] > $this->opPrecedence[KEYWORD_NEW]\n\t\t\t\t\t\t)\n\t\t\t\t\t\t\t$this->reduce($operators, $operands);\n\n\t\t\t\t\t\t// Handle () now, to regularize the n-ary case for n > 0.\n\t\t\t\t\t\t// We must set scanOperand in case there are arguments and\n\t\t\t\t\t\t// the first one is a regexp or unary+/-.\n\t\t\t\t\t\t$n = end($operators);\n\t\t\t\t\t\t$this->t->scanOperand = true;\n\t\t\t\t\t\tif ($this->t->match(OP_RIGHT_PAREN))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif ($n && $n->type == KEYWORD_NEW)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tarray_pop($operators);\n\t\t\t\t\t\t\t\t$n->addNode(array_pop($operands));\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t$n = new JSNode($this->t, JS_CALL, array_pop($operands), new JSNode($this->t, JS_LIST));\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tarray_push($operands, $n);\n\t\t\t\t\t\t\t$this->t->scanOperand = false;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif ($n && $n->type == KEYWORD_NEW)\n\t\t\t\t\t\t\t$n->type = JS_NEW_WITH_ARGS;\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tarray_push($operators, new JSNode($this->t, JS_CALL));\n\t\t\t\t\t}\n\n\t\t\t\t\t++$x->parenLevel;\n\t\t\t\tbreak;\n\n\t\t\t\tcase OP_RIGHT_PAREN:\n\t\t\t\t\tif ($this->t->scanOperand || $x->parenLevel == $pl)\n\t\t\t\t\t\tbreak 2;\n\n\t\t\t\t\twhile (($tt = $this->reduce($operators, $operands)->type) != JS_GROUP &&\n\t\t\t\t\t\t$tt != JS_CALL && $tt != JS_NEW_WITH_ARGS\n\t\t\t\t\t)\n\t\t\t\t\t{\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tif ($tt != JS_GROUP)\n\t\t\t\t\t{\n\t\t\t\t\t\t$n = end($operands);\n\t\t\t\t\t\tif ($n->treeNodes[1]->type != OP_COMMA)\n\t\t\t\t\t\t\t$n->treeNodes[1] = new JSNode($this->t, JS_LIST, $n->treeNodes[1]);\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\t$n->treeNodes[1]->type = JS_LIST;\n\t\t\t\t\t}\n\n\t\t\t\t\t--$x->parenLevel;\n\t\t\t\tbreak;\n\n\t\t\t\t// Automatic semicolon insertion means we may scan across a newline\n\t\t\t\t// and into the beginning of another statement.  If so, break out of\n\t\t\t\t// the while loop and let the t.scanOperand logic handle errors.\n\t\t\t\tdefault:\n\t\t\t\t\tbreak 2;\n\t\t\t}\n\t\t}\n\n\t\tif ($x->hookLevel != $hl)\n\t\t\tthrow $this->t->newSyntaxError('Missing : in conditional expression');\n\n\t\tif ($x->parenLevel != $pl)\n\t\t\tthrow $this->t->newSyntaxError('Missing ) in parenthetical');\n\n\t\tif ($x->bracketLevel != $bl)\n\t\t\tthrow $this->t->newSyntaxError('Missing ] in index expression');\n\n\t\tif ($this->t->scanOperand)\n\t\t\tthrow $this->t->newSyntaxError('Missing operand');\n\n\t\t// Resume default mode, scanning for operands, not operators.\n\t\t$this->t->scanOperand = true;\n\t\t$this->t->unget();\n\n\t\twhile (count($operators))\n\t\t\t$this->reduce($operators, $operands);\n\n\t\treturn array_pop($operands);\n\t}\n\n\tprivate function ParenExpression($x)\n\t{\n\t\t$this->t->mustMatch(OP_LEFT_PAREN);\n\t\t$n = $this->Expression($x);\n\t\t$this->t->mustMatch(OP_RIGHT_PAREN);\n\n\t\treturn $n;\n\t}\n\n\t// Statement stack and nested statement handler.\n\tprivate function nest($x, $node, $end = false)\n\t{\n\t\tarray_push($x->stmtStack, $node);\n\t\t$n = $this->statement($x);\n\t\tarray_pop($x->stmtStack);\n\n\t\tif ($end)\n\t\t\t$this->t->mustMatch($end);\n\n\t\treturn $n;\n\t}\n\n\tprivate function reduce(&$operators, &$operands)\n\t{\n\t\t$n = array_pop($operators);\n\t\t$op = $n->type;\n\t\t$arity = $this->opArity[$op];\n\t\t$c = count($operands);\n\t\tif ($arity == -2)\n\t\t{\n\t\t\t// Flatten left-associative trees\n\t\t\tif ($c >= 2)\n\t\t\t{\n\t\t\t\t$left = $operands[$c - 2];\n\t\t\t\tif ($left->type == $op)\n\t\t\t\t{\n\t\t\t\t\t$right = array_pop($operands);\n\t\t\t\t\t$left->addNode($right);\n\t\t\t\t\treturn $left;\n\t\t\t\t}\n\t\t\t}\n\t\t\t$arity = 2;\n\t\t}\n\n\t\t// Always use push to add operands to n, to update start and end\n\t\t$a = array_splice($operands, $c - $arity);\n\t\tfor ($i = 0; $i < $arity; $i++)\n\t\t\t$n->addNode($a[$i]);\n\n\t\t// Include closing bracket or postfix operator in [start,end]\n\t\t$te = $this->t->currentToken()->end;\n\t\tif ($n->end < $te)\n\t\t\t$n->end = $te;\n\n\t\tarray_push($operands, $n);\n\n\t\treturn $n;\n\t}\n}\n\nclass JSCompilerContext\n{\n\tpublic $inFunction = false;\n\tpublic $inForLoopInit = false;\n\tpublic $ecmaStrictMode = false;\n\tpublic $bracketLevel = 0;\n\tpublic $curlyLevel = 0;\n\tpublic $parenLevel = 0;\n\tpublic $hookLevel = 0;\n\n\tpublic $stmtStack = array();\n\tpublic $funDecls = array();\n\tpublic $varDecls = array();\n\n\tpublic function __construct($inFunction)\n\t{\n\t\t$this->inFunction = $inFunction;\n\t}\n}\n\nclass JSNode\n{\n\tprivate $type;\n\tprivate $value;\n\tprivate $lineno;\n\tprivate $start;\n\tprivate $end;\n\n\tpublic $treeNodes = array();\n\tpublic $funDecls = array();\n\tpublic $varDecls = array();\n\n\tpublic function __construct($t, $type=0)\n\t{\n\t\tif ($token = $t->currentToken())\n\t\t{\n\t\t\t$this->type = $type ? $type : $token->type;\n\t\t\t$this->value = $token->value;\n\t\t\t$this->lineno = $token->lineno;\n\t\t\t$this->start = $token->start;\n\t\t\t$this->end = $token->end;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t$this->type = $type;\n\t\t\t$this->lineno = $t->lineno;\n\t\t}\n\n\t\tif (($numargs = func_num_args()) > 2)\n\t\t{\n\t\t\t$args = func_get_args();\n\t\t\tfor ($i = 2; $i < $numargs; $i++)\n\t\t\t\t$this->addNode($args[$i]);\n\t\t}\n\t}\n\n\t// we don't want to bloat our object with all kind of specific properties, so we use overloading\n\tpublic function __set($name, $value)\n\t{\n\t\t$this->$name = $value;\n\t}\n\n\tpublic function __get($name)\n\t{\n\t\tif (isset($this->$name))\n\t\t\treturn $this->$name;\n\n\t\treturn null;\n\t}\n\n\tpublic function addNode($node)\n\t{\n\t\tif ($node !== null)\n\t\t{\n\t\t\tif ($node->start < $this->start)\n\t\t\t\t$this->start = $node->start;\n\t\t\tif ($this->end < $node->end)\n\t\t\t\t$this->end = $node->end;\n\t\t}\n\n\t\t$this->treeNodes[] = $node;\n\t}\n}\n\nclass JSTokenizer\n{\n\tprivate $cursor = 0;\n\tprivate $source;\n\n\tpublic $tokens = array();\n\tpublic $tokenIndex = 0;\n\tpublic $lookahead = 0;\n\tpublic $scanNewlines = false;\n\tpublic $scanOperand = true;\n\n\tpublic $filename;\n\tpublic $lineno;\n\n\tprivate $keywords = array(\n\t\t'break',\n\t\t'case', 'catch', 'const', 'continue',\n\t\t'debugger', 'default', 'delete', 'do',\n\t\t'else', 'enum',\n\t\t'false', 'finally', 'for', 'function',\n\t\t'if', 'in', 'instanceof',\n\t\t'new', 'null',\n\t\t'return',\n\t\t'switch',\n\t\t'this', 'throw', 'true', 'try', 'typeof',\n\t\t'var', 'void',\n\t\t'while', 'with'\n\t);\n\n\tprivate $opTypeNames = array(\n\t\t';', ',', '?', ':', '||', '&&', '|', '^',\n\t\t'&', '===', '==', '=', '!==', '!=', '<<', '<=',\n\t\t'<', '>>>', '>>', '>=', '>', '++', '--', '+',\n\t\t'-', '*', '/', '%', '!', '~', '.', '[',\n\t\t']', '{', '}', '(', ')', '@*/'\n\t);\n\n\tprivate $assignOps = array('|', '^', '&', '<<', '>>', '>>>', '+', '-', '*', '/', '%');\n\tprivate $opRegExp;\n\n\tpublic function __construct()\n\t{\n\t\t$this->opRegExp = '#^(' . implode('|', array_map('preg_quote', $this->opTypeNames)) . ')#';\n\t}\n\n\tpublic function init($source, $filename = '', $lineno = 1)\n\t{\n\t\t$this->source = $source;\n\t\t$this->filename = $filename ? $filename : '[inline]';\n\t\t$this->lineno = $lineno;\n\n\t\t$this->cursor = 0;\n\t\t$this->tokens = array();\n\t\t$this->tokenIndex = 0;\n\t\t$this->lookahead = 0;\n\t\t$this->scanNewlines = false;\n\t\t$this->scanOperand = true;\n\t}\n\n\tpublic function getInput($chunksize)\n\t{\n\t\tif ($chunksize)\n\t\t\treturn substr($this->source, $this->cursor, $chunksize);\n\n\t\treturn substr($this->source, $this->cursor);\n\t}\n\n\tpublic function isDone()\n\t{\n\t\treturn $this->peek() == TOKEN_END;\n\t}\n\n\tpublic function match($tt)\n\t{\n\t\treturn $this->get() == $tt || $this->unget();\n\t}\n\n\tpublic function mustMatch($tt)\n\t{\n\t        if (!$this->match($tt))\n\t\t\tthrow $this->newSyntaxError('Unexpected token; token ' . $tt . ' expected');\n\n\t\treturn $this->currentToken();\n\t}\n\n\tpublic function peek()\n\t{\n\t\tif ($this->lookahead)\n\t\t{\n\t\t\t$next = $this->tokens[($this->tokenIndex + $this->lookahead) & 3];\n\t\t\tif ($this->scanNewlines && $next->lineno != $this->lineno)\n\t\t\t\t$tt = TOKEN_NEWLINE;\n\t\t\telse\n\t\t\t\t$tt = $next->type;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t$tt = $this->get();\n\t\t\t$this->unget();\n\t\t}\n\n\t\treturn $tt;\n\t}\n\n\tpublic function peekOnSameLine()\n\t{\n\t\t$this->scanNewlines = true;\n\t\t$tt = $this->peek();\n\t\t$this->scanNewlines = false;\n\n\t\treturn $tt;\n\t}\n\n\tpublic function currentToken()\n\t{\n\t\tif (!empty($this->tokens))\n\t\t\treturn $this->tokens[$this->tokenIndex];\n\t}\n\n\tpublic function get($chunksize = 1000)\n\t{\n\t\twhile($this->lookahead)\n\t\t{\n\t\t\t$this->lookahead--;\n\t\t\t$this->tokenIndex = ($this->tokenIndex + 1) & 3;\n\t\t\t$token = $this->tokens[$this->tokenIndex];\n\t\t\tif ($token->type != TOKEN_NEWLINE || $this->scanNewlines)\n\t\t\t\treturn $token->type;\n\t\t}\n\n\t\t$conditional_comment = false;\n\n\t\t// strip whitespace and comments\n\t\twhile(true)\n\t\t{\n\t\t\t$input = $this->getInput($chunksize);\n\n\t\t\t// whitespace handling; gobble up \\r as well (effectively we don't have support for MAC newlines!)\n\t\t\t$re = $this->scanNewlines ? '/^[ \\r\\t]+/' : '/^\\s+/';\n\t\t\tif (preg_match($re, $input, $match))\n\t\t\t{\n\t\t\t\t$spaces = $match[0];\n\t\t\t\t$spacelen = strlen($spaces);\n\t\t\t\t$this->cursor += $spacelen;\n\t\t\t\tif (!$this->scanNewlines)\n\t\t\t\t\t$this->lineno += substr_count($spaces, \"\\n\");\n\n\t\t\t\tif ($spacelen == $chunksize)\n\t\t\t\t\tcontinue; // complete chunk contained whitespace\n\n\t\t\t\t$input = $this->getInput($chunksize);\n\t\t\t\tif ($input == '' || $input[0] != '/')\n\t\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// Comments\n\t\t\tif (!preg_match('/^\\/(?:\\*(@(?:cc_on|if|elif|else|end))?.*?\\*\\/|\\/[^\\n]*)/s', $input, $match))\n\t\t\t{\n\t\t\t\tif (!$chunksize)\n\t\t\t\t\tbreak;\n\n\t\t\t\t// retry with a full chunk fetch; this also prevents breakage of long regular expressions (which will never match a comment)\n\t\t\t\t$chunksize = null;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// check if this is a conditional (JScript) comment\n\t\t\tif (!empty($match[1]))\n\t\t\t{\n\t\t\t\t$match[0] = '/*' . $match[1];\n\t\t\t\t$conditional_comment = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t$this->cursor += strlen($match[0]);\n\t\t\t\t$this->lineno += substr_count($match[0], \"\\n\");\n\t\t\t}\n\t\t}\n\n\t\tif ($input == '')\n\t\t{\n\t\t\t$tt = TOKEN_END;\n\t\t\t$match = array('');\n\t\t}\n\t\telseif ($conditional_comment)\n\t\t{\n\t\t\t$tt = TOKEN_CONDCOMMENT_START;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tswitch ($input[0])\n\t\t\t{\n\t\t\t\tcase '0':\n\t\t\t\t\t// hexadecimal\n\t\t\t\t\tif (($input[1] == 'x' || $input[1] == 'X') && preg_match('/^0x[0-9a-f]+/i', $input, $match))\n\t\t\t\t\t{\n\t\t\t\t\t\t$tt = TOKEN_NUMBER;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t// FALL THROUGH\n\n\t\t\t\tcase '1': case '2': case '3': case '4': case '5':\n\t\t\t\tcase '6': case '7': case '8': case '9':\n\t\t\t\t\t// should always match\n\t\t\t\t\tpreg_match('/^\\d+(?:\\.\\d*)?(?:[eE][-+]?\\d+)?/', $input, $match);\n\t\t\t\t\t$tt = TOKEN_NUMBER;\n\t\t\t\tbreak;\n\n\t\t\t\tcase \"'\":\n\t\t\t\t\tif (preg_match('/^\\'(?:[^\\\\\\\\\\'\\r\\n]++|\\\\\\\\(?:.|\\r?\\n))*\\'/', $input, $match))\n\t\t\t\t\t{\n\t\t\t\t\t\t$tt = TOKEN_STRING;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tif ($chunksize)\n\t\t\t\t\t\t\treturn $this->get(null); // retry with a full chunk fetch\n\n\t\t\t\t\t\tthrow $this->newSyntaxError('Unterminated string literal');\n\t\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\t\tcase '\"':\n\t\t\t\t\tif (preg_match('/^\"(?:[^\\\\\\\\\"\\r\\n]++|\\\\\\\\(?:.|\\r?\\n))*\"/', $input, $match))\n\t\t\t\t\t{\n\t\t\t\t\t\t$tt = TOKEN_STRING;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tif ($chunksize)\n\t\t\t\t\t\t\treturn $this->get(null); // retry with a full chunk fetch\n\n\t\t\t\t\t\tthrow $this->newSyntaxError('Unterminated string literal');\n\t\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\t\tcase '/':\n\t\t\t\t\tif ($this->scanOperand && preg_match('/^\\/((?:\\\\\\\\.|\\[(?:\\\\\\\\.|[^\\]])*\\]|[^\\/])+)\\/([gimy]*)/', $input, $match))\n\t\t\t\t\t{\n\t\t\t\t\t\t$tt = TOKEN_REGEXP;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t// FALL THROUGH\n\n\t\t\t\tcase '|':\n\t\t\t\tcase '^':\n\t\t\t\tcase '&':\n\t\t\t\tcase '<':\n\t\t\t\tcase '>':\n\t\t\t\tcase '+':\n\t\t\t\tcase '-':\n\t\t\t\tcase '*':\n\t\t\t\tcase '%':\n\t\t\t\tcase '=':\n\t\t\t\tcase '!':\n\t\t\t\t\t// should always match\n\t\t\t\t\tpreg_match($this->opRegExp, $input, $match);\n\t\t\t\t\t$op = $match[0];\n\t\t\t\t\tif (in_array($op, $this->assignOps) && $input[strlen($op)] == '=')\n\t\t\t\t\t{\n\t\t\t\t\t\t$tt = OP_ASSIGN;\n\t\t\t\t\t\t$match[0] .= '=';\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t$tt = $op;\n\t\t\t\t\t\tif ($this->scanOperand)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif ($op == OP_PLUS)\n\t\t\t\t\t\t\t\t$tt = OP_UNARY_PLUS;\n\t\t\t\t\t\t\telseif ($op == OP_MINUS)\n\t\t\t\t\t\t\t\t$tt = OP_UNARY_MINUS;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t$op = null;\n\t\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\t\tcase '.':\n\t\t\t\t\tif (preg_match('/^\\.\\d+(?:[eE][-+]?\\d+)?/', $input, $match))\n\t\t\t\t\t{\n\t\t\t\t\t\t$tt = TOKEN_NUMBER;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t// FALL THROUGH\n\n\t\t\t\tcase ';':\n\t\t\t\tcase ',':\n\t\t\t\tcase '?':\n\t\t\t\tcase ':':\n\t\t\t\tcase '~':\n\t\t\t\tcase '[':\n\t\t\t\tcase ']':\n\t\t\t\tcase '{':\n\t\t\t\tcase '}':\n\t\t\t\tcase '(':\n\t\t\t\tcase ')':\n\t\t\t\t\t// these are all single\n\t\t\t\t\t$match = array($input[0]);\n\t\t\t\t\t$tt = $input[0];\n\t\t\t\tbreak;\n\n\t\t\t\tcase '@':\n\t\t\t\t\t// check end of conditional comment\n\t\t\t\t\tif (substr($input, 0, 3) == '@*/')\n\t\t\t\t\t{\n\t\t\t\t\t\t$match = array('@*/');\n\t\t\t\t\t\t$tt = TOKEN_CONDCOMMENT_END;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\tthrow $this->newSyntaxError('Illegal token');\n\t\t\t\tbreak;\n\n\t\t\t\tcase \"\\n\":\n\t\t\t\t\tif ($this->scanNewlines)\n\t\t\t\t\t{\n\t\t\t\t\t\t$match = array(\"\\n\");\n\t\t\t\t\t\t$tt = TOKEN_NEWLINE;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\tthrow $this->newSyntaxError('Illegal token');\n\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\t// FIXME: add support for unicode and unicode escape sequence \\uHHHH\n\t\t\t\t\tif (preg_match('/^[$\\w]+/', $input, $match))\n\t\t\t\t\t{\n\t\t\t\t\t\t$tt = in_array($match[0], $this->keywords) ? $match[0] : TOKEN_IDENTIFIER;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\tthrow $this->newSyntaxError('Illegal token');\n\t\t\t}\n\t\t}\n\n\t\t$this->tokenIndex = ($this->tokenIndex + 1) & 3;\n\n\t\tif (!isset($this->tokens[$this->tokenIndex]))\n\t\t\t$this->tokens[$this->tokenIndex] = new JSToken();\n\n\t\t$token = $this->tokens[$this->tokenIndex];\n\t\t$token->type = $tt;\n\n\t\tif ($tt == OP_ASSIGN)\n\t\t\t$token->assignOp = $op;\n\n\t\t$token->start = $this->cursor;\n\n\t\t$token->value = $match[0];\n\t\t$this->cursor += strlen($match[0]);\n\n\t\t$token->end = $this->cursor;\n\t\t$token->lineno = $this->lineno;\n\n\t\treturn $tt;\n\t}\n\n\tpublic function unget()\n\t{\n\t\tif (++$this->lookahead == 4)\n\t\t\tthrow $this->newSyntaxError('PANIC: too much lookahead!');\n\n\t\t$this->tokenIndex = ($this->tokenIndex - 1) & 3;\n\t}\n\n\tpublic function newSyntaxError($m)\n\t{\n\t\treturn new Exception('Parse error: ' . $m . ' in file \\'' . $this->filename . '\\' on line ' . $this->lineno);\n\t}\n}\n\nclass JSToken\n{\n\tpublic $type;\n\tpublic $value;\n\tpublic $start;\n\tpublic $end;\n\tpublic $lineno;\n\tpublic $assignOp;\n}\n"
  },
  {
    "path": "application/libraries/minify/cssmin-v3.0.1.php",
    "content": "<?php\n/**\n * CssMin - A (simple) css minifier with benefits\n * \n * --\n * Copyright (c) 2011 Joe Scylla <joe.scylla@gmail.com>\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n * \n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n * \n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n * --\n * \n * @package\t\tCssMin\n * @link\t\thttp://code.google.com/p/cssmin/\n * @author\t\tJoe Scylla <joe.scylla@gmail.com>\n * @copyright\t2008 - 2011 Joe Scylla <joe.scylla@gmail.com>\n * @license\t\thttp://opensource.org/licenses/mit-license.php MIT License\n * @version\t\t3.0.1\n */\n/**\n * Abstract definition of a CSS token class.\n * \n * Every token has to extend this class.\n *\n * @package\t\tCssMin/Tokens\n * @link\t\thttp://code.google.com/p/cssmin/\n * @author\t\tJoe Scylla <joe.scylla@gmail.com>\n * @copyright\t2008 - 2011 Joe Scylla <joe.scylla@gmail.com>\n * @license\t\thttp://opensource.org/licenses/mit-license.php MIT License\n * @version\t\t3.0.1\n */\nabstract class aCssToken\n\t{\n\t/**\n\t * Returns the token as string.\n\t * \n\t * @return string\n\t */\n\tabstract public function __toString();\n\t}\n\n/**\n * Abstract definition of a for a ruleset start token.\n *\n * @package\t\tCssMin/Tokens\n * @link\t\thttp://code.google.com/p/cssmin/\n * @author\t\tJoe Scylla <joe.scylla@gmail.com>\n * @copyright\t2008 - 2011 Joe Scylla <joe.scylla@gmail.com>\n * @license\t\thttp://opensource.org/licenses/mit-license.php MIT License\n * @version\t\t3.0.1\n */\nabstract class aCssRulesetStartToken extends aCssToken\n\t{\n\t\n\t}\n\n/**\n * Abstract definition of a for ruleset end token.\n *\n * @package\t\tCssMin/Tokens\n * @link\t\thttp://code.google.com/p/cssmin/\n * @author\t\tJoe Scylla <joe.scylla@gmail.com>\n * @copyright\t2008 - 2011 Joe Scylla <joe.scylla@gmail.com>\n * @license\t\thttp://opensource.org/licenses/mit-license.php MIT License\n * @version\t\t3.0.1\n */\nabstract class aCssRulesetEndToken extends aCssToken\n\t{\n\t/**\n\t * Implements {@link aCssToken::__toString()}.\n\t * \n\t * @return string\n\t */\n\tpublic function __toString()\n\t\t{\n\t\treturn \"}\";\n\t\t}\n\t}\n\n/**\n * Abstract definition of a parser plugin.\n * \n * Every parser plugin have to extend this class. A parser plugin contains the logic to parse one or aspects of a \n * stylesheet.\n * \n * @package\t\tCssMin/Parser/Plugins\n * @link\t\thttp://code.google.com/p/cssmin/\n * @author\t\tJoe Scylla <joe.scylla@gmail.com>\n * @copyright\t2008 - 2011 Joe Scylla <joe.scylla@gmail.com>\n * @license\t\thttp://opensource.org/licenses/mit-license.php MIT License\n * @version\t\t3.0.1\n */\nabstract class aCssParserPlugin\n\t{\n\t/**\n\t * Plugin configuration.\n\t * \n\t * @var array\n\t */\n\tprotected $configuration = array();\n\t/**\n\t * The CssParser of the plugin.\n\t * \n\t * @var CssParser\n\t */\n\tprotected $parser = null;\n\t/**\n\t * Plugin buffer.\n\t * \n\t * @var string\n\t */\n\tprotected $buffer = \"\";\n\t/**\n\t * Constructor.\n\t * \n\t * @param CssParser $parser The CssParser object of this plugin.\n\t * @param array $configuration Plugin configuration [optional]\n\t * @return void\n\t */\n\tpublic function __construct(CssParser $parser, array $configuration = null)\n\t\t{\n\t\t$this->configuration\t= $configuration;\n\t\t$this->parser\t\t\t= $parser;\n\t\t}\n\t/**\n\t * Returns the array of chars triggering the parser plugin.\n\t * \n\t * @return array\n\t */\n\tabstract public function getTriggerChars();\n\t/**\n\t * Returns the array of states triggering the parser plugin or FALSE if every state will trigger the parser plugin.\n\t * \n\t * @return array\n\t */\n\tabstract public function getTriggerStates();\n\t/**\n\t * Parser routine of the plugin.\n\t * \n\t * @param integer $index Current index\n\t * @param string $char Current char\n\t * @param string $previousChar Previous char\n\t * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing\n\t */\n\tabstract public function parse($index, $char, $previousChar, $state);\n\t}\n\n/**\n * Abstract definition of a minifier plugin class. \n * \n * Minifier plugin process the parsed tokens one by one to apply changes to the token. Every minifier plugin has to \n * extend this class.\n *\n * @package\t\tCssMin/Minifier/Plugins\n * @link\t\thttp://code.google.com/p/cssmin/\n * @author\t\tJoe Scylla <joe.scylla@gmail.com>\n * @copyright\t2008 - 2011 Joe Scylla <joe.scylla@gmail.com>\n * @license\t\thttp://opensource.org/licenses/mit-license.php MIT License\n * @version\t\t3.0.1\n */\nabstract class aCssMinifierPlugin\n\t{\n\t/**\n\t * Plugin configuration.\n\t * \n\t * @var array\n\t */\n\tprotected $configuration = array();\n\t/**\n\t * The CssMinifier of the plugin.\n\t * \n\t * @var CssMinifier\n\t */\n\tprotected $minifier = null;\n\t/**\n\t * Constructor.\n\t * \n\t * @param CssMinifier $minifier The CssMinifier object of this plugin.\n\t * @param array $configuration Plugin configuration [optional]\n\t * @return void\n\t */\n\tpublic function __construct(CssMinifier $minifier, array $configuration = array())\n\t\t{\n\t\t$this->configuration\t= $configuration;\n\t\t$this->minifier\t\t\t= $minifier;\n\t\t}\n\t/**\n\t * Apply the plugin to the token.\n\t * \n\t * @param aCssToken $token Token to process\n\t * @return boolean Return TRUE to break the processing of this token; FALSE to continue\n\t */\n\tabstract public function apply(aCssToken &$token);\n\t/**\n\t * --\n\t * \n\t * @return array\n\t */\n\tabstract public function getTriggerTokens();\n\t}\n\n/**\n * Abstract definition of a minifier filter class. \n * \n * Minifier filters allows a pre-processing of the parsed token to add, edit or delete tokens. Every minifier filter\n * has to extend this class.\n * \n * @package\t\tCssMin/Minifier/Filters\n * @link\t\thttp://code.google.com/p/cssmin/\n * @author\t\tJoe Scylla <joe.scylla@gmail.com>\n * @copyright\t2008 - 2011 Joe Scylla <joe.scylla@gmail.com>\n * @license\t\thttp://opensource.org/licenses/mit-license.php MIT License\n * @version\t\t3.0.1\n */\nabstract class aCssMinifierFilter\n\t{\n\t/**\n\t * Filter configuration.\n\t * \n\t * @var array\n\t */\n\tprotected $configuration = array();\n\t/**\n\t * The CssMinifier of the filter.\n\t * \n\t * @var CssMinifier\n\t */\n\tprotected $minifier = null;\n\t/**\n\t * Constructor.\n\t * \n\t * @param CssMinifier $minifier The CssMinifier object of this plugin.\n\t * @param array $configuration Filter configuration [optional]\n\t * @return void\n\t */\n\tpublic function __construct(CssMinifier $minifier, array $configuration = array())\n\t\t{\n\t\t$this->configuration\t= $configuration;\n\t\t$this->minifier\t\t\t= $minifier;\n\t\t}\n\t/**\n\t * Filter the tokens.\n\t * \n\t * @param array $tokens Array of objects of type aCssToken\n\t * @return integer Count of added, changed or removed tokens; a return value large than 0 will rebuild the array\n\t */\n\tabstract public function apply(array &$tokens);\n\t}\n\n/**\n * Abstract formatter definition.\n * \n * Every formatter have to extend this class.\n * \n * @package\t\tCssMin/Formatter\n * @link\t\thttp://code.google.com/p/cssmin/\n * @author\t\tJoe Scylla <joe.scylla@gmail.com>\n * @copyright\t2008 - 2011 Joe Scylla <joe.scylla@gmail.com>\n * @license\t\thttp://opensource.org/licenses/mit-license.php MIT License\n * @version\t\t3.0.1\n */\nabstract class aCssFormatter\n\t{\n\t/**\n\t * Indent string.\n\t * \n\t * @var string\n\t */\n\tprotected $indent = \"    \";\n\t/**\n\t * Declaration padding.\n\t * \n\t * @var integer\n\t */\n\tprotected $padding = 0;\n\t/**\n\t * Tokens.\n\t * \n\t * @var array\n\t */\n\tprotected $tokens = array();\n\t/**\n\t * Constructor.\n\t * \n\t * @param array $tokens Array of CssToken\n\t * @param string $indent Indent string [optional]\n\t * @param integer $padding Declaration value padding [optional]\n\t */\n\tpublic function __construct(array $tokens, $indent = null, $padding = null)\n\t\t{\n\t\t$this->tokens\t= $tokens;\n\t\t$this->indent\t= !is_null($indent) ? $indent : $this->indent;\n\t\t$this->padding\t= !is_null($padding) ? $padding : $this->padding;\n\t\t}\n\t/**\n\t * Returns the array of aCssToken as formatted string.\n\t * \n\t * @return string\n\t */\n\tabstract public function __toString();\n\t}\n\n/**\n * Abstract definition of a ruleset declaration token.\n *\n * @package\t\tCssMin/Tokens\n * @link\t\thttp://code.google.com/p/cssmin/\n * @author\t\tJoe Scylla <joe.scylla@gmail.com>\n * @copyright\t2008 - 2011 Joe Scylla <joe.scylla@gmail.com>\n * @license\t\thttp://opensource.org/licenses/mit-license.php MIT License\n * @version\t\t3.0.1\n */\nabstract class aCssDeclarationToken extends aCssToken\n\t{\n\t/**\n\t * Is the declaration flagged as important?\n\t * \n\t * @var boolean\n\t */\n\tpublic $IsImportant = false;\n\t/**\n\t * Is the declaration flagged as last one of the ruleset?\n\t * \n\t * @var boolean\n\t */\n\tpublic $IsLast = false;\n\t/**\n\t * Property name of the declaration.\n\t * \n\t * @var string\n\t */\n\tpublic $Property = \"\";\n\t/**\n\t * Value of the declaration.\n\t * \n\t * @var string\n\t */\n\tpublic $Value = \"\";\n\t/**\n\t * Set the properties of the @font-face declaration. \n\t * \n\t * @param string $property Property of the declaration\n\t * @param string $value Value of the declaration\n\t * @param boolean $isImportant Is the !important flag is set?\n\t * @param boolean $IsLast Is the declaration the last one of the block?\n\t * @return void\n\t */\n\tpublic function __construct($property, $value, $isImportant = false, $isLast = false)\n\t\t{\n\t\t$this->Property\t\t= $property;\n\t\t$this->Value\t\t= $value;\n\t\t$this->IsImportant\t= $isImportant;\n\t\t$this->IsLast\t\t= $isLast;\n\t\t}\n\t/**\n\t * Implements {@link aCssToken::__toString()}.\n\t * \n\t * @return string\n\t */\n\tpublic function __toString()\n\t\t{\n\t\treturn $this->Property . \":\" . $this->Value . ($this->IsImportant ? \" !important\" : \"\") . ($this->IsLast ? \"\" : \";\");\n\t\t}\n\t}\n\n/**\n * Abstract definition of a for at-rule block start token.\n *\n * @package\t\tCssMin/Tokens\n * @link\t\thttp://code.google.com/p/cssmin/\n * @author\t\tJoe Scylla <joe.scylla@gmail.com>\n * @copyright\t2008 - 2011 Joe Scylla <joe.scylla@gmail.com>\n * @license\t\thttp://opensource.org/licenses/mit-license.php MIT License\n * @version\t\t3.0.1\n */\nabstract class aCssAtBlockStartToken extends aCssToken\n\t{\n\t\n\t}\n\n/**\n * Abstract definition of a for at-rule block end token.\n *\n * @package\t\tCssMin/Tokens\n * @link\t\thttp://code.google.com/p/cssmin/\n * @author\t\tJoe Scylla <joe.scylla@gmail.com>\n * @copyright\t2008 - 2011 Joe Scylla <joe.scylla@gmail.com>\n * @license\t\thttp://opensource.org/licenses/mit-license.php MIT License\n * @version\t\t3.0.1\n */\nabstract class aCssAtBlockEndToken extends aCssToken\n\t{\n\t/**\n\t * Implements {@link aCssToken::__toString()}.\n\t * \n\t * @return string\n\t */\n\tpublic function __toString()\n\t\t{\n\t\treturn \"}\";\n\t\t}\n\t}\n\n/**\n * {@link aCssFromatter Formatter} returning the CSS source in {@link http://goo.gl/etzLs Whitesmiths indent style}.\n * \n * @package\t\tCssMin/Formatter\n * @link\t\thttp://code.google.com/p/cssmin/\n * @author\t\tJoe Scylla <joe.scylla@gmail.com>\n * @copyright\t2008 - 2011 Joe Scylla <joe.scylla@gmail.com>\n * @license\t\thttp://opensource.org/licenses/mit-license.php MIT License\n * @version\t\t3.0.1\n */\nclass CssWhitesmithsFormatter extends aCssFormatter\n\t{\n\t/**\n\t * Implements {@link aCssFormatter::__toString()}.\n\t * \n\t * @return string\n\t */\n\tpublic function __toString()\n\t\t{\n\t\t$r\t\t\t\t= array();\n\t\t$level\t\t\t= 0;\n\t\tfor ($i = 0, $l = count($this->tokens); $i < $l; $i++)\n\t\t\t{\n\t\t\t$token\t\t= $this->tokens[$i];\n\t\t\t$class\t\t= get_class($token);\n\t\t\t$indent \t= str_repeat($this->indent, $level);\n\t\t\tif ($class === \"CssCommentToken\")\n\t\t\t\t{\n\t\t\t\t$lines = array_map(\"trim\", explode(\"\\n\", $token->Comment));\n\t\t\t\tfor ($ii = 0, $ll = count($lines); $ii < $ll; $ii++)\n\t\t\t\t\t{\n\t\t\t\t\t$r[] = $indent . (substr($lines[$ii], 0, 1) == \"*\" ? \" \" : \"\") . $lines[$ii];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\telseif ($class === \"CssAtCharsetToken\")\n\t\t\t\t{\n\t\t\t\t$r[] = $indent . \"@charset \" . $token->Charset . \";\";\n\t\t\t\t}\n\t\t\telseif ($class === \"CssAtFontFaceStartToken\")\n\t\t\t\t{\n\t\t\t\t$r[] = $indent . \"@font-face\";\n\t\t\t\t$r[] = $this->indent . $indent . \"{\";\n\t\t\t\t$level++;\n\t\t\t\t}\n\t\t\telseif ($class === \"CssAtImportToken\")\n\t\t\t\t{\n\t\t\t\t$r[] = $indent . \"@import \" . $token->Import . \" \" . implode(\", \", $token->MediaTypes) . \";\";\n\t\t\t\t}\n\t\t\telseif ($class === \"CssAtKeyframesStartToken\")\n\t\t\t\t{\n\t\t\t\t$r[] = $indent . \"@keyframes \\\"\" . $token->Name . \"\\\"\";\n\t\t\t\t$r[] = $this->indent . $indent . \"{\";\n\t\t\t\t$level++;\n\t\t\t\t}\n\t\t\telseif ($class === \"CssAtMediaStartToken\")\n\t\t\t\t{\n\t\t\t\t$r[] = $indent . \"@media \" . implode(\", \", $token->MediaTypes);\n\t\t\t\t$r[] = $this->indent . $indent . \"{\";\n\t\t\t\t$level++;\n\t\t\t\t}\n\t\t\telseif ($class === \"CssAtPageStartToken\")\n\t\t\t\t{\n\t\t\t\t$r[] = $indent . \"@page\";\n\t\t\t\t$r[] = $this->indent . $indent . \"{\";\n\t\t\t\t$level++;\n\t\t\t\t}\n\t\t\telseif ($class === \"CssAtVariablesStartToken\")\n\t\t\t\t{\n\t\t\t\t$r[] = $indent . \"@variables \" . implode(\", \", $token->MediaTypes);\n\t\t\t\t$r[] = $this->indent . $indent . \"{\";\n\t\t\t\t$level++;\n\t\t\t\t}\n\t\t\telseif ($class === \"CssRulesetStartToken\" || $class === \"CssAtKeyframesRulesetStartToken\")\n\t\t\t\t{\n\t\t\t\t$r[] = $indent . implode(\", \", $token->Selectors);\n\t\t\t\t$r[] = $this->indent . $indent . \"{\";\n\t\t\t\t$level++;\n\t\t\t\t}\n\t\t\telseif ($class == \"CssAtFontFaceDeclarationToken\"\n\t\t\t\t|| $class === \"CssAtKeyframesRulesetDeclarationToken\"\n\t\t\t\t|| $class === \"CssAtPageDeclarationToken\"\n\t\t\t\t|| $class == \"CssAtVariablesDeclarationToken\"\n\t\t\t\t|| $class === \"CssRulesetDeclarationToken\"\n\t\t\t\t)\n\t\t\t\t{\n\t\t\t\t$declaration = $indent . $token->Property . \": \";\n\t\t\t\tif ($this->padding)\n\t\t\t\t\t{\n\t\t\t\t\t$declaration = str_pad($declaration, $this->padding, \" \", STR_PAD_RIGHT);\n\t\t\t\t\t}\n\t\t\t\t$r[] = $declaration . $token->Value . ($token->IsImportant ? \" !important\" : \"\") . \";\";\n\t\t\t\t}\n\t\t\telseif ($class === \"CssAtFontFaceEndToken\"\n\t\t\t\t|| $class === \"CssAtMediaEndToken\"\n\t\t\t\t|| $class === \"CssAtKeyframesEndToken\"\n\t\t\t\t|| $class === \"CssAtKeyframesRulesetEndToken\"\n\t\t\t\t|| $class === \"CssAtPageEndToken\"\n\t\t\t\t|| $class === \"CssAtVariablesEndToken\"\n\t\t\t\t|| $class === \"CssRulesetEndToken\"\n\t\t\t\t)\n\t\t\t\t{\n\t\t\t\t$r[] = $indent . \"}\";\n\t\t\t\t$level--;\n\t\t\t\t}\n\t\t\t}\n\t\treturn implode(\"\\n\", $r);\n\t\t}\n\t}\n\n/**\n * This {@link aCssMinifierPlugin} will process var-statement and sets the declaration value to the variable value. \n * \n * This plugin only apply the variable values. The variable values itself will get parsed by the\n * {@link CssVariablesMinifierFilter}.\n * \n * Example:\n * <code>\n * @variables\n * \t\t{\n * \t\tdefaultColor: black;\n * \t\t}\n * color: var(defaultColor);\n * </code>\n * \n * Will get converted to:\n * <code>\n * color:black;\n * </code>\n *\n * @package\t\tCssMin/Minifier/Plugins\n * @link\t\thttp://code.google.com/p/cssmin/\n * @author\t\tJoe Scylla <joe.scylla@gmail.com>\n * @copyright\t2008 - 2011 Joe Scylla <joe.scylla@gmail.com>\n * @license\t\thttp://opensource.org/licenses/mit-license.php MIT License\n * @version\t\t3.0.1\n */\nclass CssVariablesMinifierPlugin extends aCssMinifierPlugin\n\t{\n\t/**\n\t * Regular expression matching a value.\n\t * \n\t * @var string\n\t */\n\tprivate $reMatch = \"/var\\((.+)\\)/iSU\";\n\t/**\n\t * Parsed variables.\n\t * \n\t * @var array\n\t */\n\tprivate $variables = null;\n\t/**\n\t * Returns the variables.\n\t * \n\t * @return array\n\t */\n\tpublic function getVariables()\n\t\t{\n\t\treturn $this->variables;\n\t\t}\n\t/**\n\t * Implements {@link aCssMinifierPlugin::minify()}.\n\t * \n\t * @param aCssToken $token Token to process\n\t * @return boolean Return TRUE to break the processing of this token; FALSE to continue\n\t */\n\tpublic function apply(aCssToken &$token)\n\t\t{\n\t\tif (stripos($token->Value, \"var\") !== false && preg_match_all($this->reMatch, $token->Value, $m))\n\t\t\t{\n\t\t\t$mediaTypes\t= $token->MediaTypes;\n\t\t\tif (!in_array(\"all\", $mediaTypes))\n\t\t\t\t{\n\t\t\t\t$mediaTypes[] = \"all\";\n\t\t\t\t}\n\t\t\tfor ($i = 0, $l = count($m[0]); $i < $l; $i++)\n\t\t\t\t{\n\t\t\t\t$variable\t= trim($m[1][$i]);\n\t\t\t\tforeach ($mediaTypes as $mediaType)\n\t\t\t\t\t{\n\t\t\t\t\tif (isset($this->variables[$mediaType], $this->variables[$mediaType][$variable]))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t// Variable value found => set the declaration value to the variable value and return\n\t\t\t\t\t\t$token->Value = str_replace($m[0][$i], $this->variables[$mediaType][$variable], $token->Value);\n\t\t\t\t\t\tcontinue 2;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t// If no value was found trigger an error and replace the token with a CssNullToken\n\t\t\t\tCssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . \": No value found for variable <code>\" . $variable . \"</code> in media types <code>\" . implode(\", \", $mediaTypes) . \"</code>\", (string) $token));\n\t\t\t\t$token = new CssNullToken();\n\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\treturn false;\n\t\t}\n\t/**\n\t * Implements {@link aMinifierPlugin::getTriggerTokens()}\n\t * \n\t * @return array\n\t */\n\tpublic function getTriggerTokens()\n\t\t{\n\t\treturn array\n\t\t\t(\n\t\t\t\"CssAtFontFaceDeclarationToken\",\n\t\t\t\"CssAtPageDeclarationToken\",\n\t\t\t\"CssRulesetDeclarationToken\"\n\t\t\t);\n\t\t}\n\t/**\n\t * Sets the variables.\n\t * \n\t * @param array $variables Variables to set\n\t * @return void\n\t */\n\tpublic function setVariables(array $variables)\n\t\t{\n\t\t$this->variables = $variables;\n\t\t}\n\t}\n\n/**\n * This {@link aCssMinifierFilter minifier filter} will parse the variable declarations out of @variables at-rule \n * blocks. The variables will get store in the {@link CssVariablesMinifierPlugin} that will apply the variables to \n * declaration.\n * \n * @package\t\tCssMin/Minifier/Filters\n * @link\t\thttp://code.google.com/p/cssmin/\n * @author\t\tJoe Scylla <joe.scylla@gmail.com>\n * @copyright\t2008 - 2011 Joe Scylla <joe.scylla@gmail.com>\n * @license\t\thttp://opensource.org/licenses/mit-license.php MIT License\n * @version\t\t3.0.1\n */\nclass CssVariablesMinifierFilter extends aCssMinifierFilter\n\t{\n\t/**\n\t * Implements {@link aCssMinifierFilter::filter()}.\n\t * \n\t * @param array $tokens Array of objects of type aCssToken\n\t * @return integer Count of added, changed or removed tokens; a return value large than 0 will rebuild the array\n\t */\n\tpublic function apply(array &$tokens)\n\t\t{\n\t\t$variables\t\t\t= array();\n\t\t$defaultMediaTypes\t= array(\"all\");\n\t\t$mediaTypes\t\t\t= array();\n\t\t$remove\t\t\t\t= array();\n\t\tfor($i = 0, $l = count($tokens); $i < $l; $i++)\n\t\t\t{\n\t\t\t// @variables at-rule block found\n\t\t\tif (get_class($tokens[$i]) === \"CssAtVariablesStartToken\")\n\t\t\t\t{\n\t\t\t\t$remove[] = $i;\n\t\t\t\t$mediaTypes = (count($tokens[$i]->MediaTypes) == 0 ? $defaultMediaTypes : $tokens[$i]->MediaTypes);\n\t\t\t\tforeach ($mediaTypes as $mediaType)\n\t\t\t\t\t{\n\t\t\t\t\tif (!isset($variables[$mediaType]))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t$variables[$mediaType] = array();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t// Read the variable declaration tokens\n\t\t\t\tfor($i = $i; $i < $l; $i++)\n\t\t\t\t\t{\n\t\t\t\t\t// Found a variable declaration => read the variable values\n\t\t\t\t\tif (get_class($tokens[$i]) === \"CssAtVariablesDeclarationToken\")\n\t\t\t\t\t\t{\n\t\t\t\t\t\tforeach ($mediaTypes as $mediaType)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$variables[$mediaType][$tokens[$i]->Property] = $tokens[$i]->Value;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t$remove[] = $i;\n\t\t\t\t\t\t}\n\t\t\t\t\t// Found the variables end token => break;\n\t\t\t\t\telseif (get_class($tokens[$i]) === \"CssAtVariablesEndToken\")\n\t\t\t\t\t\t{\n\t\t\t\t\t\t$remove[] = $i;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t// Variables in @variables at-rule blocks\n\t\tforeach($variables as $mediaType => $null)\n\t\t\t{\n\t\t\tforeach($variables[$mediaType] as $variable => $value)\n\t\t\t\t{\n\t\t\t\t// If a var() statement in a variable value found...\n\t\t\t\tif (stripos($value, \"var\") !== false && preg_match_all(\"/var\\((.+)\\)/iSU\", $value, $m))\n\t\t\t\t\t{\n\t\t\t\t\t// ... then replace the var() statement with the variable values.\n\t\t\t\t\tfor ($i = 0, $l = count($m[0]); $i < $l; $i++)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t$variables[$mediaType][$variable] = str_replace($m[0][$i], (isset($variables[$mediaType][$m[1][$i]]) ? $variables[$mediaType][$m[1][$i]] : \"\"), $variables[$mediaType][$variable]);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t// Remove the complete @variables at-rule block\n\t\tforeach ($remove as $i)\n\t\t\t{\n\t\t\t$tokens[$i] = null;\n\t\t\t}\n\t\tif (!($plugin = $this->minifier->getPlugin(\"CssVariablesMinifierPlugin\")))\n\t\t\t{\n\t\t\tCssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . \": The plugin <code>CssVariablesMinifierPlugin</code> was not found but is required for <code>\" . __CLASS__ . \"</code>\"));\n\t\t\t}\n\t\telse\n\t\t\t{\n\t\t\t$plugin->setVariables($variables);\n\t\t\t}\n\t\treturn count($remove);\n\t\t}\n\t}\n\n/**\n * {@link aCssParserPlugin Parser plugin} for preserve parsing url() values.\n * \n * This plugin return no {@link aCssToken CssToken} but ensures that url() values will get parsed properly.\n * \n * @package\t\tCssMin/Parser/Plugins\n * @link\t\thttp://code.google.com/p/cssmin/\n * @author\t\tJoe Scylla <joe.scylla@gmail.com>\n * @copyright\t2008 - 2011 Joe Scylla <joe.scylla@gmail.com>\n * @license\t\thttp://opensource.org/licenses/mit-license.php MIT License\n * @version\t\t3.0.1\n */\nclass CssUrlParserPlugin extends aCssParserPlugin\n\t{\n\t/**\n\t * Implements {@link aCssParserPlugin::getTriggerChars()}.\n\t * \n\t * @return array\n\t */\n\tpublic function getTriggerChars()\n\t\t{\n\t\treturn array(\"(\", \")\");\n\t\t}\n\t/**\n\t * Implements {@link aCssParserPlugin::getTriggerStates()}.\n\t * \n\t * @return array\n\t */\n\tpublic function getTriggerStates()\n\t\t{\n\t\treturn false;\n\t\t}\n\t/**\n\t * Implements {@link aCssParserPlugin::parse()}.\n\t * \n\t * @param integer $index Current index\n\t * @param string $char Current char\n\t * @param string $previousChar Previous char\n\t * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing\n\t */\n\tpublic function parse($index, $char, $previousChar, $state)\n\t\t{\n\t\t// Start of string\n\t\tif ($char === \"(\" && strtolower(substr($this->parser->getSource(), $index - 3, 4)) === \"url(\" && $state !== \"T_URL\")\n\t\t\t{\n\t\t\t$this->parser->pushState(\"T_URL\");\n\t\t\t$this->parser->setExclusive(__CLASS__);\n\t\t\t}\n\t\t// Escaped LF in url => remove escape backslash and LF\n\t\telseif ($char === \"\\n\" && $previousChar === \"\\\\\" && $state === \"T_URL\")\n\t\t\t{\n\t\t\t$this->parser->setBuffer(substr($this->parser->getBuffer(), 0, -2));\n\t\t\t}\n\t\t// Parse error: Unescaped LF in string literal\n\t\telseif ($char === \"\\n\" && $previousChar !== \"\\\\\" && $state === \"T_URL\")\n\t\t\t{\n\t\t\t$line = $this->parser->getBuffer();\n\t\t\t$this->parser->setBuffer(substr($this->parser->getBuffer(), 0, -1) . \")\"); // Replace the LF with the url string delimiter\n\t\t\t$this->parser->popState();\n\t\t\t$this->parser->unsetExclusive();\n\t\t\tCssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . \": Unterminated string literal\", $line . \"_\"));\n\t\t\t}\n\t\t// End of string\n\t\telseif ($char === \")\" && $state === \"T_URL\")\n\t\t\t{\n\t\t\t$this->parser->popState();\n\t\t\t$this->parser->unsetExclusive();\n\t\t\t}\n\t\telse\n\t\t\t{\n\t\t\treturn false;\n\t\t\t}\n\t\treturn true;\n\t\t}\n\t}\n\n/**\n * {@link aCssParserPlugin Parser plugin} for preserve parsing string values.\n * \n * This plugin return no {@link aCssToken CssToken} but ensures that string values will get parsed properly.\n * \n * @package\t\tCssMin/Parser/Plugins\n * @link\t\thttp://code.google.com/p/cssmin/\n * @author\t\tJoe Scylla <joe.scylla@gmail.com>\n * @copyright\t2008 - 2011 Joe Scylla <joe.scylla@gmail.com>\n * @license\t\thttp://opensource.org/licenses/mit-license.php MIT License\n * @version\t\t3.0.1\n */\nclass CssStringParserPlugin extends aCssParserPlugin\n\t{\n\t/**\n\t * Current string delimiter char.\n\t * \n\t * @var string\n\t */\n\tprivate $delimiterChar = null;\n\t/**\n\t * Implements {@link aCssParserPlugin::getTriggerChars()}.\n\t * \n\t * @return array\n\t */\n\tpublic function getTriggerChars()\n\t\t{\n\t\treturn array(\"\\\"\", \"'\", \"\\n\");\n\t\t}\n\t/**\n\t * Implements {@link aCssParserPlugin::getTriggerStates()}.\n\t * \n\t * @return array\n\t */\n\tpublic function getTriggerStates()\n\t\t{\n\t\treturn false;\n\t\t}\n\t/**\n\t * Implements {@link aCssParserPlugin::parse()}.\n\t * \n\t * @param integer $index Current index\n\t * @param string $char Current char\n\t * @param string $previousChar Previous char\n\t * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing\n\t */\n\tpublic function parse($index, $char, $previousChar, $state)\n\t\t{\n\t\t// Start of string\n\t\tif (($char === \"\\\"\" || $char === \"'\") && $state !== \"T_STRING\")\n\t\t\t{\n\t\t\t$this->delimiterChar = $char;\n\t\t\t$this->parser->pushState(\"T_STRING\");\n\t\t\t$this->parser->setExclusive(__CLASS__);\n\t\t\t}\n\t\t// Escaped LF in string => remove escape backslash and LF\n\t\telseif ($char === \"\\n\" && $previousChar === \"\\\\\" && $state === \"T_STRING\")\n\t\t\t{\n\t\t\t$this->parser->setBuffer(substr($this->parser->getBuffer(), 0, -2));\n\t\t\t}\n\t\t// Parse error: Unescaped LF in string literal\n\t\telseif ($char === \"\\n\" && $previousChar !== \"\\\\\" && $state === \"T_STRING\")\n\t\t\t{\n\t\t\t$line = $this->parser->getBuffer();\n\t\t\t$this->parser->popState();\n\t\t\t$this->parser->unsetExclusive();\n\t\t\t$this->parser->setBuffer(substr($this->parser->getBuffer(), 0, -1) . $this->delimiterChar); // Replace the LF with the current string char\n\t\t\tCssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . \": Unterminated string literal\", $line . \"_\"));\n\t\t\t$this->delimiterChar = null;\n\t\t\t}\n\t\t// End of string\n\t\telseif ($char === $this->delimiterChar && $state === \"T_STRING\")\n\t\t\t{\n\t\t\t// If the Previous char is a escape char count the amount of the previous escape chars. If the amount of \n\t\t\t// escape chars is uneven do not end the string\n\t\t\tif ($previousChar == \"\\\\\")\n\t\t\t\t{\n\t\t\t\t$source\t= $this->parser->getSource();\n\t\t\t\t$c\t\t= 1;\n\t\t\t\t$i\t\t= $index - 2;\n\t\t\t\twhile (substr($source, $i, 1) === \"\\\\\")\n\t\t\t\t\t{\n\t\t\t\t\t$c++; $i--;\n\t\t\t\t\t}\n\t\t\t\tif ($c % 2)\n\t\t\t\t\t{\n\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t$this->parser->popState();\n\t\t\t$this->parser->unsetExclusive();\n\t\t\t$this->delimiterChar = null;\n\t\t\t}\n\t\telse\n\t\t\t{\n\t\t\treturn false;\n\t\t\t}\n\t\treturn true;\n\t\t}\n\t}\n\n/**\n * This {@link aCssMinifierFilter minifier filter} sorts the ruleset declarations of a ruleset by name.\n * \n * @package\t\tCssMin/Minifier/Filters\n * @link\t\thttp://code.google.com/p/cssmin/\n * @author\t\tRowan Beentje <http://assanka.net>\n * @copyright\tRowan Beentje <http://assanka.net>\n * @license\t\thttp://opensource.org/licenses/mit-license.php MIT License\n * @version\t\t3.0.1\n */\nclass CssSortRulesetPropertiesMinifierFilter extends aCssMinifierFilter\n\t{\n\t/**\n\t * Implements {@link aCssMinifierFilter::filter()}.\n\t * \n\t * @param array $tokens Array of objects of type aCssToken\n\t * @return integer Count of added, changed or removed tokens; a return value larger than 0 will rebuild the array\n\t */\n\tpublic function apply(array &$tokens)\n\t\t{\n\t\t$r = 0;\n\t\tfor ($i = 0, $l = count($tokens); $i < $l; $i++)\n\t\t\t{\n\t\t\t// Only look for ruleset start rules\n\t\t\tif (get_class($tokens[$i]) !== \"CssRulesetStartToken\") { continue; }\n\t\t\t// Look for the corresponding ruleset end\n\t\t\t$endIndex = false;\n\t\t\tfor ($ii = $i + 1; $ii < $l; $ii++)\n\t\t\t\t{\n\t\t\t\tif (get_class($tokens[$ii]) !== \"CssRulesetEndToken\") { continue; }\n\t\t\t\t$endIndex = $ii;\n\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\tif (!$endIndex) { break; }\n\t\t\t$startIndex = $i;\n\t\t\t$i = $endIndex;\n\t\t\t// Skip if there's only one token in this ruleset\n\t\t\tif ($endIndex - $startIndex <= 2) { continue; }\n\t\t\t// Ensure that everything between the start and end is a declaration token, for safety\n\t\t\tfor ($ii = $startIndex + 1; $ii < $endIndex; $ii++)\n\t\t\t\t{\n\t\t\t\tif (get_class($tokens[$ii]) !== \"CssRulesetDeclarationToken\") { continue(2); }\n\t\t\t\t}\n\t\t\t$declarations = array_slice($tokens, $startIndex + 1, $endIndex - $startIndex - 1);\n\t\t\t// Check whether a sort is required\n\t\t\t$sortRequired = $lastPropertyName = false;\n\t\t\tforeach ($declarations as $declaration)\t\n\t\t\t\t{\n\t\t\t\tif ($lastPropertyName)\n\t\t\t\t\t{\n\t\t\t\t\tif (strcmp($lastPropertyName, $declaration->Property) > 0)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t$sortRequired = true;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t$lastPropertyName = $declaration->Property;\n\t\t\t\t}\n\t\t\tif (!$sortRequired) { continue; }\n\t\t\t// Arrange the declarations alphabetically by name\n\t\t\tusort($declarations, array(__CLASS__, \"userDefinedSort1\"));\n\t\t\t// Update \"IsLast\" property\n\t\t\tfor ($ii = 0, $ll = count($declarations) - 1; $ii <= $ll; $ii++)\n\t\t\t\t{\n\t\t\t\tif ($ii == $ll)\n\t\t\t\t\t{\n\t\t\t\t\t$declarations[$ii]->IsLast = true;\n\t\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t$declarations[$ii]->IsLast = false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t// Splice back into the array.\n\t\t\tarray_splice($tokens, $startIndex + 1, $endIndex - $startIndex - 1, $declarations);\n\t\t\t$r += $endIndex - $startIndex - 1;\n\t\t\t}\n\t\treturn $r;\n\t\t}\n\t/**\n\t * User defined sort function.\n\t * \n\t * @return integer\n\t */\n\tpublic static function userDefinedSort1($a, $b)\n\t\t{\n\t\treturn strcmp($a->Property, $b->Property);\n\t\t}\n\t}\n\n/**\n * This {@link aCssToken CSS token} represents the start of a ruleset.\n * \n * @package\t\tCssMin/Tokens\n * @link\t\thttp://code.google.com/p/cssmin/\n * @author\t\tJoe Scylla <joe.scylla@gmail.com>\n * @copyright\t2008 - 2011 Joe Scylla <joe.scylla@gmail.com>\n * @license\t\thttp://opensource.org/licenses/mit-license.php MIT License\n * @version\t\t3.0.1\n */\nclass CssRulesetStartToken extends aCssRulesetStartToken\n\t{\n\t/**\n\t * Array of selectors.\n\t * \n\t * @var array\n\t */\n\tpublic $Selectors = array();\n\t/**\n\t * Set the properties of a ruleset token.\n\t * \n\t * @param array $selectors Selectors of the ruleset \n\t * @return void\n\t */\n\tpublic function __construct(array $selectors = array())\n\t\t{\n\t\t$this->Selectors = $selectors;\n\t\t}\n\t/**\n\t * Implements {@link aCssToken::__toString()}.\n\t * \n\t * @return string\n\t */\n\tpublic function __toString()\n\t\t{\n\t\treturn implode(\",\", $this->Selectors) . \"{\";\n\t\t}\n\t}\n\n/**\n * {@link aCssParserPlugin Parser plugin} for parsing ruleset block with including declarations.\n * \n * Found rulesets will add a {@link CssRulesetStartToken} and {@link CssRulesetEndToken} to the \n * parser; including declarations as {@link CssRulesetDeclarationToken}.\n *\n * @package\t\tCssMin/Parser/Plugins\n * @link\t\thttp://code.google.com/p/cssmin/\n * @author\t\tJoe Scylla <joe.scylla@gmail.com>\n * @copyright\t2008 - 2011 Joe Scylla <joe.scylla@gmail.com>\n * @license\t\thttp://opensource.org/licenses/mit-license.php MIT License\n * @version\t\t3.0.1\n */\nclass CssRulesetParserPlugin extends aCssParserPlugin\n\t{\n\t/**\n\t * Implements {@link aCssParserPlugin::getTriggerChars()}.\n\t * \n\t * @return array\n\t */\n\tpublic function getTriggerChars()\n\t\t{\n\t\treturn array(\",\", \"{\", \"}\", \":\", \";\");\n\t\t}\n\t/**\n\t * Implements {@link aCssParserPlugin::getTriggerStates()}.\n\t * \n\t * @return array\n\t */\n\tpublic function getTriggerStates()\n\t\t{\n\t\treturn array(\"T_DOCUMENT\", \"T_AT_MEDIA\", \"T_RULESET::SELECTORS\", \"T_RULESET\", \"T_RULESET_DECLARATION\");\n\t\t}\n\t/**\n\t * Selectors.\n\t * \n\t * @var array\n\t */\n\tprivate $selectors = array();\n\t/**\n\t * Implements {@link aCssParserPlugin::parse()}.\n\t * \n\t * @param integer $index Current index\n\t * @param string $char Current char\n\t * @param string $previousChar Previous char\n\t * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing\n\t */\n\tpublic function parse($index, $char, $previousChar, $state)\n\t\t{\n\t\t// Start of Ruleset and selectors\n\t\tif ($char === \",\" && ($state === \"T_DOCUMENT\" || $state === \"T_AT_MEDIA\" || $state === \"T_RULESET::SELECTORS\"))\n\t\t\t{\n\t\t\tif ($state !== \"T_RULESET::SELECTORS\")\n\t\t\t\t{\n\t\t\t\t$this->parser->pushState(\"T_RULESET::SELECTORS\");\n\t\t\t\t}\n\t\t\t$this->selectors[] = $this->parser->getAndClearBuffer(\",{\");\n\t\t\t}\n\t\t// End of selectors and start of declarations\n\t\telseif ($char === \"{\" && ($state === \"T_DOCUMENT\" || $state === \"T_AT_MEDIA\" || $state === \"T_RULESET::SELECTORS\"))\n\t\t\t{\n\t\t\tif ($this->parser->getBuffer() !== \"\")\n\t\t\t\t{\n\t\t\t\t$this->selectors[] = $this->parser->getAndClearBuffer(\",{\");\n\t\t\t\tif ($state == \"T_RULESET::SELECTORS\")\n\t\t\t\t\t{\n\t\t\t\t\t$this->parser->popState();\n\t\t\t\t\t}\n\t\t\t\t$this->parser->pushState(\"T_RULESET\");\n\t\t\t\t$this->parser->appendToken(new CssRulesetStartToken($this->selectors));\n\t\t\t\t$this->selectors = array();\n\t\t\t\t}\n\t\t\t}\n\t\t// Start of declaration\n\t\telseif ($char === \":\" && $state === \"T_RULESET\")\n\t\t\t{\n\t\t\t$this->parser->pushState(\"T_RULESET_DECLARATION\");\n\t\t\t$this->buffer = $this->parser->getAndClearBuffer(\":;\", true);\n\t\t\t}\n\t\t// Unterminated ruleset declaration\n\t\telseif ($char === \":\" && $state === \"T_RULESET_DECLARATION\")\n\t\t\t{\n\t\t\t// Ignore Internet Explorer filter declarations\n\t\t\tif ($this->buffer === \"filter\")\n\t\t\t\t{\n\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\tCssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . \": Unterminated declaration\", $this->buffer . \":\" . $this->parser->getBuffer() . \"_\"));\n\t\t\t}\n\t\t// End of declaration\n\t\telseif (($char === \";\" || $char === \"}\") && $state === \"T_RULESET_DECLARATION\")\n\t\t\t{\n\t\t\t$value = $this->parser->getAndClearBuffer(\";}\");\n\t\t\tif (strtolower(substr($value, -10, 10)) === \"!important\")\n\t\t\t\t{\n\t\t\t\t$value = trim(substr($value, 0, -10));\n\t\t\t\t$isImportant = true;\n\t\t\t\t}\n\t\t\telse\n\t\t\t\t{\n\t\t\t\t$isImportant = false;\n\t\t\t\t}\n\t\t\t$this->parser->popState();\n\t\t\t$this->parser->appendToken(new CssRulesetDeclarationToken($this->buffer, $value, $this->parser->getMediaTypes(), $isImportant));\n\t\t\t// Declaration ends with a right curly brace; so we have to end the ruleset\n\t\t\tif ($char === \"}\")\n\t\t\t\t{\n\t\t\t\t$this->parser->appendToken(new CssRulesetEndToken());\n\t\t\t\t$this->parser->popState();\n\t\t\t\t}\n\t\t\t$this->buffer = \"\";\n\t\t\t}\n\t\t// End of ruleset\n\t\telseif ($char === \"}\" && $state === \"T_RULESET\")\n\t\t\t{\n\t\t\t$this->parser->popState();\n\t\t\t$this->parser->clearBuffer();\n\t\t\t$this->parser->appendToken(new CssRulesetEndToken());\n\t\t\t$this->buffer = \"\";\n\t\t\t$this->selectors = array();\n\t\t\t}\n\t\telse\n\t\t\t{\n\t\t\treturn false;\n\t\t\t}\n\t\treturn true;\n\t\t}\n\t}\n\n/**\n *  This {@link aCssToken CSS token} represents the end of a ruleset.\n *\n * @package\t\tCssMin/Tokens\n * @link\t\thttp://code.google.com/p/cssmin/\n * @author\t\tJoe Scylla <joe.scylla@gmail.com>\n * @copyright\t2008 - 2011 Joe Scylla <joe.scylla@gmail.com>\n * @license\t\thttp://opensource.org/licenses/mit-license.php MIT License\n * @version\t\t3.0.1\n */\nclass CssRulesetEndToken extends aCssRulesetEndToken\n\t{\n\t\n\t}\n\n/**\n * This {@link aCssToken CSS token} represents a ruleset declaration.\n *\n * @package\t\tCssMin/Tokens\n * @link\t\thttp://code.google.com/p/cssmin/\n * @author\t\tJoe Scylla <joe.scylla@gmail.com>\n * @copyright\t2008 - 2011 Joe Scylla <joe.scylla@gmail.com>\n * @license\t\thttp://opensource.org/licenses/mit-license.php MIT License\n * @version\t\t3.0.1\n */\nclass CssRulesetDeclarationToken extends aCssDeclarationToken\n\t{\n\t/**\n\t * Media types of the declaration.\n\t * \n\t * @var array\n\t */\n\tpublic $MediaTypes = array(\"all\");\n\t/**\n\t * Set the properties of a ddocument- or at-rule @media level declaration. \n\t * \n\t * @param string $property Property of the declaration\n\t * @param string $value Value of the declaration\n\t * @param mixed $mediaTypes Media types of the declaration\n\t * @param boolean $isImportant Is the !important flag is set\n\t * @param boolean $isLast Is the declaration the last one of the ruleset\n\t * @return void\n\t */\n\tpublic function __construct($property, $value, $mediaTypes = null, $isImportant = false, $isLast = false)\n\t\t{\n\t\tparent::__construct($property, $value, $isImportant, $isLast);\n\t\t$this->MediaTypes\t= $mediaTypes ? $mediaTypes : array(\"all\");\n\t\t}\n\t}\n\n/**\n * This {@link aCssMinifierFilter minifier filter} sets the IsLast property of any last declaration in a ruleset, \n * @font-face at-rule or @page at-rule block. If the property IsLast is TRUE the decrations will get stringified \n * without tailing semicolon.\n * \n * @package\t\tCssMin/Minifier/Filters\n * @link\t\thttp://code.google.com/p/cssmin/\n * @author\t\tJoe Scylla <joe.scylla@gmail.com>\n * @copyright\t2008 - 2011 Joe Scylla <joe.scylla@gmail.com>\n * @license\t\thttp://opensource.org/licenses/mit-license.php MIT License\n * @version\t\t3.0.1\n */\nclass CssRemoveLastDelarationSemiColonMinifierFilter extends aCssMinifierFilter\n\t{\n\t/**\n\t * Implements {@link aCssMinifierFilter::filter()}.\n\t * \n\t * @param array $tokens Array of objects of type aCssToken\n\t * @return integer Count of added, changed or removed tokens; a return value large than 0 will rebuild the array\n\t */\n\tpublic function apply(array &$tokens)\n\t\t{\n\t\tfor ($i = 0, $l = count($tokens); $i < $l; $i++)\n\t\t\t{\n\t\t\t$current\t= get_class($tokens[$i]);\n\t\t\t$next\t\t= isset($tokens[$i+1]) ? get_class($tokens[$i+1]) : false;\n\t\t\tif (($current === \"CssRulesetDeclarationToken\" && $next === \"CssRulesetEndToken\") ||\n\t\t\t\t($current === \"CssAtFontFaceDeclarationToken\" && $next === \"CssAtFontFaceEndToken\") || \n\t\t\t\t($current === \"CssAtPageDeclarationToken\" && $next === \"CssAtPageEndToken\"))\n\t\t\t\t{\n\t\t\t\t$tokens[$i]->IsLast = true;\n\t\t\t\t}\n\t\t\t}\n\t\treturn 0;\n\t\t}\n\t}\n\n/**\n * This {@link aCssMinifierFilter minifier filter} will remove any empty rulesets (including @keyframes at-rule block \n * rulesets).\n *\n * @package\t\tCssMin/Minifier/Filters\n * @link\t\thttp://code.google.com/p/cssmin/\n * @author\t\tJoe Scylla <joe.scylla@gmail.com>\n * @copyright\t2008 - 2011 Joe Scylla <joe.scylla@gmail.com>\n * @license\t\thttp://opensource.org/licenses/mit-license.php MIT License\n * @version\t\t3.0.1\n */\nclass CssRemoveEmptyRulesetsMinifierFilter extends aCssMinifierFilter\n\t{\n\t/**\n\t * Implements {@link aCssMinifierFilter::filter()}.\n\t * \n\t * @param array $tokens Array of objects of type aCssToken\n\t * @return integer Count of added, changed or removed tokens; a return value large than 0 will rebuild the array\n\t */\n\tpublic function apply(array &$tokens)\n\t\t{\n\t\t$r = 0;\n\t\tfor ($i = 0, $l = count($tokens); $i < $l; $i++)\n\t\t\t{\n\t\t\t$current\t= get_class($tokens[$i]);\n\t\t\t$next\t\t= isset($tokens[$i + 1]) ? get_class($tokens[$i + 1]) : false;\n\t\t\tif (($current === \"CssRulesetStartToken\" && $next === \"CssRulesetEndToken\") ||\n\t\t\t\t($current === \"CssAtKeyframesRulesetStartToken\" && $next === \"CssAtKeyframesRulesetEndToken\" && !array_intersect(array(\"from\", \"0%\", \"to\", \"100%\"), array_map(\"strtolower\", $tokens[$i]->Selectors)))\n\t\t\t\t)\n\t\t\t\t{\n\t\t\t\t$tokens[$i]\t\t= null;\n\t\t\t\t$tokens[$i + 1]\t= null;\n\t\t\t\t$i++;\n\t\t\t\t$r = $r + 2;\n\t\t\t\t}\n\t\t\t}\n\t\treturn $r;\n\t\t}\n\t}\n\n/**\n * This {@link aCssMinifierFilter minifier filter} will remove any empty @font-face, @keyframes, @media and @page \n * at-rule blocks.\n * \n * @package\t\tCssMin/Minifier/Filters\n * @link\t\thttp://code.google.com/p/cssmin/\n * @author\t\tJoe Scylla <joe.scylla@gmail.com>\n * @copyright\t2008 - 2011 Joe Scylla <joe.scylla@gmail.com>\n * @license\t\thttp://opensource.org/licenses/mit-license.php MIT License\n * @version\t\t3.0.1\n */\nclass CssRemoveEmptyAtBlocksMinifierFilter extends aCssMinifierFilter\n\t{\n\t/**\n\t * Implements {@link aCssMinifierFilter::filter()}.\n\t * \n\t * @param array $tokens Array of objects of type aCssToken\n\t * @return integer Count of added, changed or removed tokens; a return value large than 0 will rebuild the array\n\t */\n\tpublic function apply(array &$tokens)\n\t\t{\n\t\t$r = 0;\n\t\tfor ($i = 0, $l = count($tokens); $i < $l; $i++)\n\t\t\t{\n\t\t\t$current\t= get_class($tokens[$i]);\n\t\t\t$next\t\t= isset($tokens[$i + 1]) ? get_class($tokens[$i + 1]) : false;\n\t\t\tif (($current === \"CssAtFontFaceStartToken\" && $next === \"CssAtFontFaceEndToken\") ||\n\t\t\t\t($current === \"CssAtKeyframesStartToken\" && $next === \"CssAtKeyframesEndToken\") ||\n\t\t\t\t($current === \"CssAtPageStartToken\" && $next === \"CssAtPageEndToken\") ||\n\t\t\t\t($current === \"CssAtMediaStartToken\" && $next === \"CssAtMediaEndToken\"))\n\t\t\t\t{\n\t\t\t\t$tokens[$i]\t\t= null;\n\t\t\t\t$tokens[$i + 1]\t= null;\n\t\t\t\t$i++;\n\t\t\t\t$r = $r + 2;\n\t\t\t\t}\n\t\t\t}\n\t\treturn $r;\n\t\t}\n\t}\n\n/**\n * This {@link aCssMinifierFilter minifier filter} will remove any comments from the array of parsed tokens.\n * \n * @package\t\tCssMin/Minifier/Filters\n * @link\t\thttp://code.google.com/p/cssmin/\n * @author\t\tJoe Scylla <joe.scylla@gmail.com>\n * @copyright\t2008 - 2011 Joe Scylla <joe.scylla@gmail.com>\n * @license\t\thttp://opensource.org/licenses/mit-license.php MIT License\n * @version\t\t3.0.1\n */\nclass CssRemoveCommentsMinifierFilter extends aCssMinifierFilter\n\t{\n\t/**\n\t * Implements {@link aCssMinifierFilter::filter()}.\n\t * \n\t * @param array $tokens Array of objects of type aCssToken\n\t * @return integer Count of added, changed or removed tokens; a return value large than 0 will rebuild the array\n\t */\n\tpublic function apply(array &$tokens)\n\t\t{\n\t\t$r = 0;\n\t\tfor ($i = 0, $l = count($tokens); $i < $l; $i++)\n\t\t\t{\n\t\t\tif (get_class($tokens[$i]) === \"CssCommentToken\")\n\t\t\t\t{\n\t\t\t\t$tokens[$i] = null;\n\t\t\t\t$r++;\n\t\t\t\t}\n\t\t\t}\n\t\treturn $r;\n\t\t}\n\t}\n\n/**\n * CSS Parser.\n * \n * @package\t\tCssMin/Parser\n * @link\t\thttp://code.google.com/p/cssmin/\n * @author\t\tJoe Scylla <joe.scylla@gmail.com>\n * @copyright\t2008 - 2011 Joe Scylla <joe.scylla@gmail.com>\n * @license\t\thttp://opensource.org/licenses/mit-license.php MIT License\n * @version\t\t3.0.1\n */\nclass CssParser\n\t{\n\t/**\n\t * Parse buffer.\n\t * \n\t * @var string\n\t */\n\tprivate $buffer = \"\";\n\t/**\n\t * {@link aCssParserPlugin Plugins}.\n\t * \n\t * @var array\n\t */\n\tprivate $plugins = array();\n\t/**\n\t * Source to parse.\n\t * \n\t * @var string\n\t */\n\tprivate $source = \"\";\n\t/**\n\t * Current state.\n\t * \n\t * @var integer\n\t */\n\tprivate $state = \"T_DOCUMENT\";\n\t/**\n\t * Exclusive state.\n\t * \n\t * @var string\n\t */\n\tprivate $stateExclusive = false;\n\t/**\n\t * Media types state.\n\t * \n\t * @var mixed\n\t */\n\tprivate $stateMediaTypes = false;\n\t/**\n\t * State stack.\n\t * \n\t * @var array\n\t */\n\tprivate $states = array(\"T_DOCUMENT\");\n\t/**\n\t * Parsed tokens.\n\t * \n\t * @var array\n\t */\n\tprivate $tokens = array();\n\t/**\n\t * Constructer.\n\t * \n\t *  Create instances of the used {@link aCssParserPlugin plugins}.\n\t * \n\t * @param string $source CSS source [optional]\n\t * @param array $plugins Plugin configuration [optional]\n\t * @return void\n\t */\n\tpublic function __construct($source = null, array $plugins = null)\n\t\t{\n\t\t$plugins = array_merge(array\n\t\t\t(\n\t\t\t\"Comment\"\t\t=> true,\n\t\t\t\"String\"\t\t=> true,\n\t\t\t\"Url\"\t\t\t=> true,\n\t\t\t\"Expression\"\t=> true,\n\t\t\t\"Ruleset\"\t\t=> true,\n\t\t\t\"AtCharset\"\t\t=> true,\n\t\t\t\"AtFontFace\"\t=> true,\n\t\t\t\"AtImport\"\t\t=> true,\n\t\t\t\"AtKeyframes\"\t=> true,\n\t\t\t\"AtMedia\"\t\t=> true,\n\t\t\t\"AtPage\"\t\t=> true,\n\t\t\t\"AtVariables\"\t=> true\n\t\t\t), is_array($plugins) ? $plugins : array());\n\t\t// Create plugin instances\n\t\tforeach ($plugins as $name => $config)\n\t\t\t{\n\t\t\tif ($config !== false)\n\t\t\t\t{\n\t\t\t\t$class\t= \"Css\" . $name . \"ParserPlugin\";\n\t\t\t\t$config = is_array($config) ? $config : array();\n\t\t\t\tif (class_exists($class))\n\t\t\t\t\t{\n\t\t\t\t\t$this->plugins[] = new $class($this, $config);\n\t\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\tCssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . \": The plugin <code>\" . $name . \"</code> with the class name <code>\" . $class . \"</code> was not found\"));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\tif (!is_null($source))\n\t\t\t{\n\t\t\t$this->parse($source);\n\t\t\t}\n\t\t}\n\t/**\n\t * Append a token to the array of tokens.\n\t * \n\t * @param aCssToken $token Token to append\n\t * @return void\n\t */\n\tpublic function appendToken(aCssToken $token)\n\t\t{\n\t\t$this->tokens[] = $token;\n\t\t}\n\t/**\n\t * Clears the current buffer.\n\t * \n\t * @return void\n\t */\n\tpublic function clearBuffer()\n\t\t{\n\t\t$this->buffer = \"\";\n\t\t}\n\t/**\n\t * Returns and clear the current buffer.\n\t * \n\t * @param string $trim Chars to use to trim the returned buffer\n\t * @param boolean $tolower if TRUE the returned buffer will get converted to lower case\n\t * @return string\n\t */\n\tpublic function getAndClearBuffer($trim = \"\", $tolower = false)\n\t\t{\n\t\t$r = $this->getBuffer($trim, $tolower);\n\t\t$this->buffer = \"\";\n\t\treturn $r;\n\t\t}\n\t/**\n\t * Returns the current buffer.\n\t * \n\t * @param string $trim Chars to use to trim the returned buffer\n\t * @param boolean $tolower if TRUE the returned buffer will get converted to lower case\n\t * @return string\n\t */\n\tpublic function getBuffer($trim = \"\", $tolower = false)\n\t\t{\n\t\t$r = $this->buffer;\n\t\tif ($trim)\n\t\t\t{\n\t\t\t$r = trim($r, \" \\t\\n\\r\\0\\x0B\" . $trim);\n\t\t\t}\n\t\tif ($tolower)\n\t\t\t{\n\t\t\t$r = strtolower($r);\n\t\t\t}\n\t\treturn $r;\n\t\t}\n\t/**\n\t * Returns the current media types state.\n\t * \n\t * @return array\n\t */\t\n\tpublic function getMediaTypes()\n\t\t{\n\t\treturn $this->stateMediaTypes;\n\t\t}\n\t/**\n\t * Returns the CSS source.\n\t * \n\t * @return string\n\t */\n\tpublic function getSource()\n\t\t{\n\t\treturn $this->source;\n\t\t}\n\t/**\n\t * Returns the current state.\n\t * \n\t * @return integer The current state\n\t */\n\tpublic function getState()\n\t\t{\n\t\treturn $this->state;\n\t\t}\n\t/**\n\t * Returns a plugin by class name.\n\t * \n\t * @param string $name Class name of the plugin \n\t * @return aCssParserPlugin\n\t */\n\tpublic function getPlugin($class)\n\t\t{\n\t\tstatic $index = null;\n\t\tif (is_null($index))\n\t\t\t{\n\t\t\t$index = array();\n\t\t\tfor ($i = 0, $l = count($this->plugins); $i < $l; $i++)\n\t\t\t\t{\n\t\t\t\t$index[get_class($this->plugins[$i])] = $i;\n\t\t\t\t}\n\t\t\t}\n\t\treturn isset($index[$class]) ? $this->plugins[$index[$class]] : false;\n\t\t}\n\t/**\n\t * Returns the parsed tokens.\n\t * \n\t * @return array\n\t */\n\tpublic function getTokens()\n\t\t{\n\t\treturn $this->tokens;\n\t\t}\n\t/**\n\t * Returns if the current state equals the passed state.\n\t * \n\t * @param integer $state State to compare with the current state\n\t * @return boolean TRUE is the state equals to the passed state; FALSE if not\n\t */\n\tpublic function isState($state)\n\t\t{\n\t\treturn ($this->state == $state);\n\t\t}\n\t/**\n\t * Parse the CSS source and return a array with parsed tokens.\n\t * \n\t * @param string $source CSS source\n\t * @return array Array with tokens\n\t */\n\tpublic function parse($source)\n\t\t{\n\t\t// Reset\n\t\t$this->source = \"\";\n\t\t$this->tokens = array();\n\t\t// Create a global and plugin lookup table for trigger chars; set array of plugins as local variable and create \n\t\t// several helper variables for plugin handling\n\t\t$globalTriggerChars\t\t= \"\";\n\t\t$plugins\t\t\t\t= $this->plugins;\n\t\t$pluginCount\t\t\t= count($plugins);\n\t\t$pluginIndex\t\t\t= array();\n\t\t$pluginTriggerStates\t= array();\n\t\t$pluginTriggerChars\t\t= array();\n\t\tfor ($i = 0, $l = count($plugins); $i < $l; $i++)\n\t\t\t{\n\t\t\t$tPluginClassName\t\t\t\t= get_class($plugins[$i]);\n\t\t\t$pluginTriggerChars[$i]\t\t\t= implode(\"\", $plugins[$i]->getTriggerChars());\n\t\t\t$tPluginTriggerStates\t\t\t= $plugins[$i]->getTriggerStates();\n\t\t\t$pluginTriggerStates[$i]\t\t= $tPluginTriggerStates === false ? false : \"|\" . implode(\"|\", $tPluginTriggerStates) . \"|\";\n\t\t\t$pluginIndex[$tPluginClassName]\t= $i;\n\t\t\tfor ($ii = 0, $ll = strlen($pluginTriggerChars[$i]); $ii < $ll; $ii++)\n\t\t\t\t{\n\t\t\t\t$c = substr($pluginTriggerChars[$i], $ii, 1);\n\t\t\t\tif (strpos($globalTriggerChars, $c) === false)\n\t\t\t\t\t{\n\t\t\t\t\t$globalTriggerChars .= $c;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t// Normalise line endings\n\t\t$source\t\t\t= str_replace(\"\\r\\n\", \"\\n\", $source);\t// Windows to Unix line endings\n\t\t$source\t\t\t= str_replace(\"\\r\", \"\\n\", $source);\t\t// Mac to Unix line endings\n\t\t$this->source\t= $source;\n\t\t// Variables\n\t\t$buffer\t\t\t= &$this->buffer;\n\t\t$exclusive\t\t= &$this->stateExclusive;\n\t\t$state\t\t\t= &$this->state;\n\t\t$c = $p \t\t= null;\n\t\t// --\n\t\tfor ($i = 0, $l = strlen($source); $i < $l; $i++)\n\t\t\t{\n\t\t\t// Set the current Char\n\t\t\t$c = $source[$i]; // Is faster than: $c = substr($source, $i, 1);\n\t\t\t// Normalize and filter double whitespace characters\n\t\t\tif ($exclusive === false)\n\t\t\t\t{\n\t\t\t\tif ($c === \"\\n\" || $c === \"\\t\")\n\t\t\t\t\t{\n\t\t\t\t\t$c = \" \";\n\t\t\t\t\t}\n\t\t\t\tif ($c === \" \" && $p === \" \")\n\t\t\t\t\t{\n\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t$buffer .= $c;\n\t\t\t// Extended processing only if the current char is a global trigger char\n\t\t\tif (strpos($globalTriggerChars, $c) !== false)\n\t\t\t\t{\n\t\t\t\t// Exclusive state is set; process with the exclusive plugin \n\t\t\t\tif ($exclusive)\n\t\t\t\t\t{\n\t\t\t\t\t$tPluginIndex = $pluginIndex[$exclusive];\n\t\t\t\t\tif (strpos($pluginTriggerChars[$tPluginIndex], $c) !== false && ($pluginTriggerStates[$tPluginIndex] === false || strpos($pluginTriggerStates[$tPluginIndex], $state) !== false))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t$r = $plugins[$tPluginIndex]->parse($i, $c, $p, $state);\n\t\t\t\t\t\t// Return value is TRUE => continue with next char\n\t\t\t\t\t\tif ($r === true)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t// Return value is numeric => set new index and continue with next char\n\t\t\t\t\t\telseif ($r !== false && $r != $i)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$i = $r;\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t// Else iterate through the plugins\n\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t$triggerState = \"|\" . $state . \"|\";\n\t\t\t\t\tfor ($ii = 0, $ll = $pluginCount; $ii < $ll; $ii++)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t// Only process if the current char is one of the plugin trigger chars\n\t\t\t\t\t\tif (strpos($pluginTriggerChars[$ii], $c) !== false && ($pluginTriggerStates[$ii] === false || strpos($pluginTriggerStates[$ii], $triggerState) !== false))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// Process with the plugin\n\t\t\t\t\t\t\t$r = $plugins[$ii]->parse($i, $c, $p, $state);\n\t\t\t\t\t\t\t// Return value is TRUE => break the plugin loop and and continue with next char\n\t\t\t\t\t\t\tif ($r === true)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t// Return value is numeric => set new index, break the plugin loop and and continue with next char\n\t\t\t\t\t\t\telseif ($r !== false && $r != $i)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t$i = $r;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t$p = $c; // Set the parent char\n\t\t\t}\n\t\treturn $this->tokens;\n\t\t}\n\t/**\n\t * Remove the last state of the state stack and return the removed stack value.\n\t * \n\t * @return integer Removed state value\n\t */\n\tpublic function popState()\n\t\t{\n\t\t$r = array_pop($this->states);\n\t\t$this->state = $this->states[count($this->states) - 1];\n\t\treturn $r;\n\t\t}\n\t/**\n\t * Adds a new state onto the state stack.\n\t * \n\t * @param integer $state State to add onto the state stack.\n\t * @return integer The index of the added state in the state stacks\n\t */\n\tpublic function pushState($state)\n\t\t{\n\t\t$r = array_push($this->states, $state);\n\t\t$this->state = $this->states[count($this->states) - 1];\n\t\treturn $r;\n\t\t}\n\t/**\n\t * Sets/restores the buffer.\n\t * \n\t * @param string $buffer Buffer to set\n\t * @return void\n\t */\t\n\tpublic function setBuffer($buffer)\n\t\t{\n\t\t$this->buffer = $buffer;\n\t\t}\n\t/**\n\t * Set the exclusive state.\n\t * \n\t * @param string $exclusive Exclusive state\n\t * @return void\n\t */\t\n\tpublic function setExclusive($exclusive)\n\t\t{\n\t\t$this->stateExclusive = $exclusive; \n\t\t}\n\t/**\n\t * Set the media types state.\n\t * \n\t * @param array $mediaTypes Media types state\n\t * @return void\n\t */\t\n\tpublic function setMediaTypes(array $mediaTypes)\n\t\t{\n\t\t$this->stateMediaTypes = $mediaTypes; \n\t\t}\n\t/**\n\t * Sets the current state in the state stack; equals to {@link CssParser::popState()} + {@link CssParser::pushState()}.\n\t * \n\t * @param integer $state State to set\n\t * @return integer\n\t */\n\tpublic function setState($state)\n\t\t{\n\t\t$r = array_pop($this->states);\n\t\tarray_push($this->states, $state);\n\t\t$this->state = $this->states[count($this->states) - 1];\n\t\treturn $r;\n\t\t}\n\t/**\n\t * Removes the exclusive state.\n\t * \n\t * @return void\n\t */\n\tpublic function unsetExclusive()\n\t\t{\n\t\t$this->stateExclusive = false;\n\t\t}\n\t/**\n\t * Removes the media types state.\n\t * \n\t * @return void\n\t */\n\tpublic function unsetMediaTypes()\n\t\t{\n\t\t$this->stateMediaTypes = false;\n\t\t}\n\t}\n\n/**\n * {@link aCssFromatter Formatter} returning the CSS source in {@link http://goo.gl/j4XdU OTBS indent style} (The One True Brace Style).\n * \n * @package\t\tCssMin/Formatter\n * @link\t\thttp://code.google.com/p/cssmin/\n * @author\t\tJoe Scylla <joe.scylla@gmail.com>\n * @copyright\t2008 - 2011 Joe Scylla <joe.scylla@gmail.com>\n * @license\t\thttp://opensource.org/licenses/mit-license.php MIT License\n * @version\t\t3.0.1\n */\nclass CssOtbsFormatter extends aCssFormatter\n\t{\n\t/**\n\t * Implements {@link aCssFormatter::__toString()}.\n\t * \n\t * @return string\n\t */\n\tpublic function __toString()\n\t\t{\n\t\t$r\t\t\t\t= array();\n\t\t$level\t\t\t= 0;\n\t\tfor ($i = 0, $l = count($this->tokens); $i < $l; $i++)\n\t\t\t{\n\t\t\t$token\t\t= $this->tokens[$i];\n\t\t\t$class\t\t= get_class($token);\n\t\t\t$indent \t= str_repeat($this->indent, $level);\n\t\t\tif ($class === \"CssCommentToken\")\n\t\t\t\t{\n\t\t\t\t$lines = array_map(\"trim\", explode(\"\\n\", $token->Comment));\n\t\t\t\tfor ($ii = 0, $ll = count($lines); $ii < $ll; $ii++)\n\t\t\t\t\t{\n\t\t\t\t\t$r[] = $indent . (substr($lines[$ii], 0, 1) == \"*\" ? \" \" : \"\") . $lines[$ii];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\telseif ($class === \"CssAtCharsetToken\")\n\t\t\t\t{\n\t\t\t\t$r[] = $indent . \"@charset \" . $token->Charset . \";\";\n\t\t\t\t}\n\t\t\telseif ($class === \"CssAtFontFaceStartToken\")\n\t\t\t\t{\n\t\t\t\t$r[] = $indent . \"@font-face {\";\n\t\t\t\t$level++;\n\t\t\t\t}\n\t\t\telseif ($class === \"CssAtImportToken\")\n\t\t\t\t{\n\t\t\t\t$r[] = $indent . \"@import \" . $token->Import . \" \" . implode(\", \", $token->MediaTypes) . \";\";\n\t\t\t\t}\n\t\t\telseif ($class === \"CssAtKeyframesStartToken\")\n\t\t\t\t{\n\t\t\t\t$r[] = $indent . \"@keyframes \\\"\" . $token->Name . \"\\\" {\";\n\t\t\t\t$level++;\n\t\t\t\t}\n\t\t\telseif ($class === \"CssAtMediaStartToken\")\n\t\t\t\t{\n\t\t\t\t$r[] = $indent . \"@media \" . implode(\", \", $token->MediaTypes) . \" {\";\n\t\t\t\t$level++;\n\t\t\t\t}\n\t\t\telseif ($class === \"CssAtPageStartToken\")\n\t\t\t\t{\n\t\t\t\t$r[] = $indent . \"@page {\";\n\t\t\t\t$level++;\n\t\t\t\t}\n\t\t\telseif ($class === \"CssAtVariablesStartToken\")\n\t\t\t\t{\n\t\t\t\t$r[] = $indent . \"@variables \" . implode(\", \", $token->MediaTypes) . \" {\";\n\t\t\t\t$level++;\n\t\t\t\t}\n\t\t\telseif ($class === \"CssRulesetStartToken\" || $class === \"CssAtKeyframesRulesetStartToken\")\n\t\t\t\t{\n\t\t\t\t$r[] = $indent . implode(\", \", $token->Selectors) . \" {\";\n\t\t\t\t$level++;\n\t\t\t\t}\n\t\t\telseif ($class == \"CssAtFontFaceDeclarationToken\"\n\t\t\t\t|| $class === \"CssAtKeyframesRulesetDeclarationToken\"\n\t\t\t\t|| $class === \"CssAtPageDeclarationToken\"\n\t\t\t\t|| $class == \"CssAtVariablesDeclarationToken\"\n\t\t\t\t|| $class === \"CssRulesetDeclarationToken\"\n\t\t\t\t)\n\t\t\t\t{\n\t\t\t\t$declaration = $indent . $token->Property . \": \";\n\t\t\t\tif ($this->padding)\n\t\t\t\t\t{\n\t\t\t\t\t$declaration = str_pad($declaration, $this->padding, \" \", STR_PAD_RIGHT);\n\t\t\t\t\t}\n\t\t\t\t$r[] = $declaration . $token->Value . ($token->IsImportant ? \" !important\" : \"\") . \";\";\n\t\t\t\t}\n\t\t\telseif ($class === \"CssAtFontFaceEndToken\"\n\t\t\t\t|| $class === \"CssAtMediaEndToken\"\n\t\t\t\t|| $class === \"CssAtKeyframesEndToken\"\n\t\t\t\t|| $class === \"CssAtKeyframesRulesetEndToken\"\n\t\t\t\t|| $class === \"CssAtPageEndToken\"\n\t\t\t\t|| $class === \"CssAtVariablesEndToken\"\n\t\t\t\t|| $class === \"CssRulesetEndToken\"\n\t\t\t\t)\n\t\t\t\t{\n\t\t\t\t$level--;\n\t\t\t\t$r[] = str_repeat($indent, $level) . \"}\";\n\t\t\t\t}\n\t\t\t}\n\t\treturn implode(\"\\n\", $r);\n\t\t}\n\t}\n\n/**\n * This {@link aCssToken CSS token} is a utility token that extends {@link aNullToken} and returns only a empty string.\n *\n * @package\t\tCssMin/Tokens\n * @link\t\thttp://code.google.com/p/cssmin/\n * @author\t\tJoe Scylla <joe.scylla@gmail.com>\n * @copyright\t2008 - 2011 Joe Scylla <joe.scylla@gmail.com>\n * @license\t\thttp://opensource.org/licenses/mit-license.php MIT License\n * @version\t\t3.0.1\n */\nclass CssNullToken extends aCssToken\n\t{\n\t/**\n\t * Implements {@link aCssToken::__toString()}.\n\t * \n\t * @return string\n\t */\n\tpublic function __toString()\n\t\t{\n\t\treturn \"\";\n\t\t}\n\t}\n\n/**\n * CSS Minifier.\n * \n * @package\t\tCssMin/Minifier\n * @link\t\thttp://code.google.com/p/cssmin/\n * @author\t\tJoe Scylla <joe.scylla@gmail.com>\n * @copyright\t2008 - 2011 Joe Scylla <joe.scylla@gmail.com>\n * @license\t\thttp://opensource.org/licenses/mit-license.php MIT License\n * @version\t\t3.0.1\n */\nclass CssMinifier\n\t{\n\t/**\n\t * {@link aCssMinifierFilter Filters}.\n\t *  \n\t * @var array\n\t */\n\tprivate $filters = array();\n\t/**\n\t * {@link aCssMinifierPlugin Plugins}.\n\t * \n\t * @var array\n\t */\n\tprivate $plugins = array();\n\t/**\n\t * Minified source.\n\t * \n\t * @var string\n\t */\n\tprivate $minified = \"\";\n\t/**\n\t * Constructer.\n\t * \n\t * Creates instances of {@link aCssMinifierFilter filters} and {@link aCssMinifierPlugin plugins}.\n\t * \n\t * @param string $source CSS source [optional]\n\t * @param array $filters Filter configuration [optional]\n\t * @param array $plugins Plugin configuration [optional]\n\t * @return void\n\t */\n\tpublic function __construct($source = null, array $filters = null, array $plugins = null)\n\t\t{\n\t\t$filters = array_merge(array\n\t\t\t(\n\t\t\t\"ImportImports\"\t\t\t\t\t=> false,\n\t\t\t\"RemoveComments\"\t\t\t\t=> true, \n\t\t\t\"RemoveEmptyRulesets\"\t\t\t=> true,\n\t\t\t\"RemoveEmptyAtBlocks\"\t\t\t=> true,\n\t\t\t\"ConvertLevel3Properties\"\t\t=> false,\n\t\t\t\"ConvertLevel3AtKeyframes\"\t\t=> false,\n\t\t\t\"Variables\"\t\t\t\t\t\t=> true,\n\t\t\t\"RemoveLastDelarationSemiColon\"\t=> true\n\t\t\t), is_array($filters) ? $filters : array());\n\t\t$plugins = array_merge(array\n\t\t\t(\n\t\t\t\"Variables\"\t\t\t\t\t\t=> true,\n\t\t\t\"ConvertFontWeight\"\t\t\t\t=> false,\n\t\t\t\"ConvertHslColors\"\t\t\t\t=> false,\n\t\t\t\"ConvertRgbColors\"\t\t\t\t=> false,\n\t\t\t\"ConvertNamedColors\"\t\t\t=> false,\n\t\t\t\"CompressColorValues\"\t\t\t=> false,\n\t\t\t\"CompressUnitValues\"\t\t\t=> false,\n\t\t\t\"CompressExpressionValues\"\t\t=> false\n\t\t\t), is_array($plugins) ? $plugins : array());\n\t\t// Filters\n\t\tforeach ($filters as $name => $config)\n\t\t\t{\n\t\t\tif ($config !== false)\n\t\t\t\t{\n\t\t\t\t$class\t= \"Css\" . $name . \"MinifierFilter\";\n\t\t\t\t$config = is_array($config) ? $config : array();\n\t\t\t\tif (class_exists($class))\n\t\t\t\t\t{\n\t\t\t\t\t$this->filters[] = new $class($this, $config);\n\t\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\tCssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . \": The filter <code>\" . $name . \"</code> with the class name <code>\" . $class . \"</code> was not found\"));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t// Plugins\n\t\tforeach ($plugins as $name => $config)\n\t\t\t{\n\t\t\tif ($config !== false)\n\t\t\t\t{\n\t\t\t\t$class\t= \"Css\" . $name . \"MinifierPlugin\";\n\t\t\t\t$config = is_array($config) ? $config : array();\n\t\t\t\tif (class_exists($class))\n\t\t\t\t\t{\n\t\t\t\t\t$this->plugins[] = new $class($this, $config);\n\t\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\tCssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . \": The plugin <code>\" . $name . \"</code> with the class name <code>\" . $class . \"</code> was not found\"));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t// --\n\t\tif (!is_null($source))\n\t\t\t{\n\t\t\t$this->minify($source);\n\t\t\t}\n\t\t}\n\t/**\n\t * Returns the minified Source.\n\t * \n\t * @return string\n\t */\n\tpublic function getMinified()\n\t\t{\n\t\treturn $this->minified;\n\t\t}\n\t/**\n\t * Returns a plugin by class name.\n\t * \n\t * @param string $name Class name of the plugin\n\t * @return aCssMinifierPlugin\n\t */\n\tpublic function getPlugin($class)\n\t\t{\n\t\tstatic $index = null;\n\t\tif (is_null($index))\n\t\t\t{\n\t\t\t$index = array();\n\t\t\tfor ($i = 0, $l = count($this->plugins); $i < $l; $i++)\n\t\t\t\t{\n\t\t\t\t$index[get_class($this->plugins[$i])] = $i;\n\t\t\t\t}\n\t\t\t}\n\t\treturn isset($index[$class]) ? $this->plugins[$index[$class]] : false;\n\t\t}\n\t/**\n\t * Minifies the CSS source.\n\t * \n\t * @param string $source CSS source\n\t * @return string\n\t */\n\tpublic function minify($source)\n\t\t{\n\t\t// Variables\n\t\t$r\t\t\t\t\t\t= \"\";\n\t\t$parser\t\t\t\t\t= new CssParser($source);\n\t\t$tokens\t\t\t\t\t= $parser->getTokens();\n\t\t$filters \t\t\t\t= $this->filters;\n\t\t$filterCount\t\t\t= count($this->filters);\n\t\t$plugins\t\t\t\t= $this->plugins;\n\t\t$pluginCount\t\t\t= count($plugins);\n\t\t$pluginIndex\t\t\t= array();\n\t\t$pluginTriggerTokens\t= array();\n\t\t$globalTriggerTokens\t= array();\n\t\tfor ($i = 0, $l = count($plugins); $i < $l; $i++)\n\t\t\t{\n\t\t\t$tPluginClassName\t\t\t\t= get_class($plugins[$i]);\n\t\t\t$pluginTriggerTokens[$i]\t\t= $plugins[$i]->getTriggerTokens();\n\t\t\tforeach ($pluginTriggerTokens[$i] as $v)\n\t\t\t\t{\n\t\t\t\tif (!in_array($v, $globalTriggerTokens))\n\t\t\t\t\t{\n\t\t\t\t\t$globalTriggerTokens[] = $v;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t$pluginTriggerTokens[$i] = \"|\" . implode(\"|\", $pluginTriggerTokens[$i]) . \"|\";\n\t\t\t$pluginIndex[$tPluginClassName]\t= $i;\n\t\t\t}\n\t\t$globalTriggerTokens = \"|\" . implode(\"|\", $globalTriggerTokens) . \"|\";\n\t\t/*\n\t\t * Apply filters\n\t\t */\n\t\tfor($i = 0; $i < $filterCount; $i++)\n\t\t\t{\n\t\t\t// Apply the filter; if the return value is larger than 0...\n\t\t\tif ($filters[$i]->apply($tokens) > 0)\n\t\t\t\t{\n\t\t\t\t// ...then filter null values and rebuild the token array\n\t\t\t\t$tokens = array_values(array_filter($tokens));\n\t\t\t\t}\n\t\t\t}\n\t\t$tokenCount = count($tokens);\n\t\t/*\n\t\t * Apply plugins\n\t\t */\n\t\tfor($i = 0; $i < $tokenCount; $i++)\n\t\t\t{\n\t\t\t$triggerToken = \"|\" . get_class($tokens[$i]) . \"|\";\n\t\t\tif (strpos($globalTriggerTokens, $triggerToken) !== false)\n\t\t\t\t{\n\t\t\t\tfor($ii = 0; $ii < $pluginCount; $ii++)\n\t\t\t\t\t{\n\t\t\t\t\tif (strpos($pluginTriggerTokens[$ii], $triggerToken) !== false || $pluginTriggerTokens[$ii] === false)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t// Apply the plugin; if the return value is TRUE continue to the next token\n\t\t\t\t\t\tif ($plugins[$ii]->apply($tokens[$i]) === true)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcontinue 2;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t// Stringify the tokens\n\t\tfor($i = 0; $i < $tokenCount; $i++)\n\t\t\t{\n\t\t\t$r .= (string) $tokens[$i];\n\t\t\t}\n\t\t$this->minified = $r;\n\t\treturn $r;\n\t\t}\n\t}\n\n/**\n * CssMin - A (simple) css minifier with benefits\n * \n * --\n * Copyright (c) 2011 Joe Scylla <joe.scylla@gmail.com>\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n * \n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n * \n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n * --\n * \n * @package\t\tCssMin\n * @link\t\thttp://code.google.com/p/cssmin/\n * @author\t\tJoe Scylla <joe.scylla@gmail.com>\n * @copyright\t2008 - 2011 Joe Scylla <joe.scylla@gmail.com>\n * @license\t\thttp://opensource.org/licenses/mit-license.php MIT License\n * @version\t\t3.0.1\n */\nclass CssMin\n\t{\n\t/**\n\t * Index of classes\n\t * \n\t * @var array\n\t */\n\tprivate static $classIndex = array();\n\t/**\n\t * Parse/minify errors\n\t * \n\t * @var array\n\t */\n\tprivate static $errors = array();\n\t/**\n\t * Verbose output.\n\t * \n\t * @var boolean\n\t */\n\tprivate static $isVerbose = false;\n\t/**\n\t * {@link http://goo.gl/JrW54 Autoload} function of CssMin.\n\t * \n\t * @param string $class Name of the class\n\t * @return void\n\t */\n\tpublic static function autoload($class)\n\t\t{\n\t\tif (isset(self::$classIndex[$class]))\n\t\t\t{\n\t\t\trequire(self::$classIndex[$class]);\n\t\t\t}\n\t\t}\n\t/**\n\t * Return errors\n\t * \n\t * @return array of {CssError}.\n\t */\n\tpublic static function getErrors()\n\t\t{\n\t\treturn self::$errors;\n\t\t}\n\t/**\n\t * Returns if there were errors.\n\t * \n\t * @return boolean\n\t */\n\tpublic static function hasErrors()\n\t\t{\n\t\treturn count(self::$errors) > 0;\n\t\t}\n\t/**\n\t * Initialises CssMin.\n\t * \n\t * @return void\n\t */\n\tpublic static function initialise()\n\t\t{\n\t\t// Create the class index for autoloading or including\n\t\t$paths = array(dirname(__FILE__));\n\t\t// changed by michalsn on 2019/07/26\n\t\t// each function was deprecated\n\t\tforeach ($paths as $i => $path)\n\t\t\t{\n\t\t\t$subDirectorys = glob($path . \"*\", GLOB_MARK | GLOB_ONLYDIR | GLOB_NOSORT);\n\t\t\tif (is_array($subDirectorys))\n\t\t\t\t{\n\t\t\t\tforeach ($subDirectorys as $subDirectory)\n\t\t\t\t\t{\n\t\t\t\t\t$paths[] = $subDirectory;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t$files = glob($path . \"*.php\", 0);\n\t\t\tif (is_array($files))\n\t\t\t\t{\n\t\t\t\tforeach ($files as $file)\n\t\t\t\t\t{\n\t\t\t\t\t$class = substr(basename($file), 0, -4);\n\t\t\t\t\tself::$classIndex[$class] = $file;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\tkrsort(self::$classIndex);\n\t\t// Only use autoloading if spl_autoload_register() is available and no __autoload() is defined (because \n\t\t// __autoload() breaks if spl_autoload_register() is used. \n\t\tif (function_exists(\"spl_autoload_register\") && !is_callable(\"__autoload\"))\n\t\t\t{\n\t\t\tspl_autoload_register(array(__CLASS__, \"autoload\"));\n\t\t\t}\n\t\t// Otherwise include all class files\n\t\telse\n\t\t\t{\n\t\t\tforeach (self::$classIndex as $class => $file)\n\t\t\t\t{\n\t\t\t\tif (!class_exists($class))\n\t\t\t\t\t{\n\t\t\t\t\trequire_once($file);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t/**\n\t * Minifies CSS source.\n\t * \n\t * @param string $source CSS source\n\t * @param array $filters Filter configuration [optional]\n\t * @param array $plugins Plugin configuration [optional]\n\t * @return string Minified CSS\n\t */\n\tpublic static function minify($source, array $filters = null, array $plugins = null)\n\t\t{\n\t\tself::$errors = array();\n\t\t$minifier = new CssMinifier($source, $filters, $plugins);\n\t\treturn $minifier->getMinified();\n\t\t}\n\t/**\n\t * Parse the CSS source.\n\t * \n\t * @param string $source CSS source\n\t * @param array $plugins Plugin configuration [optional]\n\t * @return array Array of aCssToken\n\t */\n\tpublic static function parse($source, array $plugins = null)\n\t\t{\n\t\tself::$errors = array();\n\t\t$parser = new CssParser($source, $plugins);\n\t\treturn $parser->getTokens();\n\t\t}\n\t/**\n\t * --\n\t * \n\t * @param boolean $to\n\t * @return boolean\n\t */\n\tpublic static function setVerbose($to)\n\t\t{\n\t\tself::$isVerbose = (boolean) $to;\n\t\treturn self::$isVerbose;\n\t\t}\n\t/**\n\t * --\n\t * \n\t * @param CssError $error\n\t * @return void\n\t */\n\tpublic static function triggerError(CssError $error)\n\t\t{\n\t\tself::$errors[] = $error;\n\t\tif (self::$isVerbose)\n\t\t\t{\n\t\t\ttrigger_error((string) $error, E_USER_WARNING);\n\t\t\t}\n\t\t}\n\t}\n// Initialises CssMin\nCssMin::initialise();\n\n/**\n * This {@link aCssMinifierFilter minifier filter} import external css files defined with the @import at-rule into the \n * current stylesheet. \n * \n * @package\t\tCssMin/Minifier/Filters\n * @link\t\thttp://code.google.com/p/cssmin/\n * @author\t\tJoe Scylla <joe.scylla@gmail.com>\n * @copyright\t2008 - 2011 Joe Scylla <joe.scylla@gmail.com>\n * @license\t\thttp://opensource.org/licenses/mit-license.php MIT License\n * @version\t\t3.0.1\n */\nclass CssImportImportsMinifierFilter extends aCssMinifierFilter\n\t{\n\t/**\n\t * Array with already imported external stylesheets.\n\t * \n\t * @var array\n\t */\n\tprivate $imported = array();\n\t/**\n\t * Implements {@link aCssMinifierFilter::filter()}.\n\t * \n\t * @param array $tokens Array of objects of type aCssToken\n\t * @return integer Count of added, changed or removed tokens; a return value large than 0 will rebuild the array\n\t */\n\tpublic function apply(array &$tokens)\n\t\t{\n\t\tif (!isset($this->configuration[\"BasePath\"]) || !is_dir($this->configuration[\"BasePath\"]))\n\t\t\t{\n\t\t\tCssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . \": Base path <code>\" . ($this->configuration[\"BasePath\"] ? $this->configuration[\"BasePath\"] : \"null\"). \"</code> is not a directory\"));\n\t\t\treturn 0;\n\t\t\t}\n\t\tfor ($i = 0, $l = count($tokens); $i < $l; $i++)\n\t\t\t{\n\t\t\tif (get_class($tokens[$i]) === \"CssAtImportToken\")\n\t\t\t\t{\n\t\t\t\t$import = $this->configuration[\"BasePath\"] . \"/\" . $tokens[$i]->Import;\n\t\t\t\t// Import file was not found/is not a file\n\t\t\t\tif (!is_file($import))\n\t\t\t\t\t{\n\t\t\t\t\tCssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . \": Import file <code>\" . $import. \"</code> was not found.\", (string) $tokens[$i]));\n\t\t\t\t\t}\n\t\t\t\t// Import file already imported; remove this @import at-rule to prevent recursions\n\t\t\t\telseif (in_array($import, $this->imported))\n\t\t\t\t\t{\n\t\t\t\t\tCssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . \": Import file <code>\" . $import. \"</code> was already imported.\", (string) $tokens[$i]));\n\t\t\t\t\t$tokens[$i] = null;\n\t\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t$this->imported[] = $import;\n\t\t\t\t\t$parser = new CssParser(file_get_contents($import));\n\t\t\t\t\t$import = $parser->getTokens();\n\t\t\t\t\t// The @import at-rule has media types defined requiring special handling\n\t\t\t\t\tif (count($tokens[$i]->MediaTypes) > 0 && !(count($tokens[$i]->MediaTypes) == 1 && $tokens[$i]->MediaTypes[0] == \"all\"))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t$blocks = array();\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t * Filter or set media types of @import at-rule or remove the @import at-rule if no media type is matching the parent @import at-rule\n\t\t\t\t\t\t */\n\t\t\t\t\t\tfor($ii = 0, $ll = count($import); $ii < $ll; $ii++)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (get_class($import[$ii]) === \"CssAtImportToken\")\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// @import at-rule defines no media type or only the \"all\" media type; set the media types to the one defined in the parent @import at-rule\n\t\t\t\t\t\t\t\tif (count($import[$ii]->MediaTypes) == 0 || (count($import[$ii]->MediaTypes) == 1 && $import[$ii]->MediaTypes[0] == \"all\"))\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t$import[$ii]->MediaTypes = $tokens[$i]->MediaTypes;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t// @import at-rule defineds one or more media types; filter out media types not matching with the  parent @import at-rule\n\t\t\t\t\t\t\t\telseif (count($import[$ii]->MediaTypes > 0))\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tforeach ($import[$ii]->MediaTypes as $index => $mediaType)\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tif (!in_array($mediaType, $tokens[$i]->MediaTypes))\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tunset($import[$ii]->MediaTypes[$index]);\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t$import[$ii]->MediaTypes = array_values($import[$ii]->MediaTypes);\n\t\t\t\t\t\t\t\t\t// If there are no media types left in the @import at-rule remove the @import at-rule\n\t\t\t\t\t\t\t\t\tif (count($import[$ii]->MediaTypes) == 0)\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t$import[$ii] = null;\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t * Remove media types of @media at-rule block not defined in the @import at-rule\n\t\t\t\t\t\t */\n\t\t\t\t\t\tfor($ii = 0, $ll = count($import); $ii < $ll; $ii++)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (get_class($import[$ii]) === \"CssAtMediaStartToken\")\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tforeach ($import[$ii]->MediaTypes as $index => $mediaType)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tif (!in_array($mediaType, $tokens[$i]->MediaTypes))\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tunset($import[$ii]->MediaTypes[$index]);\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t$import[$ii]->MediaTypes = array_values($import[$ii]->MediaTypes);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t * If no media types left of the @media at-rule block remove the complete block\n\t\t\t\t\t\t */\n\t\t\t\t\t\tfor($ii = 0, $ll = count($import); $ii < $ll; $ii++)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (get_class($import[$ii]) === \"CssAtMediaStartToken\")\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tif (count($import[$ii]->MediaTypes) === 0)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tfor ($iii = $ii; $iii < $ll; $iii++)\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tif (get_class($import[$iii]) === \"CssAtMediaEndToken\")\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tif (get_class($import[$iii]) === \"CssAtMediaEndToken\")\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tarray_splice($import, $ii, $iii - $ii + 1, array());\n\t\t\t\t\t\t\t\t\t\t$ll = count($import);\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t * If the media types of the @media at-rule equals the media types defined in the @import \n\t\t\t\t\t\t * at-rule remove the CssAtMediaStartToken and CssAtMediaEndToken token\n\t\t\t\t\t\t */ \n\t\t\t\t\t\tfor($ii = 0, $ll = count($import); $ii < $ll; $ii++)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (get_class($import[$ii]) === \"CssAtMediaStartToken\" && count(array_diff($tokens[$i]->MediaTypes, $import[$ii]->MediaTypes)) === 0)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tfor ($iii = $ii; $iii < $ll; $iii++)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tif (get_class($import[$iii]) == \"CssAtMediaEndToken\")\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif (get_class($import[$iii]) == \"CssAtMediaEndToken\")\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tunset($import[$ii]);\n\t\t\t\t\t\t\t\t\tunset($import[$iii]);\n\t\t\t\t\t\t\t\t\t$import = array_values($import);\n\t\t\t\t\t\t\t\t\t$ll = count($import);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t/**\n\t\t\t\t\t\t * Extract CssAtImportToken and CssAtCharsetToken tokens\n\t\t\t\t\t\t */\n\t\t\t\t\t\tfor($ii = 0, $ll = count($import); $ii < $ll; $ii++)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$class = get_class($import[$ii]);\n\t\t\t\t\t\t\tif ($class === \"CssAtImportToken\" || $class === \"CssAtCharsetToken\")\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t$blocks = array_merge($blocks, array_splice($import, $ii, 1, array()));\n\t\t\t\t\t\t\t\t$ll = count($import);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t * Extract the @font-face, @media and @page at-rule block\n\t\t\t\t\t\t */\n\t\t\t\t\t\tfor($ii = 0, $ll = count($import); $ii < $ll; $ii++)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$class = get_class($import[$ii]);\n\t\t\t\t\t\t\tif ($class === \"CssAtFontFaceStartToken\" || $class === \"CssAtMediaStartToken\" || $class === \"CssAtPageStartToken\" || $class === \"CssAtVariablesStartToken\")\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tfor ($iii = $ii; $iii < $ll; $iii++)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t$class = get_class($import[$iii]);\n\t\t\t\t\t\t\t\t\tif ($class === \"CssAtFontFaceEndToken\" || $class === \"CssAtMediaEndToken\" || $class === \"CssAtPageEndToken\" || $class === \"CssAtVariablesEndToken\")\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t$class = get_class($import[$iii]);\n\t\t\t\t\t\t\t\tif (isset($import[$iii]) && ($class === \"CssAtFontFaceEndToken\" || $class === \"CssAtMediaEndToken\" || $class === \"CssAtPageEndToken\" || $class === \"CssAtVariablesEndToken\"))\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t$blocks = array_merge($blocks, array_splice($import, $ii, $iii - $ii + 1, array()));\n\t\t\t\t\t\t\t\t\t$ll = count($import);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t// Create the import array with extracted tokens and the rulesets wrapped into a @media at-rule block\n\t\t\t\t\t\t$import = array_merge($blocks, array(new CssAtMediaStartToken($tokens[$i]->MediaTypes)), $import, array(new CssAtMediaEndToken()));\n\t\t\t\t\t\t}\n\t\t\t\t\t// Insert the imported tokens\n\t\t\t\t\tarray_splice($tokens, $i, 1, $import);\n\t\t\t\t\t// Modify parameters of the for-loop\n\t\t\t\t\t$i--;\n\t\t\t\t\t$l = count($tokens);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n/**\n * {@link aCssParserPlugin Parser plugin} for preserve parsing expression() declaration values.\n * \n * This plugin return no {@link aCssToken CssToken} but ensures that expression() declaration values will get parsed \n * properly.\n * \n * @package\t\tCssMin/Parser/Plugins\n * @link\t\thttp://code.google.com/p/cssmin/\n * @author\t\tJoe Scylla <joe.scylla@gmail.com>\n * @copyright\t2008 - 2011 Joe Scylla <joe.scylla@gmail.com>\n * @license\t\thttp://opensource.org/licenses/mit-license.php MIT License\n * @version\t\t3.0.1\n */\nclass CssExpressionParserPlugin extends aCssParserPlugin\n\t{\n\t/**\n\t * Count of left braces.\n\t * \n\t * @var integer\n\t */\n\tprivate $leftBraces = 0;\n\t/**\n\t * Count of right braces.\n\t * \n\t * @var integer\n\t */\n\tprivate $rightBraces = 0;\n\t/**\n\t * Implements {@link aCssParserPlugin::getTriggerChars()}.\n\t * \n\t * @return array\n\t */\n\tpublic function getTriggerChars()\n\t\t{\n\t\treturn array(\"(\", \")\", \";\", \"}\");\n\t\t}\n\t/**\n\t * Implements {@link aCssParserPlugin::getTriggerStates()}.\n\t * \n\t * @return array\n\t */\n\tpublic function getTriggerStates()\n\t\t{\n\t\treturn false;\n\t\t}\n\t/**\n\t * Implements {@link aCssParserPlugin::parse()}.\n\t * \n\t * @param integer $index Current index\n\t * @param string $char Current char\n\t * @param string $previousChar Previous char\n\t * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing\n\t */\n\tpublic function parse($index, $char, $previousChar, $state)\n\t\t{\n\t\t// Start of expression\n\t\tif ($char === \"(\" && strtolower(substr($this->parser->getSource(), $index - 10, 11)) === \"expression(\" && $state !== \"T_EXPRESSION\")\n\t\t\t{\n\t\t\t$this->parser->pushState(\"T_EXPRESSION\");\n\t\t\t$this->leftBraces++;\n\t\t\t}\n\t\t// Count left braces\n\t\telseif ($char === \"(\" && $state === \"T_EXPRESSION\")\n\t\t\t{\n\t\t\t$this->leftBraces++;\n\t\t\t}\n\t\t// Count right braces\n\t\telseif ($char === \")\" && $state === \"T_EXPRESSION\")\n\t\t\t{\n\t\t\t$this->rightBraces++;\n\t\t\t}\n\t\t// Possible end of expression; if left and right braces are equal the expressen ends\n\t\telseif (($char === \";\" || $char === \"}\") && $state === \"T_EXPRESSION\" && $this->leftBraces === $this->rightBraces)\n\t\t\t{\n\t\t\t$this->leftBraces = $this->rightBraces = 0;\n\t\t\t$this->parser->popState();\n\t\t\treturn $index - 1;\n\t\t\t}\n\t\telse\n\t\t\t{\n\t\t\treturn false;\n\t\t\t}\n\t\treturn true;\n\t\t}\n\t}\n\n/**\n * CSS Error.\n * \n * @package\t\tCssMin\n * @link\t\thttp://code.google.com/p/cssmin/\n * @author\t\tJoe Scylla <joe.scylla@gmail.com>\n * @copyright\t2008 - 2011 Joe Scylla <joe.scylla@gmail.com>\n * @license\t\thttp://opensource.org/licenses/mit-license.php MIT License\n * @version\t\t3.0.1\n */\nclass CssError\n\t{\n\t/**\n\t * File.\n\t * \n\t * @var string\n\t */\n\tpublic $File = \"\";\n\t/**\n\t * Line.\n\t * \n\t * @var integer\n\t */\n\tpublic $Line = 0;\n\t/**\n\t * Error message.\n\t * \n\t * @var string\n\t */\n\tpublic $Message = \"\";\n\t/**\n\t * Source.\n\t * \n\t * @var string\n\t */\n\tpublic $Source = \"\";\n\t/**\n\t * Constructor triggering the error.\n\t * \n\t * @param string $message Error message\n\t * @param string $source Corresponding line [optional]\n\t * @return void\n\t */\n\tpublic function __construct($file, $line, $message, $source = \"\")\n\t\t{\n\t\t$this->File\t\t= $file;\n\t\t$this->Line\t\t= $line;\n\t\t$this->Message\t= $message;\n\t\t$this->Source\t= $source;\n\t\t}\n\t/**\n\t * Returns the error as formatted string.\n\t * \n\t * @return string\n\t */\t\n\tpublic function __toString()\n\t\t{\n\t\treturn $this->Message . ($this->Source ? \": <br /><code>\" . $this->Source . \"</code>\": \"\") . \"<br />in file \" . $this->File . \" at line \" . $this->Line;\n\t\t}\n\t}\n\n/**\n * This {@link aCssMinifierPlugin} will convert a color value in rgb notation to hexadecimal notation.\n * \n * Example:\n * <code>\n * color: rgb(200,60%,5);\n * </code>\n * \n * Will get converted to:\n * <code>\n * color:#c89905;\n * </code>\n *\n * @package\t\tCssMin/Minifier/Plugins\n * @link\t\thttp://code.google.com/p/cssmin/\n * @author\t\tJoe Scylla <joe.scylla@gmail.com>\n * @copyright\t2008 - 2011 Joe Scylla <joe.scylla@gmail.com>\n * @license\t\thttp://opensource.org/licenses/mit-license.php MIT License\n * @version\t\t3.0.1\n */\nclass CssConvertRgbColorsMinifierPlugin extends aCssMinifierPlugin\n\t{\n\t/**\n\t * Regular expression matching the value.\n\t * \n\t * @var string\n\t */\n\tprivate $reMatch = \"/rgb\\s*\\(\\s*([0-9%]+)\\s*,\\s*([0-9%]+)\\s*,\\s*([0-9%]+)\\s*\\)/iS\";\n\t/**\n\t * Implements {@link aCssMinifierPlugin::minify()}.\n\t * \n\t * @param aCssToken $token Token to process\n\t * @return boolean Return TRUE to break the processing of this token; FALSE to continue\n\t */\n\tpublic function apply(aCssToken &$token)\n\t\t{\n\t\tif (stripos($token->Value, \"rgb\") !== false && preg_match($this->reMatch, $token->Value, $m))\n\t\t\t{\n\t\t\tfor ($i = 1, $l = count($m); $i < $l; $i++)\n\t\t\t\t{\n\t\t\t\tif (strpos(\"%\", $m[$i]) !== false)\n\t\t\t\t\t{\n\t\t\t\t\t$m[$i] = substr($m[$i], 0, -1);\n\t\t\t\t\t$m[$i] = (int) (256 * ($m[$i] / 100));\n\t\t\t\t\t}\n\t\t\t\t$m[$i] = str_pad(dechex($m[$i]),  2, \"0\", STR_PAD_LEFT);\n\t\t\t\t}\n\t\t\t$token->Value = str_replace($m[0], \"#\" . $m[1] . $m[2] . $m[3], $token->Value);\n\t\t\t}\n\t\treturn false;\n\t\t}\n\t/**\n\t * Implements {@link aMinifierPlugin::getTriggerTokens()}\n\t * \n\t * @return array\n\t */\n\tpublic function getTriggerTokens()\n\t\t{\n\t\treturn array\n\t\t\t(\n\t\t\t\"CssAtFontFaceDeclarationToken\",\n\t\t\t\"CssAtPageDeclarationToken\",\n\t\t\t\"CssRulesetDeclarationToken\"\n\t\t\t);\n\t\t}\n\t}\n\n/**\n * This {@link aCssMinifierPlugin} will convert named color values to hexadecimal notation.\n * \n * Example:\n * <code>\n * color: black;\n * border: 1px solid indigo;\n * </code>\n * \n * Will get converted to:\n * <code>\n * color:#000;\n * border:1px solid #4b0082;\n * </code>\n * \n * @package\t\tCssMin/Minifier/Plugins\n * @link\t\thttp://code.google.com/p/cssmin/\n * @author\t\tJoe Scylla <joe.scylla@gmail.com>\n * @copyright\t2008 - 2011 Joe Scylla <joe.scylla@gmail.com>\n * @license\t\thttp://opensource.org/licenses/mit-license.php MIT License\n * @version\t\t3.0.1\n */\nclass CssConvertNamedColorsMinifierPlugin extends aCssMinifierPlugin\n\t{\n\t\n\t/**\n\t * Regular expression matching the value.\n\t * \n\t * @var string\n\t */\n\tprivate $reMatch = null;\n\t/**\n\t * Regular expression replacing the value.\n\t * \n\t * @var string\n\t */\n\tprivate $reReplace = \"\\\"\\${1}\\\" . \\$this->transformation[strtolower(\\\"\\${2}\\\")] . \\\"\\${3}\\\"\";\n\t/**\n\t * Transformation table used by the {@link CssConvertNamedColorsMinifierPlugin::$reReplace replace regular expression}.\n\t * \n\t * @var array\n\t */\n\tprivate $transformation = array\n\t\t( \n\t\t\"aliceblue\"\t\t\t\t\t\t=> \"#f0f8ff\",\n\t\t\"antiquewhite\"\t\t\t\t\t=> \"#faebd7\",\n\t\t\"aqua\"\t\t\t\t\t\t\t=> \"#0ff\",\n\t\t\"aquamarine\"\t\t\t\t\t=> \"#7fffd4\",\n\t\t\"azure\"\t\t\t\t\t\t\t=> \"#f0ffff\",\n\t\t\"beige\"\t\t\t\t\t\t\t=> \"#f5f5dc\",\n\t\t\"black\"\t\t\t\t\t\t\t=> \"#000\",\n\t\t\"blue\"\t\t\t\t\t\t\t=> \"#00f\",\n\t\t\"blueviolet\"\t\t\t\t\t=> \"#8a2be2\",\n\t\t\"brown\"\t\t\t\t\t\t\t=> \"#a52a2a\",\n\t\t\"burlywood\"\t\t\t\t\t\t=> \"#deb887\",\n\t\t\"cadetblue\"\t\t\t\t\t\t=> \"#5f9ea0\",\n\t\t\"chartreuse\"\t\t\t\t\t=> \"#7fff00\",\n\t\t\"chocolate\"\t\t\t\t\t\t=> \"#d2691e\",\n\t\t\"coral\"\t\t\t\t\t\t\t=> \"#ff7f50\",\n\t\t\"cornflowerblue\"\t\t\t\t=> \"#6495ed\",\n\t\t\"cornsilk\"\t\t\t\t\t\t=> \"#fff8dc\",\n\t\t\"crimson\"\t\t\t\t\t\t=> \"#dc143c\",\n\t\t\"darkblue\"\t\t\t\t\t\t=> \"#00008b\",\n\t\t\"darkcyan\"\t\t\t\t\t\t=> \"#008b8b\",\n\t\t\"darkgoldenrod\"\t\t\t\t\t=> \"#b8860b\",\n\t\t\"darkgray\"\t\t\t\t\t\t=> \"#a9a9a9\",\n\t\t\"darkgreen\"\t\t\t\t\t\t=> \"#006400\",\n\t\t\"darkkhaki\"\t\t\t\t\t\t=> \"#bdb76b\",\n\t\t\"darkmagenta\"\t\t\t\t\t=> \"#8b008b\",\n\t\t\"darkolivegreen\"\t\t\t\t=> \"#556b2f\",\n\t\t\"darkorange\"\t\t\t\t\t=> \"#ff8c00\",\n\t\t\"darkorchid\"\t\t\t\t\t=> \"#9932cc\",\n\t\t\"darkred\"\t\t\t\t\t\t=> \"#8b0000\",\n\t\t\"darksalmon\"\t\t\t\t\t=> \"#e9967a\",\n\t\t\"darkseagreen\"\t\t\t\t\t=> \"#8fbc8f\",\n\t\t\"darkslateblue\"\t\t\t\t\t=> \"#483d8b\",\n\t\t\"darkslategray\"\t\t\t\t\t=> \"#2f4f4f\",\n\t\t\"darkturquoise\"\t\t\t\t\t=> \"#00ced1\",\n\t\t\"darkviolet\"\t\t\t\t\t=> \"#9400d3\",\n\t\t\"deeppink\"\t\t\t\t\t\t=> \"#ff1493\",\n\t\t\"deepskyblue\"\t\t\t\t\t=> \"#00bfff\",\n\t\t\"dimgray\"\t\t\t\t\t\t=> \"#696969\",\n\t\t\"dodgerblue\"\t\t\t\t\t=> \"#1e90ff\",\n\t\t\"firebrick\"\t\t\t\t\t\t=> \"#b22222\",\n\t\t\"floralwhite\"\t\t\t\t\t=> \"#fffaf0\",\n\t\t\"forestgreen\"\t\t\t\t\t=> \"#228b22\",\n\t\t\"fuchsia\"\t\t\t\t\t\t=> \"#f0f\",\n\t\t\"gainsboro\"\t\t\t\t\t\t=> \"#dcdcdc\",\n\t\t\"ghostwhite\"\t\t\t\t\t=> \"#f8f8ff\",\n\t\t\"gold\"\t\t\t\t\t\t\t=> \"#ffd700\",\n\t\t\"goldenrod\"\t\t\t\t\t\t=> \"#daa520\",\n\t\t\"gray\"\t\t\t\t\t\t\t=> \"#808080\",\n\t\t\"green\"\t\t\t\t\t\t\t=> \"#008000\",\n\t\t\"greenyellow\"\t\t\t\t\t=> \"#adff2f\",\n\t\t\"honeydew\"\t\t\t\t\t\t=> \"#f0fff0\",\n\t\t\"hotpink\"\t\t\t\t\t\t=> \"#ff69b4\",\n\t\t\"indianred\"\t\t\t\t\t\t=> \"#cd5c5c\",\n\t\t\"indigo\"\t\t\t\t\t\t=> \"#4b0082\",\n\t\t\"ivory\"\t\t\t\t\t\t\t=> \"#fffff0\",\n\t\t\"khaki\"\t\t\t\t\t\t\t=> \"#f0e68c\",\n\t\t\"lavender\"\t\t\t\t\t\t=> \"#e6e6fa\",\n\t\t\"lavenderblush\"\t\t\t\t\t=> \"#fff0f5\",\n\t\t\"lawngreen\"\t\t\t\t\t\t=> \"#7cfc00\",\n\t\t\"lemonchiffon\"\t\t\t\t\t=> \"#fffacd\",\n\t\t\"lightblue\"\t\t\t\t\t\t=> \"#add8e6\",\n\t\t\"lightcoral\"\t\t\t\t\t=> \"#f08080\",\n\t\t\"lightcyan\"\t\t\t\t\t\t=> \"#e0ffff\",\n\t\t\"lightgoldenrodyellow\"\t\t\t=> \"#fafad2\",\n\t\t\"lightgreen\"\t\t\t\t\t=> \"#90ee90\",\n\t\t\"lightgrey\"\t\t\t\t\t\t=> \"#d3d3d3\",\n\t\t\"lightpink\"\t\t\t\t\t\t=> \"#ffb6c1\",\n\t\t\"lightsalmon\"\t\t\t\t\t=> \"#ffa07a\",\n\t\t\"lightseagreen\"\t\t\t\t\t=> \"#20b2aa\",\n\t\t\"lightskyblue\"\t\t\t\t\t=> \"#87cefa\",\n\t\t\"lightslategray\"\t\t\t\t=> \"#789\",\n\t\t\"lightsteelblue\"\t\t\t\t=> \"#b0c4de\",\n\t\t\"lightyellow\"\t\t\t\t\t=> \"#ffffe0\",\n\t\t\"lime\"\t\t\t\t\t\t\t=> \"#0f0\",\n\t\t\"limegreen\"\t\t\t\t\t\t=> \"#32cd32\",\n\t\t\"linen\"\t\t\t\t\t\t\t=> \"#faf0e6\",\n\t\t\"maroon\"\t\t\t\t\t\t=> \"#800000\",\n\t\t\"mediumaquamarine\"\t\t\t\t=> \"#66cdaa\",\n\t\t\"mediumblue\"\t\t\t\t\t=> \"#0000cd\",\n\t\t\"mediumorchid\"\t\t\t\t\t=> \"#ba55d3\",\n\t\t\"mediumpurple\"\t\t\t\t\t=> \"#9370db\",\n\t\t\"mediumseagreen\"\t\t\t\t=> \"#3cb371\",\n\t\t\"mediumslateblue\"\t\t\t\t=> \"#7b68ee\",\n\t\t\"mediumspringgreen\"\t\t\t\t=> \"#00fa9a\",\n\t\t\"mediumturquoise\"\t\t\t\t=> \"#48d1cc\",\n\t\t\"mediumvioletred\"\t\t\t\t=> \"#c71585\",\n\t\t\"midnightblue\"\t\t\t\t\t=> \"#191970\",\n\t\t\"mintcream\"\t\t\t\t\t\t=> \"#f5fffa\",\n\t\t\"mistyrose\"\t\t\t\t\t\t=> \"#ffe4e1\",\n\t\t\"moccasin\"\t\t\t\t\t\t=> \"#ffe4b5\",\n\t\t\"navajowhite\"\t\t\t\t\t=> \"#ffdead\",\n\t\t\"navy\"\t\t\t\t\t\t\t=> \"#000080\",\n\t\t\"oldlace\"\t\t\t\t\t\t=> \"#fdf5e6\",\n\t\t\"olive\"\t\t\t\t\t\t\t=> \"#808000\",\n\t\t\"olivedrab\"\t\t\t\t\t\t=> \"#6b8e23\",\n\t\t\"orange\"\t\t\t\t\t\t=> \"#ffa500\",\n\t\t\"orangered\"\t\t\t\t\t\t=> \"#ff4500\",\n\t\t\"orchid\"\t\t\t\t\t\t=> \"#da70d6\",\n\t\t\"palegoldenrod\"\t\t\t\t\t=> \"#eee8aa\",\n\t\t\"palegreen\"\t\t\t\t\t\t=> \"#98fb98\",\n\t\t\"paleturquoise\"\t\t\t\t\t=> \"#afeeee\",\n\t\t\"palevioletred\"\t\t\t\t\t=> \"#db7093\",\n\t\t\"papayawhip\"\t\t\t\t\t=> \"#ffefd5\",\n\t\t\"peachpuff\"\t\t\t\t\t\t=> \"#ffdab9\",\n\t\t\"peru\"\t\t\t\t\t\t\t=> \"#cd853f\",\n\t\t\"pink\"\t\t\t\t\t\t\t=> \"#ffc0cb\",\n\t\t\"plum\"\t\t\t\t\t\t\t=> \"#dda0dd\",\n\t\t\"powderblue\"\t\t\t\t\t=> \"#b0e0e6\",\n\t\t\"purple\"\t\t\t\t\t\t=> \"#800080\",\n\t\t\"red\"\t\t\t\t\t\t\t=> \"#f00\",\n\t\t\"rosybrown\"\t\t\t\t\t\t=> \"#bc8f8f\",\n\t\t\"royalblue\"\t\t\t\t\t\t=> \"#4169e1\",\n\t\t\"saddlebrown\"\t\t\t\t\t=> \"#8b4513\",\n\t\t\"salmon\"\t\t\t\t\t\t=> \"#fa8072\",\n\t\t\"sandybrown\"\t\t\t\t\t=> \"#f4a460\",\n\t\t\"seagreen\"\t\t\t\t\t\t=> \"#2e8b57\",\n\t\t\"seashell\"\t\t\t\t\t\t=> \"#fff5ee\",\n\t\t\"sienna\"\t\t\t\t\t\t=> \"#a0522d\",\n\t\t\"silver\"\t\t\t\t\t\t=> \"#c0c0c0\",\n\t\t\"skyblue\"\t\t\t\t\t\t=> \"#87ceeb\",\n\t\t\"slateblue\"\t\t\t\t\t\t=> \"#6a5acd\",\n\t\t\"slategray\"\t\t\t\t\t\t=> \"#708090\",\n\t\t\"snow\"\t\t\t\t\t\t\t=> \"#fffafa\",\n\t\t\"springgreen\"\t\t\t\t\t=> \"#00ff7f\",\n\t\t\"steelblue\"\t\t\t\t\t\t=> \"#4682b4\",\n\t\t\"tan\"\t\t\t\t\t\t\t=> \"#d2b48c\",\n\t\t\"teal\"\t\t\t\t\t\t\t=> \"#008080\",\n\t\t\"thistle\"\t\t\t\t\t\t=> \"#d8bfd8\",\n\t\t\"tomato\"\t\t\t\t\t\t=> \"#ff6347\",\n\t\t\"turquoise\"\t\t\t\t\t\t=> \"#40e0d0\",\n\t\t\"violet\"\t\t\t\t\t\t=> \"#ee82ee\",\n\t\t\"wheat\"\t\t\t\t\t\t\t=> \"#f5deb3\",\n\t\t\"white\"\t\t\t\t\t\t\t=> \"#fff\",\n\t\t\"whitesmoke\"\t\t\t\t\t=> \"#f5f5f5\",\n\t\t\"yellow\"\t\t\t\t\t\t=> \"#ff0\",\n\t\t\"yellowgreen\"\t\t\t\t\t=> \"#9acd32\"\n\t\t);\n\t/**\n\t * Overwrites {@link aCssMinifierPlugin::__construct()}.\n\t * \n\t * The constructor will create the {@link CssConvertNamedColorsMinifierPlugin::$reReplace replace regular expression}\n\t * based on the {@link CssConvertNamedColorsMinifierPlugin::$transformation transformation table}.\n\t * \n\t * @param CssMinifier $minifier The CssMinifier object of this plugin.\n\t * @param array $configuration Plugin configuration [optional]\n\t * @return void\n\t */\n\tpublic function __construct(CssMinifier $minifier, array $configuration = array())\n\t\t{\n\t\t$this->reMatch = \"/(^|\\s)+(\" . implode(\"|\", array_keys($this->transformation)) . \")(\\s|$)+/eiS\";\n\t\tparent::__construct($minifier, $configuration);\n\t\t}\n\t/**\n\t * Implements {@link aCssMinifierPlugin::minify()}.\n\t * \n\t * @param aCssToken $token Token to process\n\t * @return boolean Return TRUE to break the processing of this token; FALSE to continue\n\t */\n\tpublic function apply(aCssToken &$token)\n\t\t{\n\t\t$lcValue = strtolower($token->Value);\n\t\t// Declaration value equals a value in the transformation table => simple replace\n\t\tif (isset($this->transformation[$lcValue]))\n\t\t\t{\n\t\t\t$token->Value = $this->transformation[$lcValue];\n\t\t\t}\n\t\t// Declaration value contains a value in the transformation table => regular expression replace\n\t\telseif (preg_match($this->reMatch, $token->Value))\n\t\t\t{\n\t\t\t$token->Value = preg_replace($this->reMatch, $this->reReplace, $token->Value);\n\t\t\t}\n\t\treturn false;\n\t\t}\n\t/**\n\t * Implements {@link aMinifierPlugin::getTriggerTokens()}\n\t * \n\t * @return array\n\t */\n\tpublic function getTriggerTokens()\n\t\t{\n\t\treturn array\n\t\t\t(\n\t\t\t\"CssAtFontFaceDeclarationToken\",\n\t\t\t\"CssAtPageDeclarationToken\",\n\t\t\t\"CssRulesetDeclarationToken\"\n\t\t\t);\n\t\t}\n\t}\n\n/**\n * This {@link aCssMinifierFilter minifier filter} triggers on CSS Level 3 properties and will add declaration tokens\n * with browser-specific properties.\n * \n * @package\t\tCssMin/Minifier/Filters\n * @link\t\thttp://code.google.com/p/cssmin/\n * @author\t\tJoe Scylla <joe.scylla@gmail.com>\n * @copyright\t2008 - 2011 Joe Scylla <joe.scylla@gmail.com>\n * @license\t\thttp://opensource.org/licenses/mit-license.php MIT License\n * @version\t\t3.0.1\n */\nclass CssConvertLevel3PropertiesMinifierFilter extends aCssMinifierFilter\n\t{\n\t/**\n\t * Css property transformations table. Used to convert CSS3 and proprietary properties to the browser-specific \n\t * counterparts.\n\t * \n\t * @var array\n\t */\n\tprivate $transformations = array\n\t\t(\n\t\t// Property\t\t\t\t\t\tArray(Mozilla, Webkit, Opera, Internet Explorer); NULL values are placeholders and will get ignored\n\t\t\"animation\"\t\t\t\t\t\t=> array(null, \"-webkit-animation\", null, null),\n\t\t\"animation-delay\"\t\t\t\t=> array(null, \"-webkit-animation-delay\", null, null),\n\t\t\"animation-direction\" \t\t\t=> array(null, \"-webkit-animation-direction\", null, null),\n\t\t\"animation-duration\"\t\t\t=> array(null, \"-webkit-animation-duration\", null, null),\n\t\t\"animation-fill-mode\"\t\t\t=> array(null, \"-webkit-animation-fill-mode\", null, null),\n\t\t\"animation-iteration-count\"\t\t=> array(null, \"-webkit-animation-iteration-count\", null, null),\n\t\t\"animation-name\"\t\t\t\t=> array(null, \"-webkit-animation-name\", null, null),\n\t\t\"animation-play-state\"\t\t\t=> array(null, \"-webkit-animation-play-state\", null, null),\n\t\t\"animation-timing-function\"\t\t=> array(null, \"-webkit-animation-timing-function\", null, null),\n\t\t\"appearance\"\t\t\t\t\t=> array(\"-moz-appearance\", \"-webkit-appearance\", null, null),\n\t\t\"backface-visibility\"\t\t\t=> array(null, \"-webkit-backface-visibility\", null, null),\n\t\t\"background-clip\"\t\t\t\t=> array(null, \"-webkit-background-clip\", null, null),\n\t\t\"background-composite\"\t\t\t=> array(null, \"-webkit-background-composite\", null, null),\n\t\t\"background-inline-policy\"\t\t=> array(\"-moz-background-inline-policy\", null, null, null),\n\t\t\"background-origin\"\t\t\t\t=> array(null, \"-webkit-background-origin\", null, null),\n\t\t\"background-position-x\"\t\t\t=> array(null, null, null, \"-ms-background-position-x\"),\n\t\t\"background-position-y\"\t\t\t=> array(null, null, null, \"-ms-background-position-y\"),\n\t\t\"background-size\"\t\t\t\t=> array(null, \"-webkit-background-size\", null, null),\n\t\t\"behavior\"\t\t\t\t\t\t=> array(null, null, null, \"-ms-behavior\"),\n\t\t\"binding\"\t\t\t\t\t\t=> array(\"-moz-binding\", null, null, null),\n\t\t\"border-after\"\t\t\t\t\t=> array(null, \"-webkit-border-after\", null, null),\n\t\t\"border-after-color\"\t\t\t=> array(null, \"-webkit-border-after-color\", null, null),\n\t\t\"border-after-style\"\t\t\t=> array(null, \"-webkit-border-after-style\", null, null),\n\t\t\"border-after-width\"\t\t\t=> array(null, \"-webkit-border-after-width\", null, null),\n\t\t\"border-before\"\t\t\t\t\t=> array(null, \"-webkit-border-before\", null, null),\n\t\t\"border-before-color\"\t\t\t=> array(null, \"-webkit-border-before-color\", null, null),\n\t\t\"border-before-style\"\t\t\t=> array(null, \"-webkit-border-before-style\", null, null),\n\t\t\"border-before-width\"\t\t\t=> array(null, \"-webkit-border-before-width\", null, null),\n\t\t\"border-border-bottom-colors\"\t=> array(\"-moz-border-bottom-colors\", null, null, null),\n\t\t\"border-bottom-left-radius\"\t\t=> array(\"-moz-border-radius-bottomleft\", \"-webkit-border-bottom-left-radius\", null, null),\n\t\t\"border-bottom-right-radius\"\t=> array(\"-moz-border-radius-bottomright\", \"-webkit-border-bottom-right-radius\", null, null),\n\t\t\"border-end\"\t\t\t\t\t=> array(\"-moz-border-end\", \"-webkit-border-end\", null, null),\n\t\t\"border-end-color\"\t\t\t\t=> array(\"-moz-border-end-color\", \"-webkit-border-end-color\", null, null),\n\t\t\"border-end-style\"\t\t\t\t=> array(\"-moz-border-end-style\", \"-webkit-border-end-style\", null, null),\n\t\t\"border-end-width\"\t\t\t\t=> array(\"-moz-border-end-width\", \"-webkit-border-end-width\", null, null),\n\t\t\"border-fit\"\t\t\t\t\t=> array(null, \"-webkit-border-fit\", null, null),\n\t\t\"border-horizontal-spacing\"\t\t=> array(null, \"-webkit-border-horizontal-spacing\", null, null),\n\t\t\"border-image\"\t\t\t\t\t=> array(\"-moz-border-image\", \"-webkit-border-image\", null, null),\n\t\t\"border-left-colors\"\t\t\t=> array(\"-moz-border-left-colors\", null, null, null),\n\t\t\"border-radius\"\t\t\t\t\t=> array(\"-moz-border-radius\", \"-webkit-border-radius\", null, null),\n\t\t\"border-border-right-colors\"\t=> array(\"-moz-border-right-colors\", null, null, null),\n\t\t\"border-start\"\t\t\t\t\t=> array(\"-moz-border-start\", \"-webkit-border-start\", null, null),\n\t\t\"border-start-color\"\t\t\t=> array(\"-moz-border-start-color\", \"-webkit-border-start-color\", null, null),\n\t\t\"border-start-style\"\t\t\t=> array(\"-moz-border-start-style\", \"-webkit-border-start-style\", null, null),\n\t\t\"border-start-width\"\t\t\t=> array(\"-moz-border-start-width\", \"-webkit-border-start-width\", null, null),\n\t\t\"border-top-colors\"\t\t\t\t=> array(\"-moz-border-top-colors\", null, null, null),\n\t\t\"border-top-left-radius\"\t\t=> array(\"-moz-border-radius-topleft\", \"-webkit-border-top-left-radius\", null, null),\n\t\t\"border-top-right-radius\"\t\t=> array(\"-moz-border-radius-topright\", \"-webkit-border-top-right-radius\", null, null),\n\t\t\"border-vertical-spacing\"\t\t=> array(null, \"-webkit-border-vertical-spacing\", null, null),\n\t\t\"box-align\"\t\t\t\t\t\t=> array(\"-moz-box-align\", \"-webkit-box-align\", null, null),\n\t\t\"box-direction\"\t\t\t\t\t=> array(\"-moz-box-direction\", \"-webkit-box-direction\", null, null),\n\t\t\"box-flex\"\t\t\t\t\t\t=> array(\"-moz-box-flex\", \"-webkit-box-flex\", null, null),\n\t\t\"box-flex-group\"\t\t\t\t=> array(null, \"-webkit-box-flex-group\", null, null),\n\t\t\"box-flex-lines\"\t\t\t\t=> array(null, \"-webkit-box-flex-lines\", null, null),\n\t\t\"box-ordinal-group\"\t\t\t\t=> array(\"-moz-box-ordinal-group\", \"-webkit-box-ordinal-group\", null, null),\n\t\t\"box-orient\"\t\t\t\t\t=> array(\"-moz-box-orient\", \"-webkit-box-orient\", null, null),\n\t\t\"box-pack\"\t\t\t\t\t\t=> array(\"-moz-box-pack\", \"-webkit-box-pack\", null, null),\n\t\t\"box-reflect\"\t\t\t\t\t=> array(null, \"-webkit-box-reflect\", null, null),\n\t\t\"box-shadow\"\t\t\t\t\t=> array(\"-moz-box-shadow\", \"-webkit-box-shadow\", null, null),\n\t\t\"box-sizing\"\t\t\t\t\t=> array(\"-moz-box-sizing\", null, null, null),\n\t\t\"color-correction\"\t\t\t\t=> array(null, \"-webkit-color-correction\", null, null),\n\t\t\"column-break-after\"\t\t\t=> array(null, \"-webkit-column-break-after\", null, null),\n\t\t\"column-break-before\"\t\t\t=> array(null, \"-webkit-column-break-before\", null, null),\n\t\t\"column-break-inside\"\t\t\t=> array(null, \"-webkit-column-break-inside\", null, null),\n\t\t\"column-count\"\t\t\t\t\t=> array(\"-moz-column-count\", \"-webkit-column-count\", null, null),\n\t\t\"column-gap\"\t\t\t\t\t=> array(\"-moz-column-gap\", \"-webkit-column-gap\", null, null),\n\t\t\"column-rule\"\t\t\t\t\t=> array(\"-moz-column-rule\", \"-webkit-column-rule\", null, null),\n\t\t\"column-rule-color\"\t\t\t\t=> array(\"-moz-column-rule-color\", \"-webkit-column-rule-color\", null, null),\n\t\t\"column-rule-style\"\t\t\t\t=> array(\"-moz-column-rule-style\", \"-webkit-column-rule-style\", null, null),\n\t\t\"column-rule-width\"\t\t\t\t=> array(\"-moz-column-rule-width\", \"-webkit-column-rule-width\", null, null),\n\t\t\"column-span\"\t\t\t\t\t=> array(null, \"-webkit-column-span\", null, null),\n\t\t\"column-width\"\t\t\t\t\t=> array(\"-moz-column-width\", \"-webkit-column-width\", null, null),\n\t\t\"columns\"\t\t\t\t\t\t=> array(null, \"-webkit-columns\", null, null),\n\t\t\"filter\"\t\t\t\t\t\t=> array(__CLASS__, \"filter\"),\n\t\t\"float-edge\"\t\t\t\t\t=> array(\"-moz-float-edge\", null, null, null),\n\t\t\"font-feature-settings\"\t\t\t=> array(\"-moz-font-feature-settings\", null, null, null),\n\t\t\"font-language-override\"\t\t=> array(\"-moz-font-language-override\", null, null, null),\n\t\t\"font-size-delta\"\t\t\t\t=> array(null, \"-webkit-font-size-delta\", null, null),\n\t\t\"font-smoothing\"\t\t\t\t=> array(null, \"-webkit-font-smoothing\", null, null),\n\t\t\"force-broken-image-icon\"\t\t=> array(\"-moz-force-broken-image-icon\", null, null, null),\n\t\t\"highlight\"\t\t\t\t\t\t=> array(null, \"-webkit-highlight\", null, null),\n\t\t\"hyphenate-character\"\t\t\t=> array(null, \"-webkit-hyphenate-character\", null, null),\n\t\t\"hyphenate-locale\"\t\t\t\t=> array(null, \"-webkit-hyphenate-locale\", null, null),\n\t\t\"hyphens\"\t\t\t\t\t\t=> array(null, \"-webkit-hyphens\", null, null),\n\t\t\"force-broken-image-icon\"\t\t=> array(\"-moz-image-region\", null, null, null),\n\t\t\"ime-mode\"\t\t\t\t\t\t=> array(null, null, null, \"-ms-ime-mode\"),\n\t\t\"interpolation-mode\"\t\t\t=> array(null, null, null, \"-ms-interpolation-mode\"),\n\t\t\"layout-flow\"\t\t\t\t\t=> array(null, null, null, \"-ms-layout-flow\"),\n\t\t\"layout-grid\"\t\t\t\t\t=> array(null, null, null, \"-ms-layout-grid\"),\n\t\t\"layout-grid-char\"\t\t\t\t=> array(null, null, null, \"-ms-layout-grid-char\"),\n\t\t\"layout-grid-line\"\t\t\t\t=> array(null, null, null, \"-ms-layout-grid-line\"),\n\t\t\"layout-grid-mode\"\t\t\t\t=> array(null, null, null, \"-ms-layout-grid-mode\"),\n\t\t\"layout-grid-type\"\t\t\t\t=> array(null, null, null, \"-ms-layout-grid-type\"),\n\t\t\"line-break\"\t\t\t\t\t=> array(null, \"-webkit-line-break\", null, \"-ms-line-break\"),\n\t\t\"line-clamp\"\t\t\t\t\t=> array(null, \"-webkit-line-clamp\", null, null),\n\t\t\"line-grid-mode\"\t\t\t\t=> array(null, null, null, \"-ms-line-grid-mode\"),\n\t\t\"logical-height\"\t\t\t\t=> array(null, \"-webkit-logical-height\", null, null),\n\t\t\"logical-width\"\t\t\t\t\t=> array(null, \"-webkit-logical-width\", null, null),\n\t\t\"margin-after\"\t\t\t\t\t=> array(null, \"-webkit-margin-after\", null, null),\n\t\t\"margin-after-collapse\"\t\t\t=> array(null, \"-webkit-margin-after-collapse\", null, null),\n\t\t\"margin-before\"\t\t\t\t\t=> array(null, \"-webkit-margin-before\", null, null),\n\t\t\"margin-before-collapse\"\t\t=> array(null, \"-webkit-margin-before-collapse\", null, null),\n\t\t\"margin-bottom-collapse\"\t\t=> array(null, \"-webkit-margin-bottom-collapse\", null, null),\n\t\t\"margin-collapse\"\t\t\t\t=> array(null, \"-webkit-margin-collapse\", null, null),\n\t\t\"margin-end\"\t\t\t\t\t=> array(\"-moz-margin-end\", \"-webkit-margin-end\", null, null),\n\t\t\"margin-start\"\t\t\t\t\t=> array(\"-moz-margin-start\", \"-webkit-margin-start\", null, null),\n\t\t\"margin-top-collapse\"\t\t\t=> array(null, \"-webkit-margin-top-collapse\", null, null),\n\t\t\"marquee \"\t\t\t\t\t\t=> array(null, \"-webkit-marquee\", null, null),\n\t\t\"marquee-direction\"\t\t\t\t=> array(null, \"-webkit-marquee-direction\", null, null),\n\t\t\"marquee-increment\"\t\t\t\t=> array(null, \"-webkit-marquee-increment\", null, null),\n\t\t\"marquee-repetition\"\t\t\t=> array(null, \"-webkit-marquee-repetition\", null, null),\n\t\t\"marquee-speed\"\t\t\t\t\t=> array(null, \"-webkit-marquee-speed\", null, null),\n\t\t\"marquee-style\"\t\t\t\t\t=> array(null, \"-webkit-marquee-style\", null, null),\n\t\t\"mask\"\t\t\t\t\t\t\t=> array(null, \"-webkit-mask\", null, null),\n\t\t\"mask-attachment\"\t\t\t\t=> array(null, \"-webkit-mask-attachment\", null, null),\n\t\t\"mask-box-image\"\t\t\t\t=> array(null, \"-webkit-mask-box-image\", null, null),\n\t\t\"mask-clip\"\t\t\t\t\t\t=> array(null, \"-webkit-mask-clip\", null, null),\n\t\t\"mask-composite\"\t\t\t\t=> array(null, \"-webkit-mask-composite\", null, null),\n\t\t\"mask-image\"\t\t\t\t\t=> array(null, \"-webkit-mask-image\", null, null),\n\t\t\"mask-origin\"\t\t\t\t\t=> array(null, \"-webkit-mask-origin\", null, null),\n\t\t\"mask-position\"\t\t\t\t\t=> array(null, \"-webkit-mask-position\", null, null),\n\t\t\"mask-position-x\"\t\t\t\t=> array(null, \"-webkit-mask-position-x\", null, null),\n\t\t\"mask-position-y\"\t\t\t\t=> array(null, \"-webkit-mask-position-y\", null, null),\n\t\t\"mask-repeat\"\t\t\t\t\t=> array(null, \"-webkit-mask-repeat\", null, null),\n\t\t\"mask-repeat-x\"\t\t\t\t\t=> array(null, \"-webkit-mask-repeat-x\", null, null),\n\t\t\"mask-repeat-y\"\t\t\t\t\t=> array(null, \"-webkit-mask-repeat-y\", null, null),\n\t\t\"mask-size\"\t\t\t\t\t\t=> array(null, \"-webkit-mask-size\", null, null),\n\t\t\"match-nearest-mail-blockquote-color\" => array(null, \"-webkit-match-nearest-mail-blockquote-color\", null, null),\n\t\t\"max-logical-height\"\t\t\t=> array(null, \"-webkit-max-logical-height\", null, null),\n\t\t\"max-logical-width\"\t\t\t\t=> array(null, \"-webkit-max-logical-width\", null, null),\n\t\t\"min-logical-height\"\t\t\t=> array(null, \"-webkit-min-logical-height\", null, null),\n\t\t\"min-logical-width\"\t\t\t\t=> array(null, \"-webkit-min-logical-width\", null, null),\n\t\t\"object-fit\"\t\t\t\t\t=> array(null, null, \"-o-object-fit\", null),\n\t\t\"object-position\"\t\t\t\t=> array(null, null, \"-o-object-position\", null),\n\t\t\"opacity\"\t\t\t\t\t\t=> array(__CLASS__, \"opacity\"),\n\t\t\"outline-radius\"\t\t\t\t=> array(\"-moz-outline-radius\", null, null, null),\n\t\t\"outline-bottom-left-radius\"\t=> array(\"-moz-outline-radius-bottomleft\", null, null, null),\n\t\t\"outline-bottom-right-radius\"\t=> array(\"-moz-outline-radius-bottomright\", null, null, null),\n\t\t\"outline-top-left-radius\"\t\t=> array(\"-moz-outline-radius-topleft\", null, null, null),\n\t\t\"outline-top-right-radius\"\t\t=> array(\"-moz-outline-radius-topright\", null, null, null),\n\t\t\"padding-after\"\t\t\t\t\t=> array(null, \"-webkit-padding-after\", null, null),\n\t\t\"padding-before\"\t\t\t\t=> array(null, \"-webkit-padding-before\", null, null),\n\t\t\"padding-end\"\t\t\t\t\t=> array(\"-moz-padding-end\", \"-webkit-padding-end\", null, null),\n\t\t\"padding-start\"\t\t\t\t\t=> array(\"-moz-padding-start\", \"-webkit-padding-start\", null, null),\n\t\t\"perspective\"\t\t\t\t\t=> array(null, \"-webkit-perspective\", null, null),\n\t\t\"perspective-origin\"\t\t\t=> array(null, \"-webkit-perspective-origin\", null, null),\n\t\t\"perspective-origin-x\"\t\t\t=> array(null, \"-webkit-perspective-origin-x\", null, null),\n\t\t\"perspective-origin-y\"\t\t\t=> array(null, \"-webkit-perspective-origin-y\", null, null),\n\t\t\"rtl-ordering\"\t\t\t\t\t=> array(null, \"-webkit-rtl-ordering\", null, null),\n\t\t\"scrollbar-3dlight-color\"\t\t=> array(null, null, null, \"-ms-scrollbar-3dlight-color\"),\n\t\t\"scrollbar-arrow-color\"\t\t\t=> array(null, null, null, \"-ms-scrollbar-arrow-color\"),\n\t\t\"scrollbar-base-color\"\t\t\t=> array(null, null, null, \"-ms-scrollbar-base-color\"),\n\t\t\"scrollbar-darkshadow-color\"\t=> array(null, null, null, \"-ms-scrollbar-darkshadow-color\"),\n\t\t\"scrollbar-face-color\"\t\t\t=> array(null, null, null, \"-ms-scrollbar-face-color\"),\n\t\t\"scrollbar-highlight-color\"\t\t=> array(null, null, null, \"-ms-scrollbar-highlight-color\"),\n\t\t\"scrollbar-shadow-color\"\t\t=> array(null, null, null, \"-ms-scrollbar-shadow-color\"),\n\t\t\"scrollbar-track-color\"\t\t\t=> array(null, null, null, \"-ms-scrollbar-track-color\"),\n\t\t\"stack-sizing\"\t\t\t\t\t=> array(\"-moz-stack-sizing\", null, null, null),\n\t\t\"svg-shadow\"\t\t\t\t\t=> array(null, \"-webkit-svg-shadow\", null, null),\n\t\t\"tab-size\"\t\t\t\t\t\t=> array(\"-moz-tab-size\", null, \"-o-tab-size\", null),\n\t\t\"table-baseline\"\t\t\t\t=> array(null, null, \"-o-table-baseline\", null),\n\t\t\"text-align-last\"\t\t\t\t=> array(null, null, null, \"-ms-text-align-last\"),\n\t\t\"text-autospace\"\t\t\t\t=> array(null, null, null, \"-ms-text-autospace\"),\n\t\t\"text-combine\"\t\t\t\t\t=> array(null, \"-webkit-text-combine\", null, null),\n\t\t\"text-decorations-in-effect\"\t=> array(null, \"-webkit-text-decorations-in-effect\", null, null),\n\t\t\"text-emphasis\"\t\t\t\t\t=> array(null, \"-webkit-text-emphasis\", null, null),\n\t\t\"text-emphasis-color\"\t\t\t=> array(null, \"-webkit-text-emphasis-color\", null, null),\n\t\t\"text-emphasis-position\"\t\t=> array(null, \"-webkit-text-emphasis-position\", null, null),\n\t\t\"text-emphasis-style\"\t\t\t=> array(null, \"-webkit-text-emphasis-style\", null, null),\n\t\t\"text-fill-color\"\t\t\t\t=> array(null, \"-webkit-text-fill-color\", null, null),\n\t\t\"text-justify\"\t\t\t\t\t=> array(null, null, null, \"-ms-text-justify\"),\n\t\t\"text-kashida-space\"\t\t\t=> array(null, null, null, \"-ms-text-kashida-space\"),\n\t\t\"text-overflow\"\t\t\t\t\t=> array(null, null, \"-o-text-overflow\", \"-ms-text-overflow\"),\n\t\t\"text-security\"\t\t\t\t\t=> array(null, \"-webkit-text-security\", null, null),\n\t\t\"text-size-adjust\"\t\t\t\t=> array(null, \"-webkit-text-size-adjust\", null, \"-ms-text-size-adjust\"),\n\t\t\"text-stroke\"\t\t\t\t\t=> array(null, \"-webkit-text-stroke\", null, null),\n\t\t\"text-stroke-color\"\t\t\t\t=> array(null, \"-webkit-text-stroke-color\", null, null),\n\t\t\"text-stroke-width\"\t\t\t\t=> array(null, \"-webkit-text-stroke-width\", null, null),\n\t\t\"text-underline-position\"\t\t=> array(null, null, null, \"-ms-text-underline-position\"),\n\t\t\"transform\"\t\t\t\t\t\t=> array(\"-moz-transform\", \"-webkit-transform\", \"-o-transform\", null),\n\t\t\"transform-origin\"\t\t\t\t=> array(\"-moz-transform-origin\", \"-webkit-transform-origin\", \"-o-transform-origin\", null),\n\t\t\"transform-origin-x\"\t\t\t=> array(null, \"-webkit-transform-origin-x\", null, null),\n\t\t\"transform-origin-y\"\t\t\t=> array(null, \"-webkit-transform-origin-y\", null, null),\n\t\t\"transform-origin-z\"\t\t\t=> array(null, \"-webkit-transform-origin-z\", null, null),\n\t\t\"transform-style\"\t\t\t\t=> array(null, \"-webkit-transform-style\", null, null),\n\t\t\"transition\"\t\t\t\t\t=> array(\"-moz-transition\", \"-webkit-transition\", \"-o-transition\", null),\n\t\t\"transition-delay\"\t\t\t\t=> array(\"-moz-transition-delay\", \"-webkit-transition-delay\", \"-o-transition-delay\", null),\n\t\t\"transition-duration\"\t\t\t=> array(\"-moz-transition-duration\", \"-webkit-transition-duration\", \"-o-transition-duration\", null),\n\t\t\"transition-property\"\t\t\t=> array(\"-moz-transition-property\", \"-webkit-transition-property\", \"-o-transition-property\", null),\n\t\t\"transition-timing-function\"\t=> array(\"-moz-transition-timing-function\", \"-webkit-transition-timing-function\", \"-o-transition-timing-function\", null),\n\t\t\"user-drag\"\t\t\t\t\t\t=> array(null, \"-webkit-user-drag\", null, null),\n\t\t\"user-focus\"\t\t\t\t\t=> array(\"-moz-user-focus\", null, null, null),\n\t\t\"user-input\"\t\t\t\t\t=> array(\"-moz-user-input\", null, null, null),\n\t\t\"user-modify\"\t\t\t\t\t=> array(\"-moz-user-modify\", \"-webkit-user-modify\", null, null),\n\t\t\"user-select\"\t\t\t\t\t=> array(\"-moz-user-select\", \"-webkit-user-select\", null, null),\n\t\t\"white-space\"\t\t\t\t\t=> array(__CLASS__, \"whiteSpace\"),\n\t\t\"window-shadow\"\t\t\t\t\t=> array(\"-moz-window-shadow\", null, null, null),\n\t\t\"word-break\"\t\t\t\t\t=> array(null, null, null, \"-ms-word-break\"),\n\t\t\"word-wrap\"\t\t\t\t\t\t=> array(null, null, null, \"-ms-word-wrap\"),\n\t\t\"writing-mode\"\t\t\t\t\t=> array(null, \"-webkit-writing-mode\", null, \"-ms-writing-mode\"),\n\t\t\"zoom\"\t\t\t\t\t\t\t=> array(null, null, null, \"-ms-zoom\")\n\t\t);\n\t/**\n\t * Implements {@link aCssMinifierFilter::filter()}.\n\t * \n\t * @param array $tokens Array of objects of type aCssToken\n\t * @return integer Count of added, changed or removed tokens; a return value large than 0 will rebuild the array\n\t */\n\tpublic function apply(array &$tokens)\n\t\t{\n\t\t$r = 0;\n\t\t$transformations = &$this->transformations;\n\t\tfor ($i = 0, $l = count($tokens); $i < $l; $i++)\n\t\t\t{\n\t\t\tif (get_class($tokens[$i]) === \"CssRulesetDeclarationToken\")\n\t\t\t\t{\n\t\t\t\t$tProperty = $tokens[$i]->Property;\n\t\t\t\tif (isset($transformations[$tProperty]))\n\t\t\t\t\t{\n\t\t\t\t\t$result = array();\n\t\t\t\t\tif (is_callable($transformations[$tProperty]))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t$result = call_user_func_array($transformations[$tProperty], array($tokens[$i]));\n\t\t\t\t\t\tif (!is_array($result) && is_object($result))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$result = array($result);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t$tValue\t\t\t= $tokens[$i]->Value;\n\t\t\t\t\t\t$tMediaTypes\t= $tokens[$i]->MediaTypes;\n\t\t\t\t\t\tforeach ($transformations[$tProperty] as $property)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif ($property !== null)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t$result[] = new CssRulesetDeclarationToken($property, $tValue, $tMediaTypes);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\tif (count($result) > 0)\n\t\t\t\t\t\t{\n\t\t\t\t\t\tarray_splice($tokens, $i + 1, 0, $result);\n\t\t\t\t\t\t$i += count($result);\n\t\t\t\t\t\t$l += count($result);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\treturn $r;\n\t\t}\n\t/**\n\t * Transforms the Internet Explorer specific declaration property \"filter\" to Internet Explorer 8+ compatible \n\t * declaratiopn property \"-ms-filter\". \n\t * \n\t * @param aCssToken $token\n\t * @return array\n\t */\n\tprivate static function filter($token)\n\t\t{\n\t\t$r = array\n\t\t\t(\n\t\t\tnew CssRulesetDeclarationToken(\"-ms-filter\", \"\\\"\" . $token->Value . \"\\\"\", $token->MediaTypes),\n\t\t\t);\n\t\treturn $r;\n\t\t}\n\t/**\n\t * Transforms \"opacity: {value}\" into browser specific counterparts.\n\t * \n\t * @param aCssToken $token\n\t * @return array\n\t */\n\tprivate static function opacity($token)\n\t\t{\n\t\t// Calculate the value for Internet Explorer filter statement\n\t\t$ieValue = (int) ((float) $token->Value * 100);\n\t\t$r = array\n\t\t\t(\n\t\t\t// Internet Explorer >= 8\n\t\t\tnew CssRulesetDeclarationToken(\"-ms-filter\", \"\\\"alpha(opacity=\" . $ieValue . \")\\\"\", $token->MediaTypes),\n\t\t\t// Internet Explorer >= 4 <= 7\n\t\t\tnew CssRulesetDeclarationToken(\"filter\", \"alpha(opacity=\" . $ieValue . \")\", $token->MediaTypes),\n\t\t\tnew CssRulesetDeclarationToken(\"zoom\", \"1\", $token->MediaTypes)\n\t\t\t);\n\t\treturn $r;\n\t\t}\n\t/**\n\t * Transforms \"white-space: pre-wrap\" into browser specific counterparts.\n\t * \n\t * @param aCssToken $token\n\t * @return array\n\t */\n\tprivate static function whiteSpace($token)\n\t\t{\n\t\tif (strtolower($token->Value) === \"pre-wrap\")\n\t\t\t{\n\t\t\t$r = array\n\t\t\t\t(\n\t\t\t\t// Firefox < 3\n\t\t\t\tnew CssRulesetDeclarationToken(\"white-space\", \"-moz-pre-wrap\", $token->MediaTypes),\n\t\t\t\t// Webkit\n\t\t\t\tnew CssRulesetDeclarationToken(\"white-space\", \"-webkit-pre-wrap\", $token->MediaTypes),\n\t\t\t\t// Opera >= 4 <= 6\n\t\t\t\tnew CssRulesetDeclarationToken(\"white-space\", \"-pre-wrap\", $token->MediaTypes),\n\t\t\t\t// Opera >= 7\n\t\t\t\tnew CssRulesetDeclarationToken(\"white-space\", \"-o-pre-wrap\", $token->MediaTypes),\n\t\t\t\t// Internet Explorer >= 5.5\n\t\t\t\tnew CssRulesetDeclarationToken(\"word-wrap\", \"break-word\", $token->MediaTypes)\n\t\t\t\t);\n\t\t\treturn $r;\n\t\t\t}\n\t\telse\n\t\t\t{\n\t\t\treturn array();\n\t\t\t}\n\t\t}\n\t}\n\n/**\n * This {@link aCssMinifierFilter minifier filter} will convert @keyframes at-rule block to browser specific counterparts.\n * \n * @package\t\tCssMin/Minifier/Filters\n * @link\t\thttp://code.google.com/p/cssmin/\n * @author\t\tJoe Scylla <joe.scylla@gmail.com>\n * @copyright\t2008 - 2011 Joe Scylla <joe.scylla@gmail.com>\n * @license\t\thttp://opensource.org/licenses/mit-license.php MIT License\n * @version\t\t3.0.1\n */\nclass CssConvertLevel3AtKeyframesMinifierFilter extends aCssMinifierFilter\n\t{\n\t/**\n\t * Implements {@link aCssMinifierFilter::filter()}.\n\t * \n\t * @param array $tokens Array of objects of type aCssToken\n\t * @return integer Count of added, changed or removed tokens; a return value larger than 0 will rebuild the array\n\t */\n\tpublic function apply(array &$tokens)\n\t\t{\n\t\t$r = 0;\n\t\t$transformations = array(\"-moz-keyframes\", \"-webkit-keyframes\");\n\t\tfor ($i = 0, $l = count($tokens); $i < $l; $i++)\n\t\t\t{\n\t\t\tif (get_class($tokens[$i]) === \"CssAtKeyframesStartToken\")\n\t\t\t\t{\n\t\t\t\tfor ($ii = $i; $ii < $l; $ii++)\n\t\t\t\t\t{\n\t\t\t\t\tif (get_class($tokens[$ii]) === \"CssAtKeyframesEndToken\")\n\t\t\t\t\t\t{\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\tif (get_class($tokens[$ii]) === \"CssAtKeyframesEndToken\")\n\t\t\t\t\t{\n\t\t\t\t\t$add\t= array();\n\t\t\t\t\t$source\t= array();\n\t\t\t\t\tfor ($iii = $i; $iii <= $ii; $iii++)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t$source[] = clone($tokens[$iii]);\n\t\t\t\t\t\t}\n\t\t\t\t\tforeach ($transformations as $transformation)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t$t = array();\n\t\t\t\t\t\tforeach ($source as $token)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$t[] = clone($token);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t$t[0]->AtRuleName = $transformation;\n\t\t\t\t\t\t$add = array_merge($add, $t);\n\t\t\t\t\t\t}\n\t\t\t\t\tif (isset($this->configuration[\"RemoveSource\"]) && $this->configuration[\"RemoveSource\"] === true)\n\t\t\t\t\t\t{\n\t\t\t\t\t\tarray_splice($tokens, $i, $ii - $i + 1, $add);\n\t\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\tarray_splice($tokens, $ii + 1, 0, $add);\n\t\t\t\t\t\t}\n\t\t\t\t\t$l = count($tokens);\n\t\t\t\t\t$i = $ii + count($add);\n\t\t\t\t\t$r += count($add);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\treturn $r;\n\t\t}\n\t}\n\n/**\n * This {@link aCssMinifierPlugin} will convert a color value in hsl notation to hexadecimal notation.\n * \n * Example:\n * <code>\n * color: hsl(232,36%,48%);\n * </code>\n * \n * Will get converted to:\n * <code>\n * color:#4e5aa7;\n * </code>\n * \n * @package\t\tCssMin/Minifier/Plugins\n * @link\t\thttp://code.google.com/p/cssmin/\n * @author\t\tJoe Scylla <joe.scylla@gmail.com>\n * @copyright\t2008 - 2011 Joe Scylla <joe.scylla@gmail.com>\n * @license\t\thttp://opensource.org/licenses/mit-license.php MIT License\n * @version\t\t3.0.1\n */\nclass CssConvertHslColorsMinifierPlugin extends aCssMinifierPlugin\n\t{\n\t/**\n\t * Regular expression matching the value.\n\t * \n\t * @var string\n\t */\n\tprivate $reMatch = \"/^hsl\\s*\\(\\s*([0-9]+)\\s*,\\s*([0-9]+)\\s*%\\s*,\\s*([0-9]+)\\s*%\\s*\\)/iS\";\n\t/**\n\t * Implements {@link aCssMinifierPlugin::minify()}.\n\t * \n\t * @param aCssToken $token Token to process\n\t * @return boolean Return TRUE to break the processing of this token; FALSE to continue\n\t */\n\tpublic function apply(aCssToken &$token)\n\t\t{\n\t\tif (stripos($token->Value, \"hsl\") !== false && preg_match($this->reMatch, $token->Value, $m))\n\t\t\t{\n\t\t\t$token->Value = str_replace($m[0], $this->hsl2hex($m[1], $m[2], $m[3]), $token->Value);\n\t\t\t}\n\t\treturn false;\n\t\t}\n\t/**\n\t * Implements {@link aMinifierPlugin::getTriggerTokens()}\n\t * \n\t * @return array\n\t */\n\tpublic function getTriggerTokens()\n\t\t{\n\t\treturn array\n\t\t\t(\n\t\t\t\"CssAtFontFaceDeclarationToken\",\n\t\t\t\"CssAtPageDeclarationToken\",\n\t\t\t\"CssRulesetDeclarationToken\"\n\t\t\t);\n\t\t}\n\t/**\n\t * Convert a HSL value to hexadecimal notation.\n\t * \n\t * Based on: {@link http://www.easyrgb.com/index.php?X=MATH&H=19#text19}.\n\t * \n\t * @param integer $hue Hue\n\t * @param integer $saturation Saturation\n\t * @param integer $lightness Lightnesss\n\t * @return string\n\t */\n\tprivate function hsl2hex($hue, $saturation, $lightness)\n\t\t{\n\t\t$hue\t\t= $hue / 360;\n\t\t$saturation\t= $saturation / 100;\n\t\t$lightness\t= $lightness / 100;\n\t\tif ($saturation == 0)\n\t\t\t{\n\t\t\t$red\t= $lightness * 255;\n\t\t\t$green\t= $lightness * 255;\n\t\t\t$blue\t= $lightness * 255;\n\t\t\t}\n\t\telse\n\t\t\t{\n\t\t\tif ($lightness < 0.5 )\n\t\t\t\t{\n\t\t\t\t$v2 = $lightness * (1 + $saturation);\n\t\t\t\t}\n\t\t\telse\n\t\t\t\t{\n\t\t\t\t$v2 = ($lightness + $saturation) - ($saturation * $lightness);\n\t\t\t\t}\n\t\t\t$v1\t\t= 2 * $lightness - $v2;\n\t\t\t$red\t= 255 * self::hue2rgb($v1, $v2, $hue + (1 / 3));\n\t\t\t$green\t= 255 * self::hue2rgb($v1, $v2, $hue);\n\t\t\t$blue\t= 255 * self::hue2rgb($v1, $v2, $hue - (1 / 3));\n\t\t\t}\n\t\treturn \"#\" . str_pad(dechex(round($red)), 2, \"0\", STR_PAD_LEFT) . str_pad(dechex(round($green)), 2, \"0\", STR_PAD_LEFT) . str_pad(dechex(round($blue)), 2, \"0\", STR_PAD_LEFT);\n\t\t}\n\t/**\n\t * Apply hue to a rgb color value.\n\t * \n\t * @param integer $v1 Value 1\n\t * @param integer $v2 Value 2\n\t * @param integer $hue Hue\n\t * @return integer\n\t */\n\tprivate function hue2rgb($v1, $v2, $hue)\n\t\t{\n\t\tif ($hue < 0)\n\t\t\t{\n\t\t\t$hue += 1;\n\t\t\t}\n\t\tif ($hue > 1)\n\t\t\t{\n\t\t\t$hue -= 1;\n\t\t\t}\n\t\tif ((6 * $hue) < 1)\n\t\t\t{\n\t\t\treturn ($v1 + ($v2 - $v1) * 6 * $hue);\n\t\t\t}\n\t\tif ((2 * $hue) < 1)\n\t\t\t{\n\t\t\treturn ($v2);\n\t\t\t}\n\t\tif ((3 * $hue) < 2)\n\t\t\t{\n\t\t\treturn ($v1 + ($v2 - $v1) * (( 2 / 3) - $hue) * 6);\n\t\t\t}\n\t\treturn $v1;\n\t\t}\n\t}\n\n/**\n * This {@link aCssMinifierPlugin} will convert the font-weight values normal and bold to their numeric notation.\n * \n * Example:\n * <code>\n * font-weight: normal;\n * font: bold 11px monospace;\n * </code>\n * \n * Will get converted to:\n * <code>\n * font-weight:400;\n * font:700 11px monospace;\n * </code>\n *\n * @package\t\tCssMin/Minifier/Pluginsn\n * @link\t\thttp://code.google.com/p/cssmin/\n * @author\t\tJoe Scylla <joe.scylla@gmail.com>\n * @copyright\t2008 - 2011 Joe Scylla <joe.scylla@gmail.com>\n * @license\t\thttp://opensource.org/licenses/mit-license.php MIT License\n * @version\t\t3.0.1\n */\nclass CssConvertFontWeightMinifierPlugin extends aCssMinifierPlugin\n\t{\n\t/**\n\t * Array of included declaration properties this plugin will process; others declaration properties will get\n\t * ignored. \n\t * \n\t * @var array\n\t */\n\tprivate $include = array\n\t\t(\n\t\t\"font\",\n\t\t\"font-weight\"\n\t\t);\n\t/**\n\t * Regular expression matching the value.\n\t * \n\t * @var string\n\t */\n\tprivate $reMatch = null;\n\t/**\n\t * Regular expression replace the value.\n\t * \n\t * @var string\n\t */\n\tprivate $reReplace = \"\\\"\\${1}\\\" . \\$this->transformation[\\\"\\${2}\\\"] . \\\"\\${3}\\\"\";\n\t/**\n\t * Transformation table used by the {@link CssConvertFontWeightMinifierPlugin::$reReplace replace regular expression}.\n\t * \n\t * @var array\n\t */\n\tprivate $transformation = array\n\t\t(\n\t\t\"normal\"\t=> \"400\",\n \t\t\"bold\"\t\t=> \"700\"\n\t\t);\n\t/**\n\t * Overwrites {@link aCssMinifierPlugin::__construct()}.\n\t * \n\t * The constructor will create the {@link CssConvertFontWeightMinifierPlugin::$reReplace replace regular expression}\n\t * based on the {@link CssConvertFontWeightMinifierPlugin::$transformation transformation table}.\n\t * \n\t * @param CssMinifier $minifier The CssMinifier object of this plugin.\n\t * @return void\n\t */\n\tpublic function __construct(CssMinifier $minifier)\n\t\t{\n\t\t$this->reMatch = \"/(^|\\s)+(\" . implode(\"|\", array_keys($this->transformation)). \")(\\s|$)+/eiS\";\n\t\tparent::__construct($minifier);\n\t\t}\n\t/**\n\t * Implements {@link aCssMinifierPlugin::minify()}.\n\t * \n\t * @param aCssToken $token Token to process\n\t * @return boolean Return TRUE to break the processing of this token; FALSE to continue\n\t */\n\tpublic function apply(aCssToken &$token)\n\t\t{\n\t\tif (in_array($token->Property, $this->include) && preg_match($this->reMatch, $token->Value, $m))\n\t\t\t{\n\t\t\t$token->Value = preg_replace($this->reMatch, $this->reReplace, $token->Value);\n\t\t\t}\n\t\treturn false;\n\t\t}\n\t/**\n\t * Implements {@link aMinifierPlugin::getTriggerTokens()}\n\t * \n\t * @return array\n\t */\n\tpublic function getTriggerTokens()\n\t\t{\n\t\treturn array\n\t\t\t(\n\t\t\t\"CssAtFontFaceDeclarationToken\",\n\t\t\t\"CssAtPageDeclarationToken\",\n\t\t\t\"CssRulesetDeclarationToken\"\n\t\t\t);\n\t\t}\n\t}\n\n/**\n * This {@link aCssMinifierPlugin} will compress several unit values to their short notations. Examples:\n * \n * <code>\n * padding: 0.5em;\n * border: 0px;\n * margin: 0 0 0 0;\n * </code>\n * \n * Will get compressed to:\n * \n * <code>\n * padding:.5px;\n * border:0;\n * margin:0;\n * </code>\n * \n * --\n *\n * @package\t\tCssMin/Minifier/Plugins\n * @link\t\thttp://code.google.com/p/cssmin/\n * @author\t\tJoe Scylla <joe.scylla@gmail.com>\n * @copyright\t2008 - 2011 Joe Scylla <joe.scylla@gmail.com>\n * @license\t\thttp://opensource.org/licenses/mit-license.php MIT License\n * @version\t\t3.0.1\n */\nclass CssCompressUnitValuesMinifierPlugin extends aCssMinifierPlugin\n\t{\n\t/**\n\t * Regular expression used for matching and replacing unit values.\n\t * \n\t * @var array\n\t */\n\tprivate $re = array\n\t\t(\n\t\t\"/(^| |-)0\\.([0-9]+?)(0+)?(%|em|ex|px|in|cm|mm|pt|pc)/iS\" => \"\\${1}.\\${2}\\${4}\",\n\t\t\"/(^| )-?(\\.?)0(%|em|ex|px|in|cm|mm|pt|pc)/iS\" => \"\\${1}0\",\n\t\t\"/(^0\\s0\\s0\\s0)|(^0\\s0\\s0$)|(^0\\s0$)/iS\" => \"0\"\n\t\t);\n\t/**\n\t * Regular expression matching the value.\n\t * \n\t * @var string\n\t */\n\tprivate $reMatch = \"/(^| |-)0\\.([0-9]+?)(0+)?(%|em|ex|px|in|cm|mm|pt|pc)|(^| )-?(\\.?)0(%|em|ex|px|in|cm|mm|pt|pc)|(^0\\s0\\s0\\s0$)|(^0\\s0\\s0$)|(^0\\s0$)/iS\";\n\t/**\n\t * Implements {@link aCssMinifierPlugin::minify()}.\n\t * \n\t * @param aCssToken $token Token to process\n\t * @return boolean Return TRUE to break the processing of this token; FALSE to continue\n\t */\n\tpublic function apply(aCssToken &$token)\n\t\t{\n\t\tif (preg_match($this->reMatch, $token->Value))\n\t\t\t{\n\t\t\tforeach ($this->re as $reMatch => $reReplace)\n\t\t\t\t{\n\t\t\t\t$token->Value = preg_replace($reMatch, $reReplace, $token->Value);\n\t\t\t\t}\n\t\t\t}\n\t\treturn false;\n\t\t}\n\t/**\n\t * Implements {@link aMinifierPlugin::getTriggerTokens()}\n\t * \n\t * @return array\n\t */\n\tpublic function getTriggerTokens()\n\t\t{\n\t\treturn array\n\t\t\t(\n\t\t\t\"CssAtFontFaceDeclarationToken\",\n\t\t\t\"CssAtPageDeclarationToken\",\n\t\t\t\"CssRulesetDeclarationToken\"\n\t\t\t);\n\t\t}\n\t}\n\n/**\n * This {@link aCssMinifierPlugin} compress the content of expresssion() declaration values.\n * \n * For compression of expressions {@link https://github.com/rgrove/jsmin-php/ JSMin} will get used. JSMin have to be \n * already included or loadable via {@link http://goo.gl/JrW54 PHP autoloading}. \n * \n * @package\t\tCssMin/Minifier/Plugins\n * @link\t\thttp://code.google.com/p/cssmin/\n * @author\t\tJoe Scylla <joe.scylla@gmail.com>\n * @copyright\t2008 - 2011 Joe Scylla <joe.scylla@gmail.com>\n * @license\t\thttp://opensource.org/licenses/mit-license.php MIT License\n * @version\t\t3.0.1\n */\nclass CssCompressExpressionValuesMinifierPlugin extends aCssMinifierPlugin\n\t{\n\t/**\n\t * Implements {@link aCssMinifierPlugin::minify()}.\n\t * \n\t * @param aCssToken $token Token to process\n\t * @return boolean Return TRUE to break the processing of this token; FALSE to continue\n\t */\n\tpublic function apply(aCssToken &$token)\n\t\t{\n\t\tif (class_exists(\"JSMin\") && stripos($token->Value, \"expression(\") !== false)\n\t\t\t{\n\t\t\t$value\t= $token->Value;\n\t\t\t$value\t= substr($token->Value, stripos($token->Value, \"expression(\") + 10);\n\t\t\t$value\t= trim(JSMin::minify($value));\n\t\t\t$token->Value = \"expression(\" . $value . \")\";\n\t\t\t}\n\t\treturn false;\n\t\t}\n\t/**\n\t * Implements {@link aMinifierPlugin::getTriggerTokens()}\n\t * \n\t * @return array\n\t */\n\tpublic function getTriggerTokens()\n\t\t{\n\t\treturn array\n\t\t\t(\n\t\t\t\"CssAtFontFaceDeclarationToken\",\n\t\t\t\"CssAtPageDeclarationToken\",\n\t\t\t\"CssRulesetDeclarationToken\"\n\t\t\t);\n\t\t}\n\t}\n\n/**\n * This {@link aCssMinifierPlugin} will convert hexadecimal color value with 6 chars to their 3 char hexadecimal \n * notation (if possible). \n * \n * Example:\n * <code>\n * color: #aabbcc;\n * </code>\n * \n * Will get converted to:\n * <code>\n * color:#abc;\n * </code>\n * \n * @package\t\tCssMin/Minifier/Plugins\n * @link\t\thttp://code.google.com/p/cssmin/\n * @author\t\tJoe Scylla <joe.scylla@gmail.com>\n * @copyright\t2008 - 2011 Joe Scylla <joe.scylla@gmail.com>\n * @license\t\thttp://opensource.org/licenses/mit-license.php MIT License\n * @version\t\t3.0.1\n */\nclass CssCompressColorValuesMinifierPlugin extends aCssMinifierPlugin\n\t{\n\t/**\n\t * Regular expression matching 6 char hexadecimal color values.\n\t * \n\t * @var string\n\t */\n\tprivate $reMatch = \"/\\#([0-9a-f]{6})/iS\";\n\t/**\n\t * Implements {@link aCssMinifierPlugin::minify()}.\n\t * \n\t * @param aCssToken $token Token to process\n\t * @return boolean Return TRUE to break the processing of this token; FALSE to continue\n\t */\n\tpublic function apply(aCssToken &$token)\n\t\t{\n\t\tif (strpos($token->Value, \"#\") !== false && preg_match($this->reMatch, $token->Value, $m))\n\t\t\t{\n\t\t\t$value = strtolower($m[1]);\n\t\t\tif ($value[0] == $value[1] && $value[2] == $value[3] && $value[4] == $value[5])\n\t\t\t\t{\n\t\t\t\t$token->Value = str_replace($m[0], \"#\" . $value[0] . $value[2] . $value[4], $token->Value);\n\t\t\t\t}\n\t\t\t}\n\t\treturn false;\n\t\t}\n\t/**\n\t * Implements {@link aMinifierPlugin::getTriggerTokens()}\n\t * \n\t * @return array\n\t */\n\tpublic function getTriggerTokens()\n\t\t{\n\t\treturn array\n\t\t\t(\n\t\t\t\"CssAtFontFaceDeclarationToken\",\n\t\t\t\"CssAtPageDeclarationToken\",\n\t\t\t\"CssRulesetDeclarationToken\"\n\t\t\t);\n\t\t}\n\t}\n\n/**\n * This {@link aCssToken CSS token} represents a CSS comment.\n * \n * @package\t\tCssMin/Tokens\n * @link\t\thttp://code.google.com/p/cssmin/\n * @author\t\tJoe Scylla <joe.scylla@gmail.com>\n * @copyright\t2008 - 2011 Joe Scylla <joe.scylla@gmail.com>\n * @license\t\thttp://opensource.org/licenses/mit-license.php MIT License\n * @version\t\t3.0.1\n */\nclass CssCommentToken extends aCssToken\n\t{\n\t/**\n\t * Comment as Text.\n\t * \n\t * @var string\n\t */\n\tpublic $Comment = \"\";\n\t/**\n\t * Set the properties of a comment token.\n\t * \n\t * @param string $comment Comment including comment delimiters \n\t * @return void\n\t */\n\tpublic function __construct($comment)\n\t\t{\n\t\t$this->Comment = $comment;\n\t\t}\n\t/**\n\t * Implements {@link aCssToken::__toString()}.\n\t * \n\t * @return string\n\t */\n\tpublic function __toString()\n\t\t{\n\t\treturn $this->Comment;\n\t\t}\n\t}\n\n/**\n * {@link aCssParserPlugin Parser plugin} for parsing comments.\n * \n * Adds a {@link CssCommentToken} to the parser if a comment was found.\n * \n * @package\t\tCssMin/Parser/Plugins\n * @link\t\thttp://code.google.com/p/cssmin/\n * @author\t\tJoe Scylla <joe.scylla@gmail.com>\n * @copyright\t2008 - 2011 Joe Scylla <joe.scylla@gmail.com>\n * @license\t\thttp://opensource.org/licenses/mit-license.php MIT License\n * @version\t\t3.0.1\n */\nclass CssCommentParserPlugin extends aCssParserPlugin\n\t{\n\t/**\n\t * Implements {@link aCssParserPlugin::getTriggerChars()}.\n\t * \n\t * @return array\n\t */\n\tpublic function getTriggerChars()\n\t\t{\n\t\treturn array(\"*\", \"/\");\n\t\t}\n\t/**\n\t * Implements {@link aCssParserPlugin::getTriggerStates()}.\n\t * \n\t * @return array\n\t */\n\tpublic function getTriggerStates()\n\t\t{\n\t\treturn false;\n\t\t}\n\t/**\n\t * Stored buffer for restore.\n\t * \n\t * @var string\n\t */\n\tprivate $restoreBuffer = \"\";\n\t/**\n\t * Implements {@link aCssParserPlugin::parse()}.\n\t * \n\t * @param integer $index Current index\n\t * @param string $char Current char\n\t * @param string $previousChar Previous char\n\t * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing\n\t */\n\tpublic function parse($index, $char, $previousChar, $state)\n\t\t{\n\t\tif ($char === \"*\" && $previousChar === \"/\" && $state !== \"T_COMMENT\")\n\t\t\t{\n\t\t\t$this->parser->pushState(\"T_COMMENT\");\n\t\t\t$this->parser->setExclusive(__CLASS__);\n\t\t\t$this->restoreBuffer = substr($this->parser->getAndClearBuffer(), 0, -2);\n\t\t\t}\n\t\telseif ($char === \"/\" && $previousChar === \"*\" && $state === \"T_COMMENT\")\n\t\t\t{\n\t\t\t$this->parser->popState();\n\t\t\t$this->parser->unsetExclusive();\n\t\t\t$this->parser->appendToken(new CssCommentToken(\"/*\" . $this->parser->getAndClearBuffer()));\n\t\t\t$this->parser->setBuffer($this->restoreBuffer);\n\t\t\t}\n\t\telse\n\t\t\t{\n\t\t\treturn false;\n\t\t\t}\n\t\treturn true;\n\t\t}\n\t}\n\n/**\n * This {@link aCssToken CSS token} represents the start of a @variables at-rule block.\n *\n * @package\t\tCssMin/Tokens\n * @link\t\thttp://code.google.com/p/cssmin/\n * @author\t\tJoe Scylla <joe.scylla@gmail.com>\n * @copyright\t2008 - 2011 Joe Scylla <joe.scylla@gmail.com>\n * @license\t\thttp://opensource.org/licenses/mit-license.php MIT License\n * @version\t\t3.0.1\n */\nclass CssAtVariablesStartToken extends aCssAtBlockStartToken\n\t{\n\t/**\n\t * Media types of the @variables at-rule block.\n\t * \n\t * @var array\n\t */\n\tpublic $MediaTypes = array();\n\t/**\n\t * Set the properties of a @variables at-rule token.\n\t * \n\t * @param array $mediaTypes Media types\n\t * @return void\n\t */\n\tpublic function __construct($mediaTypes = null)\n\t\t{\n\t\t$this->MediaTypes = $mediaTypes ? $mediaTypes : array(\"all\");\n\t\t}\n\t/**\n\t * Implements {@link aCssToken::__toString()}.\n\t * \n\t * @return string\n\t */\n\tpublic function __toString()\n\t\t{\n\t\treturn \"\";\n\t\t}\n\t}\n\n/**\n * {@link aCssParserPlugin Parser plugin} for parsing @variables at-rule block with including declarations.\n * \n * Found @variables at-rule blocks will add a {@link CssAtVariablesStartToken} and {@link CssAtVariablesEndToken} to the \n * parser; including declarations as {@link CssAtVariablesDeclarationToken}.\n * \n * @package\t\tCssMin/Parser/Plugins\n * @link\t\thttp://code.google.com/p/cssmin/\n * @author\t\tJoe Scylla <joe.scylla@gmail.com>\n * @copyright\t2008 - 2011 Joe Scylla <joe.scylla@gmail.com>\n * @license\t\thttp://opensource.org/licenses/mit-license.php MIT License\n * @version\t\t3.0.1\n */\nclass CssAtVariablesParserPlugin extends aCssParserPlugin\n\t{\n\t/**\n\t * Implements {@link aCssParserPlugin::getTriggerChars()}.\n\t * \n\t * @return array\n\t */\n\tpublic function getTriggerChars()\n\t\t{\n\t\treturn array(\"@\", \"{\", \"}\", \":\", \";\");\n\t\t}\n\t/**\n\t * Implements {@link aCssParserPlugin::getTriggerStates()}.\n\t * \n\t * @return array\n\t */\n\tpublic function getTriggerStates()\n\t\t{\n\t\treturn array(\"T_DOCUMENT\", \"T_AT_VARIABLES::PREPARE\", \"T_AT_VARIABLES\", \"T_AT_VARIABLES_DECLARATION\");\n\t\t}\n\t/**\n\t * Implements {@link aCssParserPlugin::parse()}.\n\t * \n\t * @param integer $index Current index\n\t * @param string $char Current char\n\t * @param string $previousChar Previous char\n\t * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing\n\t */\n\tpublic function parse($index, $char, $previousChar, $state)\n\t\t{\n\t\t// Start of @variables at-rule block\n\t\tif ($char === \"@\" && $state === \"T_DOCUMENT\" && strtolower(substr($this->parser->getSource(), $index, 10)) === \"@variables\")\n\t\t\t{\n\t\t\t$this->parser->pushState(\"T_AT_VARIABLES::PREPARE\");\n\t\t\t$this->parser->clearBuffer();\n\t\t\treturn $index + 10;\n\t\t\t}\n\t\t// Start of @variables declarations\n\t\telseif ($char === \"{\" && $state === \"T_AT_VARIABLES::PREPARE\")\n\t\t\t{\n\t\t\t$this->parser->setState(\"T_AT_VARIABLES\");\n\t\t\t$mediaTypes = array_filter(array_map(\"trim\", explode(\",\", $this->parser->getAndClearBuffer(\"{\"))));\n\t\t\t$this->parser->appendToken(new CssAtVariablesStartToken($mediaTypes));\n\t\t\t}\n\t\t// Start of @variables declaration\n\t\tif ($char === \":\" && $state === \"T_AT_VARIABLES\")\n\t\t\t{\n\t\t\t$this->buffer = $this->parser->getAndClearBuffer(\":\");\n\t\t\t$this->parser->pushState(\"T_AT_VARIABLES_DECLARATION\");\n\t\t\t}\n\t\t// Unterminated @variables declaration\n\t\telseif ($char === \":\" && $state === \"T_AT_VARIABLES_DECLARATION\")\n\t\t\t{\n\t\t\t// Ignore Internet Explorer filter declarations\n\t\t\tif ($this->buffer === \"filter\")\n\t\t\t\t{\n\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\tCssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . \": Unterminated @variables declaration\", $this->buffer . \":\" . $this->parser->getBuffer() . \"_\"));\n\t\t\t}\n\t\t// End of @variables declaration\n\t\telseif (($char === \";\" || $char === \"}\") && $state === \"T_AT_VARIABLES_DECLARATION\")\n\t\t\t{\n\t\t\t$value = $this->parser->getAndClearBuffer(\";}\");\n\t\t\tif (strtolower(substr($value, -10, 10)) === \"!important\")\n\t\t\t\t{\n\t\t\t\t$value = trim(substr($value, 0, -10));\n\t\t\t\t$isImportant = true;\n\t\t\t\t}\n\t\t\telse\n\t\t\t\t{\n\t\t\t\t$isImportant = false;\n\t\t\t\t}\n\t\t\t$this->parser->popState();\n\t\t\t$this->parser->appendToken(new CssAtVariablesDeclarationToken($this->buffer, $value, $isImportant));\n\t\t\t$this->buffer = \"\";\n\t\t\t}\n\t\t// End of @variables at-rule block\n\t\telseif ($char === \"}\" && $state === \"T_AT_VARIABLES\")\n\t\t\t{\n\t\t\t$this->parser->popState();\n\t\t\t$this->parser->clearBuffer();\n\t\t\t$this->parser->appendToken(new CssAtVariablesEndToken());\n\t\t\t}\n\t\telse\n\t\t\t{\n\t\t\treturn false;\n\t\t\t}\n\t\treturn true;\n\t\t}\n\t}\n\n/**\n * This {@link aCssToken CSS token} represents the end of a @variables at-rule block.\n *\n * @package\t\tCssMin/Tokens\n * @link\t\thttp://code.google.com/p/cssmin/\n * @author\t\tJoe Scylla <joe.scylla@gmail.com>\n * @copyright\t2008 - 2011 Joe Scylla <joe.scylla@gmail.com>\n * @license\t\thttp://opensource.org/licenses/mit-license.php MIT License\n * @version\t\t3.0.1\n */\nclass CssAtVariablesEndToken extends aCssAtBlockEndToken\n\t{\n\t/**\n\t * Implements {@link aCssToken::__toString()}.\n\t * \n\t * @return string\n\t */\n\tpublic function __toString()\n\t\t{\n\t\treturn \"\";\n\t\t}\n\t}\n\n/**\n * This {@link aCssToken CSS token} represents a declaration of a @variables at-rule block.\n * \n * @package\t\tCssMin/Tokens\n * @link\t\thttp://code.google.com/p/cssmin/\n * @author\t\tJoe Scylla <joe.scylla@gmail.com>\n * @copyright\t2008 - 2011 Joe Scylla <joe.scylla@gmail.com>\n * @license\t\thttp://opensource.org/licenses/mit-license.php MIT License\n * @version\t\t3.0.1\n */\nclass CssAtVariablesDeclarationToken extends aCssDeclarationToken\n\t{\n\t/**\n\t * Implements {@link aCssToken::__toString()}.\n\t * \n\t * @return string\n\t */\n\tpublic function __toString()\n\t\t{\n\t\treturn \"\";\n\t\t}\n\t}\n\n/**\n* This {@link aCssToken CSS token} represents the start of a @page at-rule block.\n *\n * @package\t\tCssMin/Tokens\n * @link\t\thttp://code.google.com/p/cssmin/\n * @author\t\tJoe Scylla <joe.scylla@gmail.com>\n * @copyright\t2008 - 2011 Joe Scylla <joe.scylla@gmail.com>\n * @license\t\thttp://opensource.org/licenses/mit-license.php MIT License\n * @version\t\t3.0.1\n */\nclass CssAtPageStartToken extends aCssAtBlockStartToken\n\t{\n\t/**\n\t * Selector.\n\t * \n\t * @var string\n\t */\n\tpublic $Selector = \"\";\n\t/**\n\t * Sets the properties of the @page at-rule.\n\t * \n\t * @param string $selector Selector\n\t * @return void\n\t */\n\tpublic function __construct($selector = \"\")\n\t\t{\n\t\t$this->Selector = $selector;\n\t\t}\n\t/**\n\t * Implements {@link aCssToken::__toString()}.\n\t * \n\t * @return string\n\t */\n\tpublic function __toString()\n\t\t{\n\t\treturn \"@page\" . ($this->Selector ? \" \" . $this->Selector : \"\") . \"{\";\n\t\t}\n\t}\n\n/**\n * {@link aCssParserPlugin Parser plugin} for parsing @page at-rule block with including declarations.\n * \n * Found @page at-rule blocks will add a {@link CssAtPageStartToken} and {@link CssAtPageEndToken} to the \n * parser; including declarations as {@link CssAtPageDeclarationToken}.\n * \n * @package\t\tCssMin/Parser/Plugins\n * @link\t\thttp://code.google.com/p/cssmin/\n * @author\t\tJoe Scylla <joe.scylla@gmail.com>\n * @copyright\t2008 - 2011 Joe Scylla <joe.scylla@gmail.com>\n * @license\t\thttp://opensource.org/licenses/mit-license.php MIT License\n * @version\t\t3.0.1\n */\nclass CssAtPageParserPlugin extends aCssParserPlugin\n\t{\n\t/**\n\t * Implements {@link aCssParserPlugin::getTriggerChars()}.\n\t * \n\t * @return array\n\t */\n\tpublic function getTriggerChars()\n\t\t{\n\t\treturn array(\"@\", \"{\", \"}\", \":\", \";\");\n\t\t}\n\t/**\n\t * Implements {@link aCssParserPlugin::getTriggerStates()}.\n\t * \n\t * @return array\n\t */\n\tpublic function getTriggerStates()\n\t\t{\n\t\treturn array(\"T_DOCUMENT\", \"T_AT_PAGE::SELECTOR\", \"T_AT_PAGE\", \"T_AT_PAGE_DECLARATION\");\n\t\t}\n\t/**\n\t * Implements {@link aCssParserPlugin::parse()}.\n\t * \n\t * @param integer $index Current index\n\t * @param string $char Current char\n\t * @param string $previousChar Previous char\n\t * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing\n\t */\n\tpublic function parse($index, $char, $previousChar, $state)\n\t\t{\n\t\t// Start of @page at-rule block\n\t\tif ($char === \"@\" && $state === \"T_DOCUMENT\" && strtolower(substr($this->parser->getSource(), $index, 5)) === \"@page\")\n\t\t\t{\n\t\t\t$this->parser->pushState(\"T_AT_PAGE::SELECTOR\");\n\t\t\t$this->parser->clearBuffer();\n\t\t\treturn $index + 5;\n\t\t\t}\n\t\t// Start of @page declarations\n\t\telseif ($char === \"{\" && $state === \"T_AT_PAGE::SELECTOR\")\n\t\t\t{\n\t\t\t$selector = $this->parser->getAndClearBuffer(\"{\");\n\t\t\t$this->parser->setState(\"T_AT_PAGE\");\n\t\t\t$this->parser->clearBuffer();\n\t\t\t$this->parser->appendToken(new CssAtPageStartToken($selector));\n\t\t\t}\n\t\t// Start of @page declaration\n\t\telseif ($char === \":\" && $state === \"T_AT_PAGE\")\n\t\t\t{\n\t\t\t$this->parser->pushState(\"T_AT_PAGE_DECLARATION\");\n\t\t\t$this->buffer = $this->parser->getAndClearBuffer(\":\", true);\n\t\t\t}\n\t\t// Unterminated @font-face declaration\n\t\telseif ($char === \":\" && $state === \"T_AT_PAGE_DECLARATION\")\n\t\t\t{\n\t\t\t// Ignore Internet Explorer filter declarations\n\t\t\tif ($this->buffer === \"filter\")\n\t\t\t\t{\n\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\tCssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . \": Unterminated @page declaration\", $this->buffer . \":\" . $this->parser->getBuffer() . \"_\"));\n\t\t\t}\n\t\t// End of @page declaration\n\t\telseif (($char === \";\" || $char === \"}\") && $state == \"T_AT_PAGE_DECLARATION\")\n\t\t\t{\n\t\t\t$value = $this->parser->getAndClearBuffer(\";}\");\n\t\t\tif (strtolower(substr($value, -10, 10)) == \"!important\")\n\t\t\t\t{\n\t\t\t\t$value = trim(substr($value, 0, -10));\n\t\t\t\t$isImportant = true;\n\t\t\t\t}\n\t\t\telse\n\t\t\t\t{\n\t\t\t\t$isImportant = false;\n\t\t\t\t}\n\t\t\t$this->parser->popState();\n\t\t\t$this->parser->appendToken(new CssAtPageDeclarationToken($this->buffer, $value, $isImportant));\n\t\t\t// --\n\t\t\tif ($char === \"}\")\n\t\t\t\t{\n\t\t\t\t$this->parser->popState();\n\t\t\t\t$this->parser->appendToken(new CssAtPageEndToken());\n\t\t\t\t}\n\t\t\t$this->buffer = \"\";\n\t\t\t}\n\t\t// End of @page at-rule block\n\t\telseif ($char === \"}\" && $state === \"T_AT_PAGE\")\n\t\t\t{\n\t\t\t$this->parser->popState();\n\t\t\t$this->parser->clearBuffer();\n\t\t\t$this->parser->appendToken(new CssAtPageEndToken());\n\t\t\t}\n\t\telse\n\t\t\t{\n\t\t\treturn false;\n\t\t\t}\n\t\treturn true;\n\t\t}\n\t}\n\n/**\n * This {@link aCssToken CSS token} represents the end of a @page at-rule block.\n *\n * @package\t\tCssMin/Tokens\n * @link\t\thttp://code.google.com/p/cssmin/\n * @author\t\tJoe Scylla <joe.scylla@gmail.com>\n * @copyright\t2008 - 2011 Joe Scylla <joe.scylla@gmail.com>\n * @license\t\thttp://opensource.org/licenses/mit-license.php MIT License\n * @version\t\t3.0.1\n */\nclass CssAtPageEndToken extends aCssAtBlockEndToken\n\t{\n\t\n\t}\n\n/**\n * This {@link aCssToken CSS token} represents a declaration of a @page at-rule block.\n * \n * @package\t\tCssMin/Tokens\n * @link\t\thttp://code.google.com/p/cssmin/\n * @author\t\tJoe Scylla <joe.scylla@gmail.com>\n * @copyright\t2008 - 2011 Joe Scylla <joe.scylla@gmail.com>\n * @license\t\thttp://opensource.org/licenses/mit-license.php MIT License\n * @version\t\t3.0.1\n */\nclass CssAtPageDeclarationToken extends aCssDeclarationToken\n\t{\n\t\n\t}\n\n/**\n * This {@link aCssToken CSS token} represents the start of a @media at-rule block.\n *\n * @package\t\tCssMin/Tokens\n * @link\t\thttp://code.google.com/p/cssmin/\n * @author\t\tJoe Scylla <joe.scylla@gmail.com>\n * @copyright\t2008 - 2011 Joe Scylla <joe.scylla@gmail.com>\n * @license\t\thttp://opensource.org/licenses/mit-license.php MIT License\n * @version\t\t3.0.1\n */\nclass CssAtMediaStartToken extends aCssAtBlockStartToken\n\t{\n\t/**\n\t * Sets the properties of the @media at-rule.\n\t * \n\t * @param array $mediaTypes Media types\n\t * @return void\n\t */\n\tpublic function __construct(array $mediaTypes = array())\n\t\t{\n\t\t$this->MediaTypes = $mediaTypes;\n\t\t}\n\t/**\n\t * Implements {@link aCssToken::__toString()}.\n\t * \n\t * @return string\n\t */\n\tpublic function __toString()\n\t\t{\n\t\treturn \"@media \" . implode(\",\", $this->MediaTypes) . \"{\";\n\t\t}\n\t}\n\n/**\n * {@link aCssParserPlugin Parser plugin} for parsing @media at-rule block.\n * \n * Found @media at-rule blocks will add a {@link CssAtMediaStartToken} and {@link CssAtMediaEndToken} to the parser. \n * This plugin will also set the the current media types using {@link CssParser::setMediaTypes()} and\n * {@link CssParser::unsetMediaTypes()}.\n *\n * @package\t\tCssMin/Parser/Plugins\n * @link\t\thttp://code.google.com/p/cssmin/\n * @author\t\tJoe Scylla <joe.scylla@gmail.com>\n * @copyright\t2008 - 2011 Joe Scylla <joe.scylla@gmail.com>\n * @license\t\thttp://opensource.org/licenses/mit-license.php MIT License\n * @version\t\t3.0.1\n */\nclass CssAtMediaParserPlugin extends aCssParserPlugin\n\t{\n\t/**\n\t * Implements {@link aCssParserPlugin::getTriggerChars()}.\n\t * \n\t * @return array\n\t */\n\tpublic function getTriggerChars()\n\t\t{\n\t\treturn array(\"@\", \"{\", \"}\");\n\t\t}\n\t/**\n\t * Implements {@link aCssParserPlugin::getTriggerStates()}.\n\t * \n\t * @return array\n\t */\n\tpublic function getTriggerStates()\n\t\t{\n\t\treturn array(\"T_DOCUMENT\", \"T_AT_MEDIA::PREPARE\", \"T_AT_MEDIA\");\n\t\t}\n\t/**\n\t * Implements {@link aCssParserPlugin::parse()}.\n\t * \n\t * @param integer $index Current index\n\t * @param string $char Current char\n\t * @param string $previousChar Previous char\n\t * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing\n\t */\n\tpublic function parse($index, $char, $previousChar, $state)\n\t\t{\n\t\tif ($char === \"@\" && $state === \"T_DOCUMENT\" && strtolower(substr($this->parser->getSource(), $index, 6)) === \"@media\")\n\t\t\t{\n\t\t\t$this->parser->pushState(\"T_AT_MEDIA::PREPARE\");\n\t\t\t$this->parser->clearBuffer();\n\t\t\treturn $index + 6;\n\t\t\t}\n\t\telseif ($char === \"{\" && $state === \"T_AT_MEDIA::PREPARE\")\n\t\t\t{\n\t\t\t$mediaTypes = array_filter(array_map(\"trim\", explode(\",\", $this->parser->getAndClearBuffer(\"{\"))));\n\t\t\t$this->parser->setMediaTypes($mediaTypes);\n\t\t\t$this->parser->setState(\"T_AT_MEDIA\");\n\t\t\t$this->parser->appendToken(new CssAtMediaStartToken($mediaTypes));\n\t\t\t}\n\t\telseif ($char === \"}\" && $state === \"T_AT_MEDIA\")\n\t\t\t{\n\t\t\t$this->parser->appendToken(new CssAtMediaEndToken());\n\t\t\t$this->parser->clearBuffer();\n\t\t\t$this->parser->unsetMediaTypes();\n\t\t\t$this->parser->popState();\n\t\t\t}\n\t\telse\n\t\t\t{\n\t\t\treturn false;\n\t\t\t}\n\t\treturn true;\n\t\t}\n\t}\n\n/**\n * This {@link aCssToken CSS token} represents the end of a @media at-rule block.\n *\n * @package\t\tCssMin/Tokens\n * @link\t\thttp://code.google.com/p/cssmin/\n * @author\t\tJoe Scylla <joe.scylla@gmail.com>\n * @copyright\t2008 - 2011 Joe Scylla <joe.scylla@gmail.com>\n * @license\t\thttp://opensource.org/licenses/mit-license.php MIT License\n * @version\t\t3.0.1\n */\nclass CssAtMediaEndToken extends aCssAtBlockEndToken\n\t{\n\t\n\t}\n\n/**\n * This {@link aCssToken CSS token} represents the start of a @keyframes at-rule block.\n *\n * @package\t\tCssMin/Tokens\n * @link\t\thttp://code.google.com/p/cssmin/\n * @author\t\tJoe Scylla <joe.scylla@gmail.com>\n * @copyright\t2008 - 2011 Joe Scylla <joe.scylla@gmail.com>\n * @license\t\thttp://opensource.org/licenses/mit-license.php MIT License\n * @version\t\t3.0.1\n */\nclass CssAtKeyframesStartToken extends aCssAtBlockStartToken\n\t{\n\t/**\n\t * Name of the at-rule.\n\t * \n\t * @var string\n\t */\n\tpublic $AtRuleName = \"keyframes\";\n\t/**\n\t * Name\n\t * \n\t * @var string\n\t */\n\tpublic $Name = \"\";\n\t/**\n\t * Sets the properties of the @page at-rule.\n\t * \n\t * @param string $selector Selector\n\t * @return void\n\t */\n\tpublic function __construct($name, $atRuleName = null)\n\t\t{\n\t\t$this->Name = $name;\n\t\tif (!is_null($atRuleName))\n\t\t\t{\n\t\t\t$this->AtRuleName = $atRuleName;\n\t\t\t}\n\t\t}\n\t/**\n\t * Implements {@link aCssToken::__toString()}.\n\t * \n\t * @return string\n\t */\n\tpublic function __toString()\n\t\t{\n\t\treturn \"@\" . $this->AtRuleName . \" \\\"\" . $this->Name . \"\\\"{\";\n\t\t}\n\t}\n\n/**\n * This {@link aCssToken CSS token} represents the start of a ruleset of a @keyframes at-rule block.\n * \n * @package\t\tCssMin/Tokens\n * @link\t\thttp://code.google.com/p/cssmin/\n * @author\t\tJoe Scylla <joe.scylla@gmail.com>\n * @copyright\t2008 - 2011 Joe Scylla <joe.scylla@gmail.com>\n * @license\t\thttp://opensource.org/licenses/mit-license.php MIT License\n * @version\t\t3.0.1\n */\nclass CssAtKeyframesRulesetStartToken extends aCssRulesetStartToken\n\t{\n\t/**\n\t * Array of selectors.\n\t * \n\t * @var array\n\t */\n\tpublic $Selectors = array();\n\t/**\n\t * Set the properties of a ruleset token.\n\t * \n\t * @param array $selectors Selectors of the ruleset \n\t * @return void\n\t */\n\tpublic function __construct(array $selectors = array())\n\t\t{\n\t\t$this->Selectors = $selectors;\n\t\t}\n\t/**\n\t * Implements {@link aCssToken::__toString()}.\n\t * \n\t * @return string\n\t */\n\tpublic function __toString()\n\t\t{\n\t\treturn implode(\",\", $this->Selectors) . \"{\";\n\t\t}\n\t}\n\n/**\n * This {@link aCssToken CSS token} represents the end of a ruleset of a @keyframes at-rule block.\n * \n * @package\t\tCssMin/Tokens\n * @link\t\thttp://code.google.com/p/cssmin/\n * @author\t\tJoe Scylla <joe.scylla@gmail.com>\n * @copyright\t2008 - 2011 Joe Scylla <joe.scylla@gmail.com>\n * @license\t\thttp://opensource.org/licenses/mit-license.php MIT License\n * @version\t\t3.0.1\n */\nclass CssAtKeyframesRulesetEndToken extends aCssRulesetEndToken\n\t{\n\t\n\t}\n\n/**\n * This {@link aCssToken CSS token} represents a ruleset declaration of a @keyframes at-rule block.\n *\n * @package\t\tCssMin/Tokens\n * @link\t\thttp://code.google.com/p/cssmin/\n * @author\t\tJoe Scylla <joe.scylla@gmail.com>\n * @copyright\t2008 - 2011 Joe Scylla <joe.scylla@gmail.com>\n * @license\t\thttp://opensource.org/licenses/mit-license.php MIT License\n * @version\t\t3.0.1\n */\nclass CssAtKeyframesRulesetDeclarationToken extends aCssDeclarationToken\n\t{\n\t\n\t}\n\n/**\n * {@link aCssParserPlugin Parser plugin} for parsing @keyframes at-rule blocks, rulesets and declarations.\n * \n * @package\t\tCssMin/Parser/Plugins\n * @link\t\thttp://code.google.com/p/cssmin/\n * @author\t\tJoe Scylla <joe.scylla@gmail.com>\n * @copyright\t2008 - 2011 Joe Scylla <joe.scylla@gmail.com>\n * @license\t\thttp://opensource.org/licenses/mit-license.php MIT License\n * @version\t\t3.0.1\n */\nclass CssAtKeyframesParserPlugin extends aCssParserPlugin\n\t{\n\t/**\n\t * @var string Keyword\n\t */\n\tprivate $atRuleName = \"\";\n\t/**\n\t * Selectors.\n\t * \n\t * @var array\n\t */\n\tprivate $selectors = array();\n\t/**\n\t * Implements {@link aCssParserPlugin::getTriggerChars()}.\n\t * \n\t * @return array\n\t */\n\tpublic function getTriggerChars()\n\t\t{\n\t\treturn array(\"@\", \"{\", \"}\", \":\", \",\", \";\");\n\t\t}\n\t/**\n\t * Implements {@link aCssParserPlugin::getTriggerStates()}.\n\t * \n\t * @return array\n\t */\n\tpublic function getTriggerStates()\n\t\t{\n\t\treturn array(\"T_DOCUMENT\", \"T_AT_KEYFRAMES::NAME\", \"T_AT_KEYFRAMES\", \"T_AT_KEYFRAMES_RULESETS\", \"T_AT_KEYFRAMES_RULESET\", \"T_AT_KEYFRAMES_RULESET_DECLARATION\");\n\t\t}\n\t/**\n\t * Implements {@link aCssParserPlugin::parse()}.\n\t * \n\t * @param integer $index Current index\n\t * @param string $char Current char\n\t * @param string $previousChar Previous char\n\t * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing\n\t */\n\tpublic function parse($index, $char, $previousChar, $state)\n\t\t{\n\t\t// Start of @keyframes at-rule block\n\t\tif ($char === \"@\" && $state === \"T_DOCUMENT\" && strtolower(substr($this->parser->getSource(), $index, 10)) === \"@keyframes\") \n\t\t\t{\n\t\t\t$this->atRuleName = \"keyframes\";\n\t\t\t$this->parser->pushState(\"T_AT_KEYFRAMES::NAME\");\n\t\t\t$this->parser->clearBuffer();\n\t\t\treturn $index + 10;\n\t\t\t}\n\t\t// Start of @keyframes at-rule block (@-moz-keyframes)\n\t\telseif ($char === \"@\" && $state === \"T_DOCUMENT\" && strtolower(substr($this->parser->getSource(), $index, 15)) === \"@-moz-keyframes\")\n\t\t\t{\n\t\t\t$this->atRuleName = \"-moz-keyframes\";\n\t\t\t$this->parser->pushState(\"T_AT_KEYFRAMES::NAME\");\n\t\t\t$this->parser->clearBuffer();\n\t\t\treturn $index + 15;\n\t\t\t}\n\t\t// Start of @keyframes at-rule block (@-webkit-keyframes)\n\t\telseif ($char === \"@\" && $state === \"T_DOCUMENT\" && strtolower(substr($this->parser->getSource(), $index, 18)) === \"@-webkit-keyframes\")\n\t\t\t{\n\t\t\t$this->atRuleName = \"-webkit-keyframes\";\n\t\t\t$this->parser->pushState(\"T_AT_KEYFRAMES::NAME\");\n\t\t\t$this->parser->clearBuffer();\n\t\t\treturn $index + 18;\n\t\t\t}\n\t\t// Start of @keyframes rulesets\n\t\telseif ($char === \"{\" && $state === \"T_AT_KEYFRAMES::NAME\")\n\t\t\t{\n\t\t\t$name = $this->parser->getAndClearBuffer(\"{\\\"'\");\n\t\t\t$this->parser->setState(\"T_AT_KEYFRAMES_RULESETS\");\n\t\t\t$this->parser->clearBuffer();\n\t\t\t$this->parser->appendToken(new CssAtKeyframesStartToken($name, $this->atRuleName));\n\t\t\t}\n\t\t// Start of @keyframe ruleset and selectors\n\t\tif ($char === \",\" && $state === \"T_AT_KEYFRAMES_RULESETS\")\n\t\t\t{\n\t\t\t$this->selectors[] = $this->parser->getAndClearBuffer(\",{\");\n\t\t\t}\n\t\t// Start of a @keyframes ruleset\n\t\telseif ($char === \"{\" && $state === \"T_AT_KEYFRAMES_RULESETS\")\n\t\t\t{\n\t\t\tif ($this->parser->getBuffer() !== \"\")\n\t\t\t\t{\n\t\t\t\t$this->selectors[] = $this->parser->getAndClearBuffer(\",{\");\n\t\t\t\t$this->parser->pushState(\"T_AT_KEYFRAMES_RULESET\");\n\t\t\t\t$this->parser->appendToken(new CssAtKeyframesRulesetStartToken($this->selectors));\n\t\t\t\t$this->selectors = array();\n\t\t\t\t}\n\t\t\t}\n\t\t// Start of @keyframes ruleset declaration\n\t\telseif ($char === \":\" && $state === \"T_AT_KEYFRAMES_RULESET\")\n\t\t\t{\n\t\t\t$this->parser->pushState(\"T_AT_KEYFRAMES_RULESET_DECLARATION\");\n\t\t\t$this->buffer = $this->parser->getAndClearBuffer(\":;\", true);\n\t\t\t}\n\t\t// Unterminated @keyframes ruleset declaration\n\t\telseif ($char === \":\" && $state === \"T_AT_KEYFRAMES_RULESET_DECLARATION\")\n\t\t\t{\n\t\t\t// Ignore Internet Explorer filter declarations\n\t\t\tif ($this->buffer === \"filter\")\n\t\t\t\t{\n\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\tCssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . \": Unterminated @keyframes ruleset declaration\", $this->buffer . \":\" . $this->parser->getBuffer() . \"_\"));\n\t\t\t}\n\t\t// End of declaration\n\t\telseif (($char === \";\" || $char === \"}\") && $state === \"T_AT_KEYFRAMES_RULESET_DECLARATION\")\n\t\t\t{\n\t\t\t$value = $this->parser->getAndClearBuffer(\";}\");\n\t\t\tif (strtolower(substr($value, -10, 10)) === \"!important\")\n\t\t\t\t{\n\t\t\t\t$value = trim(substr($value, 0, -10));\n\t\t\t\t$isImportant = true;\n\t\t\t\t}\n\t\t\telse\n\t\t\t\t{\n\t\t\t\t$isImportant = false;\n\t\t\t\t}\n\t\t\t$this->parser->popState();\n\t\t\t$this->parser->appendToken(new CssAtKeyframesRulesetDeclarationToken($this->buffer, $value, $isImportant));\n\t\t\t// Declaration ends with a right curly brace; so we have to end the ruleset\n\t\t\tif ($char === \"}\")\n\t\t\t\t{\n\t\t\t\t$this->parser->appendToken(new CssAtKeyframesRulesetEndToken());\n\t\t\t\t$this->parser->popState();\n\t\t\t\t}\n\t\t\t$this->buffer = \"\";\n\t\t\t}\n\t\t// End of @keyframes ruleset\n\t\telseif ($char === \"}\" && $state === \"T_AT_KEYFRAMES_RULESET\")\n\t\t\t{\n\t\t\t$this->parser->clearBuffer();\n\t\t\t\n\t\t\t$this->parser->popState();\n\t\t\t$this->parser->appendToken(new CssAtKeyframesRulesetEndToken());\n\t\t\t}\n\t\t// End of @keyframes rulesets\n\t\telseif ($char === \"}\" && $state === \"T_AT_KEYFRAMES_RULESETS\")\n\t\t\t{\n\t\t\t$this->parser->clearBuffer();\n\t\t\t$this->parser->popState();\n\t\t\t$this->parser->appendToken(new CssAtKeyframesEndToken());\n\t\t\t}\n\t\telse\n\t\t\t{\n\t\t\treturn false;\n\t\t\t}\n\t\treturn true;\n\t\t}\n\t}\n\n/**\n * This {@link aCssToken CSS token} represents the end of a @keyframes at-rule block.\n *\n * @package\t\tCssMin/Tokens\n * @link\t\thttp://code.google.com/p/cssmin/\n * @author\t\tJoe Scylla <joe.scylla@gmail.com>\n * @copyright\t2008 - 2011 Joe Scylla <joe.scylla@gmail.com>\n * @license\t\thttp://opensource.org/licenses/mit-license.php MIT License\n * @version\t\t3.0.1\n */\nclass CssAtKeyframesEndToken extends aCssAtBlockEndToken\n\t{\n\t\n\t}\n\n/**\n * This {@link aCssToken CSS token} represents a @import at-rule.\n * \n * @package\t\tCssMin/Tokens\n * @link\t\thttp://code.google.com/p/cssmin/\n * @author\t\tJoe Scylla <joe.scylla@gmail.com>\n * @copyright\t2008 - 2011 Joe Scylla <joe.scylla@gmail.com>\n * @license\t\thttp://opensource.org/licenses/mit-license.php MIT License\n * @version\t\t3.0.1.b1 (2001-02-22)\n */\nclass CssAtImportToken extends aCssToken\n\t{\n\t/**\n\t * Import path of the @import at-rule.\n\t * \n\t * @var string\n\t */\n\tpublic $Import = \"\";\n\t/**\n\t * Media types of the @import at-rule.\n\t * \n\t * @var array\n\t */\n\tpublic $MediaTypes = array();\n\t/**\n\t * Set the properties of a @import at-rule token.\n\t * \n\t * @param string $import Import path\n\t * @param array $mediaTypes Media types\n\t * @return void\n\t */\n\tpublic function __construct($import, $mediaTypes)\n\t\t{\n\t\t$this->Import\t\t= $import;\n\t\t$this->MediaTypes\t= $mediaTypes ? $mediaTypes : array();\n\t\t}\n\t/**\n\t * Implements {@link aCssToken::__toString()}.\n\t * \n\t * @return string\n\t */\n\tpublic function __toString()\n\t\t{\n\t\treturn \"@import \\\"\" . $this->Import . \"\\\"\" . (count($this->MediaTypes) > 0 ? \" \"  . implode(\",\", $this->MediaTypes) : \"\"). \";\";\n\t\t}\n\t}\n\n/**\n * {@link aCssParserPlugin Parser plugin} for parsing @import at-rule.\n * \n * If a @import at-rule was found this plugin will add a {@link CssAtImportToken} to the parser.\n * \n * @package\t\tCssMin/Parser/Plugins\n * @link\t\thttp://code.google.com/p/cssmin/\n * @author\t\tJoe Scylla <joe.scylla@gmail.com>\n * @copyright\t2008 - 2011 Joe Scylla <joe.scylla@gmail.com>\n * @license\t\thttp://opensource.org/licenses/mit-license.php MIT License\n * @version\t\t3.0.1\n */\nclass CssAtImportParserPlugin extends aCssParserPlugin\n\t{\n\t/**\n\t * Implements {@link aCssParserPlugin::getTriggerChars()}.\n\t * \n\t * @return array\n\t */\n\tpublic function getTriggerChars()\n\t\t{\n\t\treturn array(\"@\", \";\", \",\", \"\\n\");\n\t\t}\n\t/**\n\t * Implements {@link aCssParserPlugin::getTriggerStates()}.\n\t * \n\t * @return array\n\t */\n\tpublic function getTriggerStates()\n\t\t{\n\t\treturn array(\"T_DOCUMENT\", \"T_AT_IMPORT\");\n\t\t}\n\t/**\n\t * Implements {@link aCssParserPlugin::parse()}.\n\t * \n\t * @param integer $index Current index\n\t * @param string $char Current char\n\t * @param string $previousChar Previous char\n\t * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing\n\t */\n\tpublic function parse($index, $char, $previousChar, $state)\n\t\t{\n\t\tif ($char === \"@\" && $state === \"T_DOCUMENT\" && strtolower(substr($this->parser->getSource(), $index, 7)) === \"@import\")\n\t\t\t{\n\t\t\t$this->parser->pushState(\"T_AT_IMPORT\");\n\t\t\t$this->parser->clearBuffer();\n\t\t\treturn $index + 7;\n\t\t\t}\n\t\telseif (($char === \";\" || $char === \"\\n\") && $state === \"T_AT_IMPORT\")\n\t\t\t{\n\t\t\t$this->buffer = $this->parser->getAndClearBuffer(\";\");\n\t\t\t$pos = false;\n\t\t\tforeach (array(\")\", \"\\\"\", \"'\") as $needle)\n\t\t\t\t{\n\t\t\t\tif (($pos = strrpos($this->buffer, $needle)) !== false)\n\t\t\t\t\t{\n\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t$import = substr($this->buffer, 0, $pos + 1);\n\t\t\tif (stripos($import, \"url(\") === 0)\n\t\t\t\t{\n\t\t\t\t$import = substr($import, 4, -1);\n\t\t\t\t}\n\t\t\t$import = trim($import, \" \\t\\n\\r\\0\\x0B'\\\"\");\n\t\t\t$mediaTypes = array_filter(array_map(\"trim\", explode(\",\", trim(substr($this->buffer, $pos + 1), \" \\t\\n\\r\\0\\x0B{\"))));\n\t\t\tif ($pos)\n\t\t\t\t{\n\t\t\t\t$this->parser->appendToken(new CssAtImportToken($import, $mediaTypes));\n\t\t\t\t}\n\t\t\telse\n\t\t\t\t{\n\t\t\t\tCssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . \": Invalid @import at-rule syntax\", $this->parser->buffer));\n\t\t\t\t}\n\t\t\t$this->parser->popState();\n\t\t\t}\n\t\telse\n\t\t\t{\n\t\t\treturn false;\n\t\t\t}\n\t\treturn true;\n\t\t}\n\t}\n\n/**\n * This {@link aCssToken CSS token} represents the start of a @font-face at-rule block.\n *\n * @package\t\tCssMin/Tokens\n * @link\t\thttp://code.google.com/p/cssmin/\n * @author\t\tJoe Scylla <joe.scylla@gmail.com>\n * @copyright\t2008 - 2011 Joe Scylla <joe.scylla@gmail.com>\n * @license\t\thttp://opensource.org/licenses/mit-license.php MIT License\n * @version\t\t3.0.1\n */\nclass CssAtFontFaceStartToken extends aCssAtBlockStartToken\n\t{\n\t/**\n\t * Implements {@link aCssToken::__toString()}.\n\t * \n\t * @return string\n\t */\n\tpublic function __toString()\n\t\t{\n\t\treturn \"@font-face{\";\n\t\t}\n\t}\n\n/**\n * {@link aCssParserPlugin Parser plugin} for parsing @font-face at-rule block with including declarations.\n * \n * Found @font-face at-rule blocks will add a {@link CssAtFontFaceStartToken} and {@link CssAtFontFaceEndToken} to the \n * parser; including declarations as {@link CssAtFontFaceDeclarationToken}.\n * \n * @package\t\tCssMin/Parser/Plugins\n * @link\t\thttp://code.google.com/p/cssmin/\n * @author\t\tJoe Scylla <joe.scylla@gmail.com>\n * @copyright\t2008 - 2011 Joe Scylla <joe.scylla@gmail.com>\n * @license\t\thttp://opensource.org/licenses/mit-license.php MIT License\n * @version\t\t3.0.1\n */\nclass CssAtFontFaceParserPlugin extends aCssParserPlugin\n\t{\n\t/**\n\t * Implements {@link aCssParserPlugin::getTriggerChars()}.\n\t * \n\t * @return array\n\t */\n\tpublic function getTriggerChars()\n\t\t{\n\t\treturn array(\"@\", \"{\", \"}\", \":\", \";\");\n\t\t}\n\t/**\n\t * Implements {@link aCssParserPlugin::getTriggerStates()}.\n\t * \n\t * @return array\n\t */\n\tpublic function getTriggerStates()\n\t\t{\n\t\treturn array(\"T_DOCUMENT\", \"T_AT_FONT_FACE::PREPARE\", \"T_AT_FONT_FACE\", \"T_AT_FONT_FACE_DECLARATION\");\n\t\t}\n\t/**\n\t * Implements {@link aCssParserPlugin::parse()}.\n\t * \n\t * @param integer $index Current index\n\t * @param string $char Current char\n\t * @param string $previousChar Previous char\n\t * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing\n\t */\n\tpublic function parse($index, $char, $previousChar, $state)\n\t\t{\n\t\t// Start of @font-face at-rule block\n\t\tif ($char === \"@\" && $state === \"T_DOCUMENT\" && strtolower(substr($this->parser->getSource(), $index, 10)) === \"@font-face\")\n\t\t\t{\n\t\t\t$this->parser->pushState(\"T_AT_FONT_FACE::PREPARE\");\n\t\t\t$this->parser->clearBuffer();\n\t\t\treturn $index + 10;\n\t\t\t}\n\t\t// Start of @font-face declarations\n\t\telseif ($char === \"{\" && $state === \"T_AT_FONT_FACE::PREPARE\")\n\t\t\t{\n\t\t\t$this->parser->setState(\"T_AT_FONT_FACE\");\n\t\t\t$this->parser->clearBuffer();\n\t\t\t$this->parser->appendToken(new CssAtFontFaceStartToken());\n\t\t\t}\n\t\t// Start of @font-face declaration\n\t\telseif ($char === \":\" && $state === \"T_AT_FONT_FACE\")\n\t\t\t{\n\t\t\t$this->parser->pushState(\"T_AT_FONT_FACE_DECLARATION\");\n\t\t\t$this->buffer = $this->parser->getAndClearBuffer(\":\", true);\n\t\t\t}\n\t\t// Unterminated @font-face declaration\n\t\telseif ($char === \":\" && $state === \"T_AT_FONT_FACE_DECLARATION\")\n\t\t\t{\n\t\t\t// Ignore Internet Explorer filter declarations\n\t\t\tif ($this->buffer === \"filter\")\n\t\t\t\t{\n\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\tCssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . \": Unterminated @font-face declaration\", $this->buffer . \":\" . $this->parser->getBuffer() . \"_\"));\n\t\t\t}\n\t\t// End of @font-face declaration\n\t\telseif (($char === \";\" || $char === \"}\") && $state === \"T_AT_FONT_FACE_DECLARATION\")\n\t\t\t{\n\t\t\t$value = $this->parser->getAndClearBuffer(\";}\");\n\t\t\tif (strtolower(substr($value, -10, 10)) === \"!important\")\n\t\t\t\t{\n\t\t\t\t$value = trim(substr($value, 0, -10));\n\t\t\t\t$isImportant = true;\n\t\t\t\t}\n\t\t\telse\n\t\t\t\t{\n\t\t\t\t$isImportant = false;\n\t\t\t\t}\n\t\t\t$this->parser->popState();\n\t\t\t$this->parser->appendToken(new CssAtFontFaceDeclarationToken($this->buffer, $value, $isImportant));\n\t\t\t$this->buffer = \"\";\n\t\t\t// --\n\t\t\tif ($char === \"}\")\n\t\t\t\t{\n\t\t\t\t$this->parser->appendToken(new CssAtFontFaceEndToken());\n\t\t\t\t$this->parser->popState();\n\t\t\t\t}\n\t\t\t}\n\t\t// End of @font-face at-rule block\n\t\telseif ($char === \"}\" && $state === \"T_AT_FONT_FACE\")\n\t\t\t{\n\t\t\t$this->parser->appendToken(new CssAtFontFaceEndToken());\n\t\t\t$this->parser->clearBuffer();\n\t\t\t$this->parser->popState();\n\t\t\t}\n\t\telse\n\t\t\t{\n\t\t\treturn false;\n\t\t\t}\n\t\treturn true;\n\t\t}\n\t}\n\n/**\n * This {@link aCssToken CSS token} represents the end of a @font-face at-rule block.\n *\n * @package\t\tCssMin/Tokens\n * @link\t\thttp://code.google.com/p/cssmin/\n * @author\t\tJoe Scylla <joe.scylla@gmail.com>\n * @copyright\t2008 - 2011 Joe Scylla <joe.scylla@gmail.com>\n * @license\t\thttp://opensource.org/licenses/mit-license.php MIT License\n * @version\t\t3.0.1\n */\nclass CssAtFontFaceEndToken extends aCssAtBlockEndToken\n\t{\n\t\n\t}\n\n/**\n * This {@link aCssToken CSS token} represents a declaration of a @font-face at-rule block.\n *\n * @package\t\tCssMin/Tokens\n * @link\t\thttp://code.google.com/p/cssmin/\n * @author\t\tJoe Scylla <joe.scylla@gmail.com>\n * @copyright\t2008 - 2011 Joe Scylla <joe.scylla@gmail.com>\n * @license\t\thttp://opensource.org/licenses/mit-license.php MIT License\n * @version\t\t3.0.1\n */\nclass CssAtFontFaceDeclarationToken extends aCssDeclarationToken\n\t{\n\t\n\t}\n\n/**\n * This {@link aCssToken CSS token} represents a @charset at-rule.\n * \n * @package\t\tCssMin/Tokens\n * @link\t\thttp://code.google.com/p/cssmin/\n * @author\t\tJoe Scylla <joe.scylla@gmail.com>\n * @copyright\t2008 - 2011 Joe Scylla <joe.scylla@gmail.com>\n * @license\t\thttp://opensource.org/licenses/mit-license.php MIT License\n * @version\t\t3.0.1\n */\nclass CssAtCharsetToken extends aCssToken\n\t{\n\t/**\n\t * Charset of the @charset at-rule.\n\t * \n\t * @var string\n\t */\n\tpublic $Charset = \"\";\n\t/**\n\t * Set the properties of @charset at-rule token. \n\t * \n\t * @param string $charset Charset of the @charset at-rule token\n\t * @return void\n\t */\n\tpublic function __construct($charset)\n\t\t{\n\t\t$this->Charset = $charset;\n\t\t}\n\t/**\n\t * Implements {@link aCssToken::__toString()}.\n\t * \n\t * @return string\n\t */\n\tpublic function __toString()\n\t\t{\n\t\treturn \"@charset \" . $this->Charset . \";\";\n\t\t}\n\t}\n\n/**\n * {@link aCssParserPlugin Parser plugin} for parsing @charset at-rule.\n * \n * If a @charset at-rule was found this plugin will add a {@link CssAtCharsetToken} to the parser.\n *\n * @package\t\tCssMin/Parser/Plugins\n * @link\t\thttp://code.google.com/p/cssmin/\n * @author\t\tJoe Scylla <joe.scylla@gmail.com>\n * @copyright\t2008 - 2011 Joe Scylla <joe.scylla@gmail.com>\n * @license\t\thttp://opensource.org/licenses/mit-license.php MIT License\n * @version\t\t3.0.1\n */\nclass CssAtCharsetParserPlugin extends aCssParserPlugin\n\t{\n\t/**\n\t * Implements {@link aCssParserPlugin::getTriggerChars()}.\n\t * \n\t * @return array\n\t */\n\tpublic function getTriggerChars()\n\t\t{\n\t\treturn array(\"@\", \";\", \"\\n\");\n\t\t}\n\t/**\n\t * Implements {@link aCssParserPlugin::getTriggerStates()}.\n\t * \n\t * @return array\n\t */\n\tpublic function getTriggerStates()\n\t\t{\n\t\treturn array(\"T_DOCUMENT\", \"T_AT_CHARSET\");\n\t\t}\n\t/**\n\t * Implements {@link aCssParserPlugin::parse()}.\n\t * \n\t * @param integer $index Current index\n\t * @param string $char Current char\n\t * @param string $previousChar Previous char\n\t * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing\n\t */\n\tpublic function parse($index, $char, $previousChar, $state)\n\t\t{\n\t\tif ($char === \"@\" && $state === \"T_DOCUMENT\" && strtolower(substr($this->parser->getSource(), $index, 8)) === \"@charset\")\n\t\t\t{\n\t\t\t$this->parser->pushState(\"T_AT_CHARSET\");\n\t\t\t$this->parser->clearBuffer();\n\t\t\treturn $index + 8;\n\t\t\t}\n\t\telseif (($char === \";\" || $char === \"\\n\") && $state === \"T_AT_CHARSET\")\n\t\t\t{\n\t\t\t$charset = $this->parser->getAndClearBuffer(\";\");\n\t\t\t$this->parser->popState();\n\t\t\t$this->parser->appendToken(new CssAtCharsetToken($charset));\n\t\t\t}\n\t\telse\n\t\t\t{\n\t\t\treturn false;\n\t\t\t}\n\t\treturn true;\n\t\t}\n\t}\n\n?>"
  },
  {
    "path": "application/libraries/minify/cssminify.php",
    "content": "<?php\n/**\n * Created by PhpStorm.\n * User: slav\n * Date: 10/02/15\n * Time: 12:20 PM\n */\n\n\nclass cssminify {\n\t/**\n\t * Minify compression engine\n\t *\n\t * @package  Minify\n\t * @authohor Stephen Clay <steve@mrclay.org>\n\t * @author   http://code.google.com/u/1stvamp/ (Issue 64 patch)\n\t */\n\n\tpublic function compress($css)\n\t{\n\t\t$this->_inHack = FALSE;\n\n\t\t$css = str_replace(\"\\r\\n\", \"\\n\", $css);\n\n\t\t// preserve empty comment after '>'\n\t\t// http://www.webdevout.net/css-hacks#in_css-selectors\n\t\t$css = preg_replace('@>/\\\\*\\\\s*\\\\*/@', '>/*keep*/', $css);\n\n\t\t// preserve empty comment between property and value\n\t\t// http://css-discuss.incutio.com/?page=BoxModelHack\n\t\t$css = preg_replace('@/\\\\*\\\\s*\\\\*/\\\\s*:@', '/*keep*/:', $css);\n\t\t$css = preg_replace('@:\\\\s*/\\\\*\\\\s*\\\\*/@', ':/*keep*/', $css);\n\n\t\t// apply callback to all valid comments (and strip out surrounding ws\n\t\t$css = preg_replace_callback('@\\\\s*/\\\\*([\\\\s\\\\S]*?)\\\\*/\\\\s*@', array($this, '_commentCB'), $css);\n\n\t\t// remove ws around { } and last semicolon in declaration block\n\t\t$css = preg_replace('/\\\\s*{\\\\s*/', '{', $css);\n\t\t$css = preg_replace('/;?\\\\s*}\\\\s*/', '}', $css);\n\n\t\t// remove ws surrounding semicolons\n\t\t$css = preg_replace('/\\\\s*;\\\\s*/', ';', $css);\n\n\t\t// remove ws around urls\n\t\t$css = preg_replace('/\n                url\\\\(      # url(\n                \\\\s*\n                ([^\\\\)]+?)  # 1 = the URL (really just a bunch of non right parenthesis)\n                \\\\s*\n                \\\\)         # )\n            /x', 'url($1)', $css);\n\n\t\t// remove ws between rules and colons\n\t\t$css = preg_replace('/\n                \\\\s*\n                ([{;])              # 1 = beginning of block or rule separator\n                \\\\s*\n                ([\\\\*_]?[\\\\w\\\\-]+)  # 2 = property (and maybe IE filter)\n                \\\\s*\n                :\n                \\\\s*\n                (\\\\b|[#\\'\"-])        # 3 = first character of a value\n            /x', '$1$2:$3', $css);\n\n\t\t// remove ws in selectors\n\t\t$css = preg_replace_callback('/\n                (?:              # non-capture\n                    \\\\s*\n                    [^~>+,\\\\s]+  # selector part\n                    \\\\s*\n                    [,>+~]       # combinators\n                )+\n                \\\\s*\n                [^~>+,\\\\s]+      # selector part\n                {                # open declaration block\n            /x', array($this, '_selectorsCB'), $css);\n\n\t\t// minimize hex colors\n\t\t$css = preg_replace('/([^=])#([a-f\\\\d])\\\\2([a-f\\\\d])\\\\3([a-f\\\\d])\\\\4([\\\\s;\\\\}])/i', '$1#$2$3$4$5', $css);\n\n\t\t// remove spaces between font families\n\t\t$css = preg_replace_callback('/font-family:([^;}]+)([;}])/', array($this, '_fontFamilyCB'), $css);\n\n\t\t$css = preg_replace('/@import\\\\s+url/', '@import url', $css);\n\n\t\t// replace any ws involving newlines with a single newline\n\t\t$css = preg_replace('/[ \\\\t]*\\\\n+\\\\s*/', \"\\n\", $css);\n\n\t\t// separate common descendent selectors w/ newlines (to limit line lengths)\n\t\t$css = preg_replace('/([\\\\w#\\\\.\\\\*]+)\\\\s+([\\\\w#\\\\.\\\\*]+){/', \"$1\\n$2{\", $css);\n\n\t\t// Use newline after 1st numeric value (to limit line lengths).\n\t\t$css = preg_replace('/\n            ((?:padding|margin|border|outline):\\\\d+(?:px|em)?) # 1 = prop : 1st numeric value\n            \\\\s+\n            /x', \"$1\\n\", $css);\n\n\t\t// prevent triggering IE6 bug: http://www.crankygeek.com/ie6pebug/\n\t\t$css = preg_replace('/:first-l(etter|ine)\\\\{/', ':first-l$1 {', $css);\n\n\t\treturn trim($css);\n\t}\n\n\t/**\n\t * Replace what looks like a set of selectors\n\t *\n\t * @param array $m regex matches\n\t *\n\t * @return string\n\t */\n\tprotected function _selectorsCB($m)\n\t{\n\t\t// remove ws around the combinators\n\t\treturn preg_replace('/\\\\s*([,>+~])\\\\s*/', '$1', $m[0]);\n\t}\n\n\t/**\n\t * Process a comment and return a replacement\n\t *\n\t * @param array $m regex matches\n\t *\n\t * @return string\n\t */\n\tprotected function _commentCB($m)\n\t{\n\t\t$hasSurroundingWs = (trim($m[0]) !== $m[1]);\n\t\t$m                = $m[1];\n\t\t// $m is the comment content w/o the surrounding tokens,\n\t\t// but the return value will replace the entire comment.\n\t\tif ($m === 'keep')\n\t\t{\n\t\t\treturn '/**/';\n\t\t}\n\t\tif ($m === '\" \"')\n\t\t{\n\t\t\t// component of http://tantek.com/CSS/Examples/midpass.html\n\t\t\treturn '/*\" \"*/';\n\t\t}\n\t\tif (preg_match('@\";\\\\}\\\\s*\\\\}/\\\\*\\\\s+@', $m))\n\t\t{\n\t\t\t// component of http://tantek.com/CSS/Examples/midpass.html\n\t\t\treturn '/*\";}}/* */';\n\t\t}\n\t\tif ($this->_inHack)\n\t\t{\n\t\t\t// inversion: feeding only to one browser\n\t\t\tif (preg_match('@\n                    ^/               # comment started like /*/\n                    \\\\s*\n                    (\\\\S[\\\\s\\\\S]+?)  # has at least some non-ws content\n                    \\\\s*\n                    /\\\\*             # ends like /*/ or /**/\n                @x', $m, $n))\n\t\t\t{\n\t\t\t\t// end hack mode after this comment, but preserve the hack and comment content\n\t\t\t\t$this->_inHack = FALSE;\n\n\t\t\t\treturn \"/*/{$n[1]}/**/\";\n\t\t\t}\n\t\t}\n\t\tif (substr($m, - 1) === '\\\\')\n\t\t{ // comment ends like \\*/\n\t\t\t// begin hack mode and preserve hack\n\t\t\t$this->_inHack = TRUE;\n\n\t\t\treturn '/*\\\\*/';\n\t\t}\n\t\tif ($m !== '' && $m[0] === '/')\n\t\t{ // comment looks like /*/ foo */\n\t\t\t// begin hack mode and preserve hack\n\t\t\t$this->_inHack = TRUE;\n\n\t\t\treturn '/*/*/';\n\t\t}\n\t\tif ($this->_inHack)\n\t\t{\n\t\t\t// a regular comment ends hack mode but should be preserved\n\t\t\t$this->_inHack = FALSE;\n\n\t\t\treturn '/**/';\n\t\t}\n\t\t// Issue 107: if there's any surrounding whitespace, it may be important, so\n\t\t// replace the comment with a single space\n\t\treturn $hasSurroundingWs // remove all other comments\n\t\t\t? ' ' : '';\n\t}\n\n\t/**\n\t * Process a font-family listing and return a replacement\n\t *\n\t * @param array $m regex matches\n\t *\n\t * @return string\n\t */\n\tprotected function _fontFamilyCB($m)\n\t{\n\t\t$m[1] = preg_replace('/\n                \\\\s*\n                (\n                    \"[^\"]+\"      # 1 = family in double qutoes\n                    |\\'[^\\']+\\'  # or 1 = family in single quotes\n                    |[\\\\w\\\\-]+   # or 1 = unquoted family\n                )\n                \\\\s*\n            /x', '$1', $m[1]);\n\n\t\treturn 'font-family:' . $m[1] . $m[2];\n\t}\n}"
  },
  {
    "path": "application/views/index.html",
    "content": "<html>\n<head>\n\t<title>403 Forbidden</title>\n</head>\n<body>\n\n<p>Directory access is forbidden.</p>\n\n</body>\n</html>"
  },
  {
    "path": "application/views/welcome_message.php",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n\t<meta charset=\"utf-8\">\n\t<title>Welcome to CodeIgniter</title>\n\t<?php // add css files\n\t\t$this->minify->css(array('browser-specific.css', 'style.css'));\n\t\techo $this->minify->deploy_css();\n\n\t\t$this->minify->js(array('helpers.js', 'jqModal.js'));\n\t\techo $this->minify->deploy_js(FALSE, 'custom_js_name.min.js');\n\n\t?>\n</head>\n<body>\n\n<div id=\"container\">\n\t<h1>Welcome to CodeIgniter Minify library!</h1>\n\n\t<div id=\"body\">\n\t\t<p>Check out if minified files are working for you.</p>\n\t\t<p>Click here to get <a href=\"<?php echo $this->minify->assets_dir .'/' . $this->minify->js_file ?>\">JavaScript</a> file</p>\n\t\t<p>Click here to check out <a href=\"<?php echo $this->minify->assets_dir .'/' . $this->minify->css_file ?>\">CSS</a> </p>\n\t</div>\n\n\t<p class=\"footer\">Page rendered in <strong>{elapsed_time}</strong> seconds</p>\n</div>\n\n</body>\n</html>"
  },
  {
    "path": "assets/css/browser-specific.css",
    "content": "::selection{ background-color: #E13300; color: white; }\n::moz-selection{ background-color: #E13300; color: white; }\n::webkit-selection{ background-color: #E13300; color: white; }"
  },
  {
    "path": "assets/css/style.css",
    "content": "body {\n    background-color: #fff;\n    margin: 40px;\n    font: 13px/20px normal Helvetica, Arial, sans-serif;\n    color: #4F5155;\n}\n\na {\n    color: #003399;\n    background-color: transparent;\n    font-weight: normal;\n}\n\n\nh1 {\n    color: #444;\n    background-color: transparent;\n    border-bottom: 1px solid #D0D0D0;\n    font-size: 19px;\n    font-weight: normal;\n    margin: 0 0 14px 0;\n    padding: 14px 15px 10px 15px;\n}\n\ncode {\n    font-family: Consolas, Monaco, Courier New, Courier, monospace;\n    font-size: 12px;\n    background-color: #f9f9f9;\n    border: 1px solid #D0D0D0;\n    color: #002166;\n    display: block;\n    margin: 14px 0 14px 0;\n    padding: 12px 10px 12px 10px;\n}\n\n#body {\n    margin: 0 15px 0 15px;\n}\n\np.footer {\n    text-align: right;\n    font-size: 11px;\n    border-top: 1px solid #D0D0D0;\n    line-height: 32px;\n    padding: 0 10px 0 10px;\n    margin: 20px 0 0 0;\n}\n\n#container {\n    margin: 10px;\n    border: 1px solid #D0D0D0;\n    -webkit-box-shadow: 0 0 8px #D0D0D0;\n}"
  },
  {
    "path": "assets/js/helpers.js",
    "content": "function string_contains(haystack, needle) {\n    if (haystack.indexOf(needle) == -1) {\n        return false;\n    } else {\n        return true;\n    }\n}\n\nfunction str_replace(search, replace, subject, count) {\n    var i = 0,\n        j = 0,\n        temp = '',\n        repl = '',\n        sl = 0,\n        fl = 0,\n        f = [].concat(search),\n        r = [].concat(replace),\n        s = subject,\n        ra = Object.prototype.toString.call(r) === '[object Array]',\n        sa = Object.prototype.toString.call(s) === '[object Array]';\n    s = [].concat(s);\n    if (count) {\n        this.window[count] = 0;\n    }\n\n    for (i = 0, sl = s.length; i < sl; i++) {\n        if (s[i] === '') {\n            continue;\n        }\n        for (j = 0, fl = f.length; j < fl; j++) {\n            temp = s[i] + '';\n            repl = ra ? (r[j] !== undefined ? r[j] : '') : r[0];\n            s[i] = (temp).split(f[j]).join(repl);\n            if (count && s[i] !== temp) {\n                this.window[count] += (temp.length - s[i].length) / f[j].length;\n            }\n        }\n    }\n    return sa ? s : s[0];\n}\n\n\n\nfunction htmlspecialchars(string, quote_style, charset, double_encode) {\n    var optTemp = 0,\n        i = 0,\n        noquotes = false;\n    if (typeof quote_style === 'undefined' || quote_style === null) {\n        quote_style = 2;\n    }\n    string = string.toString();\n    if (double_encode !== false) { // Put this first to avoid double-encoding\n        string = string.replace(/&/g, '&amp;');\n    }\n    string = string.replace(/</g, '&lt;').replace(/>/g, '&gt;');\n\n    var OPTS = {\n        'ENT_NOQUOTES': 0,\n        'ENT_HTML_QUOTE_SINGLE': 1,\n        'ENT_HTML_QUOTE_DOUBLE': 2,\n        'ENT_COMPAT': 2,\n        'ENT_QUOTES': 3,\n        'ENT_IGNORE': 4\n    };\n    if (quote_style === 0) {\n        noquotes = true;\n    }\n    if (typeof quote_style !== 'number') { // Allow for a single string or an array of string flags\n        quote_style = [].concat(quote_style);\n        for (i = 0; i < quote_style.length; i++) {\n            // Resolve string input to bitwise e.g. 'ENT_IGNORE' becomes 4\n            if (OPTS[quote_style[i]] === 0) {\n                noquotes = true;\n            }\n            else if (OPTS[quote_style[i]]) {\n                optTemp = optTemp | OPTS[quote_style[i]];\n            }\n        }\n        quote_style = optTemp;\n    }\n    if (quote_style & OPTS.ENT_HTML_QUOTE_SINGLE) {\n        string = string.replace(/'/g, '&#039;');\n    }\n    if (!noquotes) {\n        string = string.replace(/\"/g, '&quot;');\n    }\n\n    return string;\n}\n\n\nfunction initDataTable() {\n    /*\n     var b_destroy = false;\n     if (typeof(oTable) != 'undefined') {\n     var b_destroy = true;\n     }\n     */\n    $('#clients-assigned-view').dataTable({\n        \"aaSorting\": [\n            [7, \"asc\"]\n        ],\n        'aoColumnDefs': [\n            {'bSortable': false, \"aTargets\": [0, 1, 2, 3, 5, 6]}\n        ],\n        //'bDestroy' :b_destroy,\n        'fnDrawCallback': function (oSettings) {\n            runEditables();\n        },\n        'bAutoWidth': false,\n        'bPaginate': false\n        //\"sPaginationType\": \"bootstrap\",\n    });\n\n    $('#leads-assigned-view').dataTable({\n        \"aaSorting\": [\n            [1, \"asc\"]\n        ],\n        'fnDrawCallback': function (oSettings) {\n            runEditables();\n        },\n        'bAutoWidth': false,\n        'bPaginate': false\n    });\n\n};\n\nfunction addslashes(str) {\n    return (str + '').replace(/([\\\\\"'])/g, \"\\\\$1\").replace(/\\0/g, \"\\\\0\");\n}\n\nfunction nl2br(str, is_xhtml) {\n    var breakTag = '';\n    breakTag = '<br />';\n    if (typeof is_xhtml != 'undefined' && !is_xhtml) {\n        breakTag = '<br>';\n    }\n    return (str + '').replace(/([^>]?)\\n/g, '$1' + breakTag + '\\n');\n}\n\nfunction replaceAndSymbol(str) {\n    str = str.replace(/&/, \"%26\");\n    return str;\n}\n\nfunction removeCommas(str) {\n    str = str.replace(/\\,/g, '');\n    return str;\n}\nfunction setCaretPosition(elemId, caretPos) {\n    var elem = document.getElementById(elemId);\n\n    if (elem != null) {\n        if (elem.createTextRange) {\n            var range = elem.createTextRange();\n            range.move('character', caretPos);\n            range.select();\n        }\n        else {\n            if (elem.selectionStart) {\n                elem.focus();\n                elem.setSelectionRange(caretPos, caretPos);\n            }\n            else\n                elem.focus();\n        }\n    }\n}\n\nfunction setStartTimeNow(textarea) {\n    var d = new Date();\n    var currYear = d.getFullYear();\n    var currMonth = d.getMonth() + 1;\n    var currDate = d.getDate();\n    var currHour = d.getHours();\n    var currMin = d.getMinutes();\n    time = currYear + \"-\" +\n        (currMonth < 10 ? \"0\" : \"\") + currMonth + \"-\" +\n        (currDate < 10 ? \"0\" : \"\") + currDate + \" \" +\n        (currHour < 10 ? \"0\" : \"\") + currHour + \":\" +\n        (currMin < 10 ? \"0\" : \"\") + currMin;\n\n    theInput = document.getElementById(textarea);\n    theInput.value = time + \" - \\n\\n\" + theInput.value;\n\n    setCaretPosition(textarea, 19);\n}\n\nfunction setCopy(textarea) {\n    textarea.rows = 14;\n}\n\nfunction closeCopy(textarea) {\n    textarea.rows = 8;\n}"
  },
  {
    "path": "assets/js/jqModal.js",
    "content": "/*\n * jqModal - Minimalist Modaling with jQuery\n *   (http://dev.iceburg.net/jquery/jqModal/)\n *\n * Copyright (c) 2007,2008 Brice Burgess <bhb@iceburg.net>\n * Dual licensed under the MIT and GPL licenses:\n *   http://www.opensource.org/licenses/mit-license.php\n *   http://www.gnu.org/licenses/gpl.html\n * \n * $Version: 03/01/2009 +r14\n */\n(function($) {\n$.fn.jqm=function(o){\nvar p={\noverlay: 50,\noverlayClass: 'jqmOverlay',\ncloseClass: 'jqmClose',\ntrigger: '.jqModal',\najax: F,\najaxText: '',\ntarget: F,\nmodal: F,\ntoTop: F,\nonShow: F,\nonHide: F,\nonLoad: F\n};\nreturn this.each(function(){if(this._jqm)return H[this._jqm].c=$.extend({},H[this._jqm].c,o);s++;this._jqm=s;\nH[s]={c:$.extend(p,$.jqm.params,o),a:F,w:$(this).addClass('jqmID'+s),s:s};\nif(p.trigger)$(this).jqmAddTrigger(p.trigger);\n});};\n\n$.fn.jqmAddClose=function(e){return hs(this,e,'jqmHide');};\n$.fn.jqmAddTrigger=function(e){return hs(this,e,'jqmShow');};\n$.fn.jqmShow=function(t){return this.each(function(){t=t||window.event;$.jqm.open(this._jqm,t);});};\n$.fn.jqmHide=function(t){return this.each(function(){t=t||window.event;$.jqm.close(this._jqm,t)});};\n\n$.jqm = {\nhash:{},\nopen:function(s,t){var h=H[s],c=h.c,cc='.'+c.closeClass,z=(parseInt(h.w.css('z-index'))),z=(z>0)?z:3000,o=$('<div></div>').css({height:'100%',width:'100%',position:'fixed',left:0,top:0,'z-index':z-1,opacity:c.overlay/100});if(h.a)return F;h.t=t;h.a=true;h.w.css('z-index',z);\n if(c.modal) {if(!A[0])L('bind');A.push(s);}\n else if(c.overlay > 0)h.w.jqmAddClose(o);\n else o=F;\n\n h.o=(o)?o.addClass(c.overlayClass).prependTo('body'):F;\n if(ie6){$('html,body').css({height:'100%',width:'100%'});if(o){o=o.css({position:'absolute'})[0];for(var y in {Top:1,Left:1})o.style.setExpression(y.toLowerCase(),\"(_=(document.documentElement.scroll\"+y+\" || document.body.scroll\"+y+\"))+'px'\");}}\n\n if(c.ajax) {var r=c.target||h.w,u=c.ajax,r=(typeof r == 'string')?$(r,h.w):$(r),u=(u.substr(0,1) == '@')?$(t).attr(u.substring(1)):u;\n  r.html(c.ajaxText).load(u,function(){if(c.onLoad)c.onLoad.call(this,h);if(cc)h.w.jqmAddClose($(cc,h.w));e(h);});}\n else if(cc)h.w.jqmAddClose($(cc,h.w));\n\n if(c.toTop&&h.o)h.w.before('<span id=\"jqmP'+h.w[0]._jqm+'\"></span>').insertAfter(h.o);\t\n (c.onShow)?c.onShow(h):h.w.show();e(h);return F;\n},\nclose:function(s){var h=H[s];if(!h.a)return F;h.a=F;\n if(A[0]){A.pop();if(!A[0])L('unbind');}\n if(h.c.toTop&&h.o)$('#jqmP'+h.w[0]._jqm).after(h.w).remove();\n if(h.c.onHide)h.c.onHide(h);else{h.w.hide();if(h.o)h.o.remove();} return F;\n},\nparams:{}};\nvar s=0,H=$.jqm.hash,A=[],ie6=$.browser.msie&&($.browser.version == \"6.0\"),F=false,\ni=$('<iframe src=\"javascript:false;document.write(\\'\\');\" class=\"jqm\"></iframe>').css({opacity:0}),\ne=function(h){if(ie6)if(h.o)h.o.html('<p style=\"width:100%;height:100%\"/>').prepend(i);else if(!$('iframe.jqm',h.w)[0])h.w.prepend(i); f(h);},\nf=function(h){try{$(':input:visible',h.w)[0].focus();}catch(_){}},\nL=function(t){$()[t](\"keypress\",m)[t](\"keydown\",m)[t](\"mousedown\",m);},\nm=function(e){var h=H[A[A.length-1]],r=(!$(e.target).parents('.jqmID'+h.s)[0]);if(r)f(h);return !r;},\nhs=function(w,t,c){return w.each(function(){var s=this._jqm;$(t).each(function() {\n if(!this[c]){this[c]=[];$(this).click(function(){for(var i in {jqmShow:1,jqmHide:1})for(var s in this[i])if(H[this[i][s]])H[this[i][s]].w[i](this);return F;});}this[c].push(s);});});};\n})(jQuery);\n"
  },
  {
    "path": "composer.json",
    "content": "{\n    \"require-dev\": {\n        \"phpunit/phpunit\": \"5.*\"\n    },\n  \"require\": {\n    \"ext-curl\": \"*\"\n  }\n}\n"
  },
  {
    "path": "index.php",
    "content": "<?php\n/**\n * CodeIgniter\n *\n * An open source application development framework for PHP\n *\n * This content is released under the MIT License (MIT)\n *\n * Copyright (c) 2014 - 2019, British Columbia Institute of Technology\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n *\n * @package\tCodeIgniter\n * @author\tEllisLab Dev Team\n * @copyright\tCopyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)\n * @copyright\tCopyright (c) 2014 - 2019, British Columbia Institute of Technology (https://bcit.ca/)\n * @license\thttps://opensource.org/licenses/MIT\tMIT License\n * @link\thttps://codeigniter.com\n * @since\tVersion 1.0.0\n * @filesource\n */\n\n/*\n *---------------------------------------------------------------\n * APPLICATION ENVIRONMENT\n *---------------------------------------------------------------\n *\n * You can load different configurations depending on your\n * current environment. Setting the environment also influences\n * things like logging and error reporting.\n *\n * This can be set to anything, but default usage is:\n *\n *     development\n *     testing\n *     production\n *\n * NOTE: If you change these, also change the error_reporting() code below\n */\n\tdefine('ENVIRONMENT', isset($_SERVER['CI_ENV']) ? $_SERVER['CI_ENV'] : 'development');\n\n/*\n *---------------------------------------------------------------\n * ERROR REPORTING\n *---------------------------------------------------------------\n *\n * Different environments will require different levels of error reporting.\n * By default development will show errors but testing and live will hide them.\n */\nswitch (ENVIRONMENT)\n{\n\tcase 'development':\n\t\terror_reporting(-1);\n\t\tini_set('display_errors', 1);\n\tbreak;\n\n\tcase 'testing':\n\tcase 'production':\n\t\tini_set('display_errors', 0);\n\t\tif (version_compare(PHP_VERSION, '5.3', '>='))\n\t\t{\n\t\t\terror_reporting(E_ALL & ~E_NOTICE & ~E_DEPRECATED & ~E_STRICT & ~E_USER_NOTICE & ~E_USER_DEPRECATED);\n\t\t}\n\t\telse\n\t\t{\n\t\t\terror_reporting(E_ALL & ~E_NOTICE & ~E_STRICT & ~E_USER_NOTICE);\n\t\t}\n\tbreak;\n\n\tdefault:\n\t\theader('HTTP/1.1 503 Service Unavailable.', TRUE, 503);\n\t\techo 'The application environment is not set correctly.';\n\t\texit(1); // EXIT_ERROR\n}\n\n/*\n *---------------------------------------------------------------\n * SYSTEM DIRECTORY NAME\n *---------------------------------------------------------------\n *\n * This variable must contain the name of your \"system\" directory.\n * Set the path if it is not in the same directory as this file.\n */\n\t$system_path = '../ci/system';\n\n/*\n *---------------------------------------------------------------\n * APPLICATION DIRECTORY NAME\n *---------------------------------------------------------------\n *\n * If you want this front controller to use a different \"application\"\n * directory than the default one you can set its name here. The directory\n * can also be renamed or relocated anywhere on your server. If you do,\n * use an absolute (full) server path.\n * For more info please see the user guide:\n *\n * https://codeigniter.com/user_guide/general/managing_apps.html\n *\n * NO TRAILING SLASH!\n */\n\t$application_folder = 'application';\n\n/*\n *---------------------------------------------------------------\n * VIEW DIRECTORY NAME\n *---------------------------------------------------------------\n *\n * If you want to move the view directory out of the application\n * directory, set the path to it here. The directory can be renamed\n * and relocated anywhere on your server. If blank, it will default\n * to the standard location inside your application directory.\n * If you do move this, use an absolute (full) server path.\n *\n * NO TRAILING SLASH!\n */\n\t$view_folder = '';\n\n\n/*\n * --------------------------------------------------------------------\n * DEFAULT CONTROLLER\n * --------------------------------------------------------------------\n *\n * Normally you will set your default controller in the routes.php file.\n * You can, however, force a custom routing by hard-coding a\n * specific controller class/function here. For most applications, you\n * WILL NOT set your routing here, but it's an option for those\n * special instances where you might want to override the standard\n * routing in a specific front controller that shares a common CI installation.\n *\n * IMPORTANT: If you set the routing here, NO OTHER controller will be\n * callable. In essence, this preference limits your application to ONE\n * specific controller. Leave the function name blank if you need\n * to call functions dynamically via the URI.\n *\n * Un-comment the $routing array below to use this feature\n */\n\t// The directory name, relative to the \"controllers\" directory.  Leave blank\n\t// if your controller is not in a sub-directory within the \"controllers\" one\n\t// $routing['directory'] = '';\n\n\t// The controller class file name.  Example:  mycontroller\n\t// $routing['controller'] = '';\n\n\t// The controller function you wish to be called.\n\t// $routing['function']\t= '';\n\n\n/*\n * -------------------------------------------------------------------\n *  CUSTOM CONFIG VALUES\n * -------------------------------------------------------------------\n *\n * The $assign_to_config array below will be passed dynamically to the\n * config class when initialized. This allows you to set custom config\n * items or override any default config values found in the config.php file.\n * This can be handy as it permits you to share one application between\n * multiple front controller files, with each file containing different\n * config values.\n *\n * Un-comment the $assign_to_config array below to use this feature\n */\n\t// $assign_to_config['name_of_config_item'] = 'value of config item';\n\n\n\n// --------------------------------------------------------------------\n// END OF USER CONFIGURABLE SETTINGS.  DO NOT EDIT BELOW THIS LINE\n// --------------------------------------------------------------------\n\n/*\n * ---------------------------------------------------------------\n *  Resolve the system path for increased reliability\n * ---------------------------------------------------------------\n */\n\n\t// Set the current directory correctly for CLI requests\n\tif (defined('STDIN'))\n\t{\n\t\tchdir(dirname(__FILE__));\n\t}\n\n\tif (($_temp = realpath($system_path)) !== FALSE)\n\t{\n\t\t$system_path = $_temp.DIRECTORY_SEPARATOR;\n\t}\n\telse\n\t{\n\t\t// Ensure there's a trailing slash\n\t\t$system_path = strtr(\n\t\t\trtrim($system_path, '/\\\\'),\n\t\t\t'/\\\\',\n\t\t\tDIRECTORY_SEPARATOR.DIRECTORY_SEPARATOR\n\t\t).DIRECTORY_SEPARATOR;\n\t}\n\n\t// Is the system path correct?\n\tif ( ! is_dir($system_path))\n\t{\n\t\theader('HTTP/1.1 503 Service Unavailable.', TRUE, 503);\n\t\techo 'Your system folder path does not appear to be set correctly. Please open the following file and correct this: '.pathinfo(__FILE__, PATHINFO_BASENAME);\n\t\texit(3); // EXIT_CONFIG\n\t}\n\n/*\n * -------------------------------------------------------------------\n *  Now that we know the path, set the main path constants\n * -------------------------------------------------------------------\n */\n\t// The name of THIS file\n\tdefine('SELF', pathinfo(__FILE__, PATHINFO_BASENAME));\n\n\t// Path to the system directory\n\tdefine('BASEPATH', $system_path);\n\n\t// Path to the front controller (this file) directory\n\tdefine('FCPATH', dirname(__FILE__).DIRECTORY_SEPARATOR);\n\n\t// Name of the \"system\" directory\n\tdefine('SYSDIR', basename(BASEPATH));\n\n\t// The path to the \"application\" directory\n\tif (is_dir($application_folder))\n\t{\n\t\tif (($_temp = realpath($application_folder)) !== FALSE)\n\t\t{\n\t\t\t$application_folder = $_temp;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t$application_folder = strtr(\n\t\t\t\trtrim($application_folder, '/\\\\'),\n\t\t\t\t'/\\\\',\n\t\t\t\tDIRECTORY_SEPARATOR.DIRECTORY_SEPARATOR\n\t\t\t);\n\t\t}\n\t}\n\telseif (is_dir(BASEPATH.$application_folder.DIRECTORY_SEPARATOR))\n\t{\n\t\t$application_folder = BASEPATH.strtr(\n\t\t\ttrim($application_folder, '/\\\\'),\n\t\t\t'/\\\\',\n\t\t\tDIRECTORY_SEPARATOR.DIRECTORY_SEPARATOR\n\t\t);\n\t}\n\telse\n\t{\n\t\theader('HTTP/1.1 503 Service Unavailable.', TRUE, 503);\n\t\techo 'Your application folder path does not appear to be set correctly. Please open the following file and correct this: '.SELF;\n\t\texit(3); // EXIT_CONFIG\n\t}\n\n\tdefine('APPPATH', $application_folder.DIRECTORY_SEPARATOR);\n\n\t// The path to the \"views\" directory\n\tif ( ! isset($view_folder[0]) && is_dir(APPPATH.'views'.DIRECTORY_SEPARATOR))\n\t{\n\t\t$view_folder = APPPATH.'views';\n\t}\n\telseif (is_dir($view_folder))\n\t{\n\t\tif (($_temp = realpath($view_folder)) !== FALSE)\n\t\t{\n\t\t\t$view_folder = $_temp;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t$view_folder = strtr(\n\t\t\t\trtrim($view_folder, '/\\\\'),\n\t\t\t\t'/\\\\',\n\t\t\t\tDIRECTORY_SEPARATOR.DIRECTORY_SEPARATOR\n\t\t\t);\n\t\t}\n\t}\n\telseif (is_dir(APPPATH.$view_folder.DIRECTORY_SEPARATOR))\n\t{\n\t\t$view_folder = APPPATH.strtr(\n\t\t\ttrim($view_folder, '/\\\\'),\n\t\t\t'/\\\\',\n\t\t\tDIRECTORY_SEPARATOR.DIRECTORY_SEPARATOR\n\t\t);\n\t}\n\telse\n\t{\n\t\theader('HTTP/1.1 503 Service Unavailable.', TRUE, 503);\n\t\techo 'Your view folder path does not appear to be set correctly. Please open the following file and correct this: '.SELF;\n\t\texit(3); // EXIT_CONFIG\n\t}\n\n\tdefine('VIEWPATH', $view_folder.DIRECTORY_SEPARATOR);\n\n/*\n * --------------------------------------------------------------------\n * LOAD THE BOOTSTRAP FILE\n * --------------------------------------------------------------------\n *\n * And away we go...\n */\nrequire_once BASEPATH.'core/CodeIgniter.php';\n"
  },
  {
    "path": "phpunit.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<phpunit bootstrap=\"./tests/bootstrap.php\" colors=\"true\">\n\n\t<testsuites>\n\t\t<testsuite name=\"Basic test suite\">\n\t\t\t<directory suffix=\"Test.php\">./tests</directory>\n\t\t</testsuite>\n\t</testsuites>\n\t<logging>\n\n\n\t<log type=\"coverage-html\" target=\"tests/coverage\" title=\"Minify\"\n\t     charset=\"UTF-8\" yui=\"true\" highlight=\"true\"\n\t     lowUpperBound=\"35\" highLowerBound=\"70\"/>\n\t</logging>\n\n\t<filter>\n\t\t<whitelist>\n\t\t\t<directory>./</directory>\n\t\t\t<exclude>\n\t\t\t\t<directory>./application/controllers</directory>\n\t\t\t\t<directory>./application/errors</directory>\n\t\t\t\t<directory>./application/views</directory>\n\t\t\t\t<directory>./vendor</directory>\n\t\t\t</exclude>\n\t\t</whitelist>\n\t</filter>\n</phpunit>"
  },
  {
    "path": "tests/MinifyTest.php",
    "content": "<?php\n/**\n * Created by PhpStorm.\n * User: slav\n * Date: 10/02/15\n * Time: 9:51 AM\n */\n\nclass MinifyTest extends PHPUnit_Framework_TestCase {\n\n\tpublic $minify;\n\n\tpublic function setUp() {\n\t\tinclude_once('application/libraries/Minify.php');\n\t}\n\n\t// test init test\n\tpublic function testInit()\n\t{\n\n\t\t// Arrange\n\t\t$this->minify = new Minify();\n\n\t\t// Assert\n\t\t$this->assertTrue(is_object($this->minify), 'is object');\n\t}\n\n\t// test js when functionality is disabled\n\tpublic function testJsDisabled()\n\t{\n\t\t$this->minify = new Minify();\n\n\t\t$this->minify->enabled = FALSE;\n\t\t$this->minify->assets_dir_js = 'assets/js';\n\t\t$this->minify->add_js(array('helpers.js'))->add_js('jqModal.js');\n\n\t\t$result = $this->minify->deploy_js(FALSE);\n\t\t$this->assertTrue(is_string($result), 'deploy with add_js');\n\n\t\t$this->assertEquals('<script type=\"text/javascript\" src=\"http://minify.localhost/assets/js/helpers.js\"></script>'.\n\t\t\tPHP_EOL.'<script type=\"text/javascript\" src=\"http://minify.localhost/assets/js/jqModal.js\"></script>',\n\t\t\t$result, 'output js with disabled library\\'s functionality');\n\t}\n\n\t// test css when functionality is disabled\n\tpublic function testCssDisabled()\n\t{\n\t\t$this->minify = new Minify();\n\n\t\t$this->minify->enabled = FALSE;\n\t\t$this->minify->assets_dir_css = 'assets/css';\n\t\t$this->minify->add_css(array('style.css'))->add_css('browser-specific.css');\n\n\t\t$result = $this->minify->deploy_css(TRUE);\n\t\t$this->assertTrue(is_string($result), 'deploy with add_css');\n\n\t\t$this->assertEquals('<link href=\"http://minify.localhost/assets/css/style.css\" rel=\"stylesheet\" type=\"text/css\" />'.\n\t\t\tPHP_EOL.'<link href=\"http://minify.localhost/assets/css/browser-specific.css\" rel=\"stylesheet\" type=\"text/css\" />',\n\t\t\t$result, 'output css with disabled library\\'s functionality');\n\t}\n\n\t// test js when no html tags\n\tpublic function testJsNoHtmlTagsWithDisabled()\n\t{\n\t\t$this->minify = new Minify();\n\n\t\t$this->minify->enabled = FALSE;\n\t\t$this->minify->html_tags = FALSE;\n\t\t$this->minify->assets_dir_js = 'assets/js';\n\t\t$this->minify->add_js(array('helpers.js'))->add_js('jqModal.js');\n\n\t\t$result = $this->minify->deploy_js(FALSE);\n\t\t$this->assertTrue(is_array($result), 'deploy with add_js');\n\n\t\t$this->assertEquals(array('http://minify.localhost/assets/js/helpers.js', 'http://minify.localhost/assets/js/jqModal.js'), $result, 'output js with no html tags');\n\t}\n\n\t// test css when no html tags\n\tpublic function testCssNoHtmlTagsWithDisabled()\n\t{\n\t\t$this->minify = new Minify();\n\n\t\t$this->minify->enabled = FALSE;\n\t\t$this->minify->html_tags = FALSE;\n\t\t$this->minify->assets_dir_css = 'assets/css';\n\t\t$this->minify->add_css(array('style.css'))->add_css('browser-specific.css');\n\n\t\t$result = $this->minify->deploy_css(TRUE);\n\t\t$this->assertTrue(is_array($result), 'deploy with add_css');\n\n\t\t$this->assertEquals(array('http://minify.localhost/assets/css/style.css', 'http://minify.localhost/assets/css/browser-specific.css'), $result, 'output css with no html tags');\n\t}\n\n\t// test js when no html tags\n\tpublic function testJsNoHtmlTagsWithEnabled()\n\t{\n\t\t$this->minify = new Minify();\n\n\t\t$this->minify->html_tags = FALSE;\n\t\t$this->minify->assets_dir_js = 'assets/js';\n\t\t$this->minify->add_js(array('helpers.js'))->add_js('jqModal.js');\n\n\t\t$result = $this->minify->deploy_js(FALSE);\n\t\t$this->assertTrue(is_array($result), 'deploy with add_js');\n\n\t\t$this->assertEquals(array('http://minify.localhost/assets/js/scripts.min.js'), $result, 'output js with no html tags');\n\t}\n\n\t// test css when no html tags\n\tpublic function testCssNoHtmlTagsWithEnabled()\n\t{\n\t\t$this->minify = new Minify();\n\n\t\t$this->minify->html_tags = FALSE;\n\t\t$this->minify->assets_dir_css = 'assets/css';\n\t\t$this->minify->add_css(array('style.css'))->add_css('browser-specific.css');\n\n\t\t$result = $this->minify->deploy_css(TRUE);\n\t\t$this->assertTrue(is_array($result), 'deploy with add_css');\n\n\t\t$this->assertEquals(array('http://minify.localhost/assets/css/styles.min.css'), $result, 'output css with no html tags');\n\t}\n\n\t// check js compression\n\tpublic function testJsCompress()\n\t{\n\t\t$this->minify = new Minify();\n\n\t\t$this->minify->js_dir = 'assets/js';\n\t\t$this->minify->js(array('helpers.js'));\n\n\t\t$result = $this->minify->deploy_js(FALSE, 'ut.js');\n\t\t$this->assertTrue(is_string($result), 'deploy js with name');\n\n\t\t$this->assertEquals($this->minify->js_file, 'ut.min.js', 'output js file name');\n\t}\n\n\t// check js compression with closule compiler\n\tpublic function testJsCompressWithClosureCompiler()\n\t{\n\t\t$this->minify = new Minify();\n\n\t\t$this->minify->js_dir = 'assets/js';\n\t\t$this->minify->compression_engine['js'] = 'closurecompiler';\n\t\t$this->minify->js(array('helpers.js'));\n\n\t\t$result = $this->minify->deploy_js(TRUE, 'ut.js');\n\t\t$this->assertTrue(is_string($result), 'deploy js with closurecompiler');\n\t\t$this->assertEquals($this->minify->js_file, 'ut.min.js', 'output js file name');\n\n\t\t$file_content = file_get_contents($this->minify->assets_dir.DIRECTORY_SEPARATOR.$this->minify->js_file);\n\t\t$this->assertNotContains('Error', $file_content, 'output file has errors');\n\t\t$this->assertTrue( ! empty($file_content), 'output is not empty');\n\t\t\n\t}\n\n\t// test css compresion\n\tpublic function testCssCompress()\n\t{\n\t\t$this->minify = new Minify();\n\n\t\t$this->minify->css_dir = 'assets/css';\n\t\t$this->minify->css(array('style.css'));\n\n\t\t$result = $this->minify->deploy_css(TRUE, 'ut.css');\n\t\t$this->assertTrue(is_string($result), 'deploy css with name');\n\n\t\t$this->assertEquals($this->minify->css_file, 'ut.min.css', 'output css file name');\n\t}\n\n\t// test js with auto names\n\tpublic function testJsCompressWithAutoNames()\n\t{\n\t\t$this->minify = new Minify();\n\n\t\t$this->minify->auto_names = TRUE;\n\t\t$this->minify->js_dir = 'assets/js';\n\t\t$this->minify->js(array('helpers.js'));\n\n\t\t$result = $this->minify->deploy_js(FALSE);\n\t\t$this->assertTrue(is_string($result), 'deploy js with auto name');\n\n\t\t$this->assertEquals($this->minify->js_file, '91e30b9b77dc616476b94acf4dbb25c1.min.js', 'output js auto file name');\n\t}\n\n\t// test css with auto names\n\tpublic function testCssCompressWithAutoNames()\n\t{\n\t\t$this->minify = new Minify();\n\n\t\t$this->minify->auto_names = TRUE;\n\t\t$this->minify->css_dir = 'assets/css';\n\t\t$this->minify->css(array('style.css'));\n\n\t\t$result = $this->minify->deploy_css(TRUE);\n\t\t$this->assertTrue(is_string($result), 'deploy css with auto name');\n\n\t\t$this->assertEquals($this->minify->css_file, '72ac8bfd7cb9dd0f9df9ef4aafe0c714.min.css', 'output css auto file name');\n\t}\n\n\t// test js add\n\tpublic function testJsCompressWithAdd()\n\t{\n\t\t$this->minify = new Minify();\n\n\t\t$this->minify->js_dir = 'assets/js';\n\t\t$this->minify->add_js(array('helpers.js'))->add_js('jqModal.js');\n\n\t\t$result = $this->minify->deploy_js(FALSE);\n\t\t$this->assertTrue(is_string($result), 'deploy with add_js');\n\n\t\t$this->assertEquals($this->minify->js_file, 'scripts.min.js', 'output js default file name');\n\t}\n\n\t// tetst css with cadd\n\tpublic function testCssCompressWithAdd()\n\t{\n\t\t$this->minify = new Minify();\n\n\t\t$this->minify->css_dir = 'assets/css';\n\t\t$this->minify->add_css(array('style.css'))->add_css('browser-specific.css');\n\n\t\t$result = $this->minify->deploy_css(TRUE);\n\t\t$this->assertTrue(is_string($result), 'deploy with add_css');\n\n\t\t$this->assertEquals($this->minify->css_file, 'styles.min.css', 'output css default file name');\n\t}\n\n\n\tpublic function testJsCompressWithIndividualAutoName()\n\t{\n\t\t$this->minify = new Minify();\n\n\t\t$this->minify->js_dir = 'assets/js';\n\t\t$this->minify->js(array('helpers.js'));\n\n\t\t$result = $this->minify->deploy_js(FALSE, 'auto');\n\t\t$this->assertTrue(is_string($result), 'deploy js with individual auto name');\n\n\t\t$this->assertEquals($this->minify->js_file, '91e30b9b77dc616476b94acf4dbb25c1.min.js', 'output js auto file name');\n\t}\n\n\tpublic function testCssCompressWithIndividualAutoName()\n\t{\n\t\t$this->minify = new Minify();\n\n\t\t$this->minify->css_dir = 'assets/css';\n\t\t$this->minify->css(array('style.css'));\n\n\t\t$result = $this->minify->deploy_css(TRUE, 'auto');\n\t\t$this->assertTrue(is_string($result), 'deploy css with individual auto name');\n\n\t\t$this->assertEquals($this->minify->css_file, '72ac8bfd7cb9dd0f9df9ef4aafe0c714.min.css', 'output css auto file name');\n\t}\n\n\t// feature/custom_folders_for_compiled_css_and_js\n\tpublic function testCustomJsPathForAssets()\n\t{\n\t\t$this->minify = new Minify();\n\n\t\t$this->minify->assets_dir_js = 'assets/js';\n\t\t$this->minify->js_dir = 'assets/js';\n\t\t$this->minify->js(array('helpers.js'));\n\n\t\t$result = $this->minify->deploy_js(TRUE, 'auto');\n\t\t$this->assertEquals('<script type=\"text/javascript\" src=\"http://minify.localhost/assets/js/91e30b9b77dc616476b94acf4dbb25c1.min.js\"></script>', $result, 'deploy js with custom save path');\n\t}\n\n\t//\n\tpublic function testCustomCssPathForAssets()\n\t{\n\t\t$this->minify = new Minify();\n\n\t\t$this->minify->assets_dir_css = 'assets/css';\n\t\t$this->minify->css_dir        = 'assets/css';\n\t\t$this->minify->css(array('style.css'));\n\n\t\t$result = $this->minify->deploy_css(TRUE, 'auto');\n\t\t$this->assertEquals('<link href=\"http://minify.localhost/assets/css/72ac8bfd7cb9dd0f9df9ef4aafe0c714.min.css\" rel=\"stylesheet\" type=\"text/css\" />', $result, 'deploy css with custom save path');\n\t}\n\n\tpublic function testCssCompressWithGroupNames()\n\t{\n\t\t$this->minify = new Minify();\n\n\t\t$this->minify->css_dir = 'assets/css';\n\t\t$this->minify->add_css(array('style.css'), 'sample1')->add_css('browser-specific.css', 'sample2');\n\n\t\t$result = $this->minify->deploy_css(TRUE, NULL, 'sample1');\n\t\t$this->assertTrue(is_string($result), 'deploy with group name: sample1');\n\n\t\t$this->assertEquals($this->minify->css_file, 'sample1_styles.min.css', 'output css default file name for group: sample1');\n\n\t\t$result = $this->minify->deploy_css(TRUE, NULL, 'sample2');\n\t\t$this->assertTrue(is_string($result), 'deploy with group name: sample2');\n\n\t\t$this->assertEquals($this->minify->css_file, 'sample2_styles.min.css', 'output css default file name for group: sample2');\n\t}\n\n\tpublic function testJsCompressWithGroupNames()\n\t{\n\t\t$this->minify = new Minify();\n\n\t\t$this->minify->css_dir = 'assets/js';\n\t\t$this->minify->add_js(array('helpers.js'), 'sample1')->add_js('jqModal.js', 'sample2');\n\n\t\t$result = $this->minify->deploy_js(TRUE, NULL, 'sample1');\n\t\t$this->assertTrue(is_string($result), 'deploy with group name: sample1');\n\n\t\t$this->assertEquals($this->minify->js_file, 'sample1_scripts.min.js', 'output js default file name for group: sample1');\n\n\t\t$result = $this->minify->deploy_js(TRUE, NULL, 'sample2');\n\t\t$this->assertTrue(is_string($result), 'deploy with group name: sample2');\n\n\t\t$this->assertEquals($this->minify->js_file, 'sample2_scripts.min.js', 'output js default file name for group: sample2');\n\t}\n\n\t// test versioning js\n\tpublic function testJsVersioning()\n\t{\n\t\t$this->minify = new Minify();\n\n\t\tunlink(APPPATH.'../assets/js/scripts.min.js');\n\n\t\t$this->minify->assets_dir_js = 'assets/js';\n\t\t$this->minify->versioning = TRUE;\n\t\t$this->minify->add_js(array('helpers.js'))->add_js('jqModal.js');\n\n\t\t$result = $this->minify->deploy_js(FALSE);\n\t\t$this->assertTrue(is_string($result), 'deploy js with versioning');\n\n\t\t$this->assertEquals('<script type=\"text/javascript\" src=\"http://minify.localhost/assets/js/scripts.min.js?v=a6a391594c356eb31f44360b30b40c6b\"></script>', $result, 'output js default file name with version');\n\t}\n\n\t// test versioning css\n\tpublic function testCssVersioning()\n\t{\n\t\t$this->minify = new Minify();\n\n\t\tunlink(APPPATH.'../assets/css/styles.min.css');\n\n\t\t$this->minify->assets_dir_css = 'assets/css';\n\t\t$this->minify->versioning = TRUE;\n\t\t$this->minify->add_css(array('style.css'))->add_css('browser-specific.css');\n\n\t\t$result = $this->minify->deploy_css(TRUE);\n\t\t$this->assertTrue(is_string($result), 'deploy css with versioning');\n\n\t\t$this->assertEquals('<link href=\"http://minify.localhost/assets/css/styles.min.css?v=bde54117b391ceca3436e85e7ddf1851\" rel=\"stylesheet\" type=\"text/css\" />', $result, 'output css default file name with versioning');\n\t}\n\n\t// test versioning js with custom version number\n\tpublic function testJsVersioningCustomNumber()\n\t{\n\t\t$this->minify = new Minify();\n\n\t\tunlink(APPPATH.'../assets/js/scripts.min.js');\n\n\t\t$this->minify->assets_dir_js = 'assets/js';\n\t\t$this->minify->versioning = TRUE;\n\t\t$this->minify->version_number = '12345';\n\t\t$this->minify->add_js(array('helpers.js'))->add_js('jqModal.js');\n\n\t\t$result = $this->minify->deploy_js(FALSE);\n\t\t$this->assertTrue(is_string($result), 'deploy js with versioning');\n\n\t\t$this->assertEquals('<script type=\"text/javascript\" src=\"http://minify.localhost/assets/js/scripts.min.js?v=12345\"></script>', $result, 'output js default file name with custom version number');\n\t}\n\n\t// test versioning css with custom version number\n\tpublic function testCssVersioningCustomNumber()\n\t{\n\t\t$this->minify = new Minify();\n\n\t\tunlink(APPPATH.'../assets/css/styles.min.css');\n\n\t\t$this->minify->assets_dir_css = 'assets/css';\n\t\t$this->minify->versioning = TRUE;\n\t\t$this->minify->version_number = '12345';\n\t\t$this->minify->add_css(array('style.css'))->add_css('browser-specific.css');\n\n\t\t$result = $this->minify->deploy_css(TRUE);\n\t\t$this->assertTrue(is_string($result), 'deploy css with versioning');\n\n\t\t$this->assertEquals('<link href=\"http://minify.localhost/assets/css/styles.min.css?v=12345\" rel=\"stylesheet\" type=\"text/css\" />', $result, 'output css default file name with custom version number');\n\t}\n\n\t// test deploy on change js\n\tpublic function testJsDeployOnChangeFalse()\n\t{\n\t\t$this->minify = new Minify();\n\n\t\t$this->minify->assets_dir_js = 'assets/js';\n\t\t$this->minify->versioning = TRUE;\n\n\t\t// deploy on change turned off\n\t\t$this->minify->deploy_on_change = FALSE;\n\t\t$this->minify->js(array('helpers.js'));\n\n\t\t$result = $this->minify->deploy_js(FALSE);\n\t\t$this->assertTrue(is_string($result), 'deploy js with deploy_on_change = FALSE');\n\n\t\t$this->assertEquals('<script type=\"text/javascript\" src=\"http://minify.localhost/assets/js/scripts.min.js?v=a6a391594c356eb31f44360b30b40c6b\"></script>', $result, 'output js default file name without deploy_on_change');\n\t}\n\n\t// test deploy on change css\n\tpublic function testCssDeployOnChangeFalse()\n\t{\n\t\t$this->minify = new Minify();\n\n\t\t$this->minify->assets_dir_css = 'assets/css';\n\t\t$this->minify->versioning = TRUE;\n\n\t\t// deploy on change turned off\n\t\t$this->minify->deploy_on_change = FALSE;\n\t\t$this->minify->css(array('style.css'));\n\n\t\t$result = $this->minify->deploy_css(FALSE);\n\t\t$this->assertTrue(is_string($result), 'deploy css with deploy_on_change = FALSE');\n\n\t\t$this->assertEquals('<link href=\"http://minify.localhost/assets/css/styles.min.css?v=bde54117b391ceca3436e85e7ddf1851\" rel=\"stylesheet\" type=\"text/css\" />', $result, 'output css default file name without deploy_on_change');\n\t}\n\n\t// test js with custom base url\n\tpublic function testJsWithChangedBaseUrl()\n\t{\n\t\t$this->minify = new Minify();\n\n\t\t$this->minify->html_tags = FALSE;\n\t\t$this->minify->base_url = 'http://cdn1.minify.localhost/';\n\t\t$this->minify->assets_dir_js = 'assets/js';\n\t\t$this->minify->add_js(array('helpers.js'))->add_js('jqModal.js');\n\n\t\t$result = $this->minify->deploy_js(FALSE);\n\t\t$this->assertTrue(is_array($result), 'deploy with add_js');\n\n\t\t$this->assertEquals(array('http://cdn1.minify.localhost/assets/js/scripts.min.js'), $result, 'output js with no html tags and custom base_url');\n\t}\n\n\t// test css with custom base url\n\tpublic function testCssWithChangedBaseUrl()\n\t{\n\t\t$this->minify = new Minify();\n\n\t\t$this->minify->html_tags = FALSE;\n\t\t$this->minify->base_url = 'http://cdn2.minify.localhost';\n\t\t$this->minify->assets_dir_css = 'assets/css';\n\t\t$this->minify->add_css(array('style.css'))->add_css('browser-specific.css');\n\n\t\t$result = $this->minify->deploy_css(TRUE);\n\t\t$this->assertTrue(is_array($result), 'deploy with add_css');\n\n\t\t$this->assertEquals(array('http://cdn2.minify.localhost/assets/css/styles.min.css'), $result, 'output css with no html tags and custom base_url');\n\t}\n\n\t// test js with custom config in constructor\n\tpublic function testJsWithCustomConstructorConfig()\n\t{\n\t\t$config = array('js_file' => 'changed_scripts.js');\n\t\t$this->minify = new Minify($config);\n\n\t\t$this->minify->html_tags = FALSE;\n\t\t$this->minify->assets_dir_js = 'assets/js';\n\t\t$this->minify->add_js(array('helpers.js'))->add_js('jqModal.js');\n\n\t\t$result = $this->minify->deploy_js(FALSE);\n\t\t$this->assertTrue(is_array($result), 'deploy with add_js');\n\n\t\t$this->assertEquals(array('http://minify.localhost/assets/js/changed_scripts.min.js'), $result, 'output js with no html tags');\n\t}\n\n\t// test css with custom config in constructor\n\tpublic function testCssWithCustomConstructorConfig()\n\t{\n\t\t$config = array('css_file' => 'changed_styles.css');\n\t\t$this->minify = new Minify($config);\n\n\t\t$this->minify->html_tags = FALSE;\n\t\t$this->minify->assets_dir_css = 'assets/css';\n\t\t$this->minify->add_css(array('style.css'))->add_css('browser-specific.css');\n\n\t\t$result = $this->minify->deploy_css(TRUE);\n\t\t$this->assertTrue(is_array($result), 'deploy with add_css');\n\n\t\t$this->assertEquals(array('http://minify.localhost/assets/css/changed_styles.min.css'), $result, 'output css with no html tags');\n\t}\n\n}"
  },
  {
    "path": "tests/bootstrap.php",
    "content": "<?php\n\ndefine('BASEPATH', 'application');\ndefine('APPPATH', 'application/');\n\n\n\nfunction get_instance()\n{\n\treturn new CI();\n}\n\nfunction base_url($string) {\n\tstatic $base_url = NULL;\n\n\tif ($base_url === NULL)\n\t{\n\t\tinclude_once(APPPATH.'config/config.php');\n\t\t$base_url = $config['base_url'];\n\t}\n\n\treturn $base_url.$string;\n}\n\nfunction link_tag($string) {\n\treturn $string;\n}\n\nfunction log_message($string1, $string2) {\n\treturn;\n}\n\nclass CI\n{\n\n\n\tpublic function __construct()\n\t{\n\t\t$this->load   = new CI_Loader();\n\t\t$this->config = new CI_Config();\n\t}\n\n\tpublic function config()\n\t{\n\n\t}\n\n\n}\n\n/**\n * The loads happen in the constructor (before we can mock anything out),\n * so instead we'll fakeify the Loader\n */\nclass CI_Loader\n{\n\tpublic function __construct()\n\t{\n\t\t$this->item = new CI_Config();\n\t}\n\n\tpublic function __call($method, $params = array())\n\t{\n\n\n\t}\n\n}\n\nclass CI_Config\n{\n\tpublic function __call($method, $params = array())\n\t{\n\n\t\tswitch ($params[0]) {\n\t\t\tcase 'assets_dir':\n\t\t\t\treturn sys_get_temp_dir();\n\t\t\t\tbreak;\n\t\t\tcase 'compression_engine':\n\t\t\t\treturn array('js' => 'jsmin', 'css' => 'minify');\n\t\t\t\tbreak;\n\t\t}\n\t}\n}\n\n\n"
  }
]