diff --git a/htdocs/application/libraries/carabiner.php b/htdocs/application/libraries/carabiner.php
new file mode 100644
index 0000000..bf2a80c
--- /dev/null
+++ b/htdocs/application/libraries/carabiner.php
@@ -0,0 +1,708 @@
+
+ * @version 1.2
+ * @license http://www.opensource.org/licenses/bsd-license.php BSD licensed.
+ */
+
+/*
+ ===============================================================================================
+ USAGE
+ ===============================================================================================
+
+ Load the library as normal:
+ -----------------------------------------------------------------------------------------------
+ $this->load->library('carabiner');
+ -----------------------------------------------------------------------------------------------
+
+ Configure it like so:
+ -----------------------------------------------------------------------------------------------
+ $carabiner_config = array(
+ 'script_dir' => 'assets/scripts/',
+ 'style_dir' => 'assets/styles/',
+ 'cache_dir' => 'assets/cache/',
+ 'base_uri' => $base,
+ 'combine' => TRUE,
+ 'dev' => FALSE
+ );
+
+ $this->carabiner->config($carabiner_config);
+ -----------------------------------------------------------------------------------------------
+
+
+ There are 8 options. 4 are required:
+
+ script_dir
+ STRING Path to the script directory. Relative to the CI front controller (index.php)
+
+ style_dir
+ STRING Path to the style directory. Relative to the CI front controller (index.php)
+
+ cache_dir
+ STRING Path to the cache directory. Must be writable. Relative to the CI front controller (index.php)
+
+ base_uri
+ STRING Base uri of the site, like http://www.example.com/
+
+
+ 4 are not required:
+
+ dev
+ BOOL Flags whether your in a development environment or not. See above for what this means.
+ Defaults to FALSE.
+
+ combine
+ BOOLEAN Flags whether to combine files. Defaults to TRUE.
+
+ minify_js
+ BOOLEAN Flags whether to minify javascript. Defaults to TRUE.
+
+ minify_css
+ BOOLEAN Flags whether to minify CSS. Defaults to TRUE.
+
+
+ Add assets like so:
+ -----------------------------------------------------------------------------------------------
+ // add a js file
+ $this->carabiner->js('scripts.js');
+
+ // add a css file
+ $this->carabiner->css('reset.css');
+
+ // add a css file with a mediatype
+ $this->carabiner->css('admin/print.css','print');
+ -----------------------------------------------------------------------------------------------
+
+
+
+ To set a (prebuilt) production version of a js asset:
+ -----------------------------------------------------------------------------------------------
+ // JS: pass a second string to the method with a path to the production version
+ $this->carabiner->js('wymeditor/wymeditor.js', 'wymeditor/wymeditor.pack.js' );
+
+ // add a css file with prebuilt production version
+ $this->carabiner->css('framework/type.css', 'screen', 'framework/type.pack.css');
+ -----------------------------------------------------------------------------------------------
+
+
+ And to prevent a file from being combined:
+ -----------------------------------------------------------------------------------------------
+ // JS: pass a boolean FALSE as the third attribute of the method
+ $this->carabiner->js('wymeditor/wymeditor.js', 'wymeditor.pack.js', FALSE );
+
+ // CSS: pass a boolean FALSE as the fourth attribute of the method
+ $this->carabiner->css('framework/type.css', 'screen', 'framework/type.pack.css', FALSE);
+ -----------------------------------------------------------------------------------------------
+
+
+
+ You can also pass arrays (and arrays of arrays) to these methods. Like so:
+ -----------------------------------------------------------------------------------------------
+ // a single array
+ $this->carabiner->css( array('mobile.css', 'handheld', 'mobile.prod.css') );
+
+ // an array of arrays
+ $js_assets = array(
+ array('dev/jquery.js', 'prod/jquery.js'),
+ array('dev/jquery.ext.js', 'prod/jquery.ext.js'),
+ )
+
+ $this->carabiner->js( $js_assets );
+ -----------------------------------------------------------------------------------------------
+
+
+ To output your assets, including appropriate markup:
+ -----------------------------------------------------------------------------------------------
+ // display css
+ $this->carabiner->display('css');
+
+ //display js
+ $this->carabiner->display('js');
+ -----------------------------------------------------------------------------------------------
+
+
+ Since Carabiner won't delete old cached files, you'll need to clear them out manually.
+ To do so programatically:
+ -----------------------------------------------------------------------------------------------
+ // clear css cache
+ $this->carabiner->empty_cache('css');
+
+ //clear js cache
+ $this->carabiner->empty_cache('js');
+
+ // clear both
+ $this->carabiner->empty_cache();
+ -----------------------------------------------------------------------------------------------
+ ===============================================================================================
+*/
+
+class Carabiner {
+
+ var $base_uri = '';
+
+ var $script_dir = '';
+ var $script_path = '';
+ var $script_uri = '';
+
+ var $style_dir = '';
+ var $style_path = '';
+ var $style_uri = '';
+
+ var $cache_dir = '';
+ var $cache_path = '';
+ var $cache_uri = '';
+
+ var $dev = FALSE;
+ var $combine = TRUE;
+
+ var $minify_js = TRUE;
+ var $minify_css = TRUE;
+
+ var $js = array();
+ var $css = array();
+
+ var $CI;
+
+
+ /**
+ * Class Constructor
+ */
+ public function __construct()
+ {
+ $this->CI =& get_instance();
+ log_message('debug', 'Carabiner Asset Management library initialized.');
+
+ }
+
+
+ /**
+ * Load Config
+ * @param Array of config variables. Requires script_dir(string), style_dir(string), cache_dir(string), and base_uri(string).
+ * dev(bool), combine(bool), minify_js(bool), minify_css(bool) are optional.
+ */
+ public function config($config)
+ {
+ foreach ($config as $key => $value)
+ {
+ $this->$key = $value;
+ }
+
+ // use the provided values to define the rest of them
+ //$this->script_path = dirname(BASEPATH).'/'.$this->script_dir;
+ $this->script_path = $this->script_dir;
+ $this->script_uri = $this->base_uri.$this->script_dir;
+
+ //$this->style_path = dirname(BASEPATH).'/'.$this->style_dir;
+ $this->style_path = $this->style_dir;
+ $this->style_uri = $this->base_uri.$this->style_dir;
+
+ //$this->cache_path = dirname(BASEPATH).'/'.$this->cache_dir;
+ $this->cache_path = $this->cache_dir;
+ $this->cache_uri = $this->base_uri.$this->cache_dir;
+ }
+
+
+
+ /**
+ * Add JS file to queue
+ * @param String of the path to development version of the JS file. Could also be an array, or array of arrays.
+ * @param String of the path to production version of the JS file. NOT REQUIRED
+ * @param Flag whether the file is to be combined NOT REQUIRED
+ */
+ public function js($dev_file, $prod_file = '', $combine = TRUE)
+ {
+
+ if( is_array($dev_file) ){
+
+ if( is_array($dev_file[0]) ){
+
+ foreach($dev_file as $file){
+
+ $d = $file[0];
+ $p = (isset($file[1])) ? $file[1] : '';
+ $c = (isset($file[2])) ? $file[2] : $combine;
+
+ $this->_asset('js', $d, $p, $c);
+
+ }
+
+ }else{
+
+ $d = $dev_file[0];
+ $p = (isset($dev_file[1])) ? $dev_file[1] : '';
+ $c = (isset($dev_file[2])) ? $dev_file[2] : $combine;
+
+ $this->_asset('js', $d, $p, $c);
+
+ }
+
+ }else{
+
+ $this->_asset('js', $dev_file, $prod_file, $combine);
+
+ }
+ }
+
+
+
+ /**
+ * Add CSS file to queue
+ * @param String of the path to development version of the CSS file. Could also be an array, or array of arrays.
+ * @param String of the media type, usually one of (screen, print, handheld) for css. Defaults to screen.
+ * @param String of the path to production version of the CSS file. NOT REQUIRED
+ * @param Flag whether the file is to be combined. NOT REQUIRED
+ */
+ public function css($dev_file, $media = 'all', $prod_file = '', $combine = TRUE)
+ {
+
+ if( is_array($dev_file) ){
+
+ if( is_array($dev_file[0]) ){
+
+ foreach($dev_file as $file){
+
+ $d = $file[0];
+ $m = (isset($file[1])) ? $file[1] : $media;
+ $p = (isset($file[2])) ? $file[2] : '';
+ $c = (isset($file[3])) ? $file[3] : $combine;
+
+ $this->_asset('css', $d, $p, $c, $m);
+
+ }
+
+ }else{
+
+ $d = $dev_file[0];
+ $m = (isset($file[1])) ? $file[1] : $media;
+ $p = (isset($dev_file[2])) ? $dev_file[2] : '';
+ $c = (isset($dev_file[3])) ? $dev_file[3] : $combine;
+
+ $this->_asset('css', $d, $p, $c, $m);
+
+ }
+
+ }else{
+
+ $this->_asset('css', $dev_file, $prod_file, $combine, $media);
+
+ }
+ }
+
+
+ /**
+ * Add an asset to queue
+ * @param String of the type of asset (lowercase) . css | js
+ * @param String of the path to development version of the asset.
+ * @param String of the path to production version of the asset. NOT REQUIRED
+ * @param Flag whether the file is to be combined. Defaults to true. NOT REQUIRED
+ * @param String of the media type associated with the asset. Only applicable to CSS assets. NOT REQUIRED
+ */
+ private function _asset($type, $dev_file, $prod_file = '', $combine = TRUE, $media = 'screen')
+ {
+ if ($type == 'css') :
+
+ $this->css[$media][] = array( 'dev'=>$dev_file );
+ $index = count($this->css[$media]) - 1;
+
+ if($prod_file != '') $this->{$type}[$media][$index]['prod'] = $prod_file;
+ $this->css[$media][$index]['combine'] = $combine;
+
+ else :
+
+ $this->{$type}[] = array( 'dev'=>$dev_file );
+ $index = count($this->{$type}) - 1;
+
+ if($prod_file != '') $this->js[$index]['prod'] = $prod_file;
+ $this->js[$index]['combine'] = $combine;
+
+ endif;
+
+ }
+
+
+ /**
+ * Display HTML references to the assets
+ * @param Flag the asset type: css|js
+ */
+ public function display($flag)
+ {
+ switch($flag){
+
+ case 'js':
+
+ if( empty($this->js) ) return; // if there aren't any js files, just stop!
+
+ // if we're in a dev environment
+ if($this->dev){
+
+ foreach($this->js as $ref):
+
+ echo $this->_tag('js', $ref['dev']);
+
+ endforeach;
+
+
+ // if we're combining files
+ } elseif($this->combine) {
+
+ $lastmodified = 0;
+ $files = array();
+ $filenames = '';
+ $not_combined = '';
+
+ foreach ($this->js as $ref) {
+
+ // get the last modified date of the most recently modified file
+ $lastmodified = max( $lastmodified , filemtime( realpath($this->script_path.$ref['dev']) ) );
+ $filenames .= $ref['dev'];
+
+ if($ref['combine'] == false):
+ $not_combined .= (isset($ref['prod'])) ? $this->_tag('js', $ref['prod']) : $this->_tag('js', $ref['dev']);
+ else:
+ $files[] = (isset($ref['prod'])) ? array('prod'=>$ref['prod'], 'dev'=>$ref['dev'] ) : array('dev'=>$ref['dev']);
+ endif;
+ }
+
+ $filename = $lastmodified . md5($filenames).'.js';
+
+ if( !file_exists($this->cache_path.$filename) ) $this->_combine('js', $files, $filename);
+
+ echo $not_combined;
+ echo $this->_tag('js', $filename, TRUE);
+
+
+
+ // if we're minifying. but not combining
+ } elseif(!$this->combine && $this->minify_js) {
+
+ // minify each file, cache it, and serve it up. Oy.
+ foreach($this->js as $ref):
+
+ if( isset($ref['prod']) ){
+
+ $f = $ref['prod'];
+
+ echo $this->_tag('js', $f, FALSE);
+
+ } else {
+
+ $f = filemtime( realpath( $this->script_path . $ref['dev'] ) ) . md5($ref['dev']) . '.js';
+
+ if( !file_exists($this->cache_path.$f) ):
+
+ $c = $this->_minify( 'js', $ref['dev'] );
+ $this->_cache($f, $c);
+
+ endif;
+
+ echo $this->_tag('js', $f, TRUE);
+ }
+
+ endforeach;
+
+ }else{
+
+ foreach($this->js as $ref):
+
+ $f = (isset($ref['prod'])) ? $ref['prod'] : $ref['dev'];
+ echo $this->_tag('js', $f);
+
+ endforeach;
+
+ }
+
+ break;
+
+ case 'css':
+
+ if( empty($this->css) ) return; // there aren't any css assets, so just stop!
+
+ if($this->dev){ // we're in a development environment
+
+ foreach($this->css as $media => $refs):
+
+ foreach($refs as $ref):
+
+ echo $this->_tag('css', $ref['dev'], FALSE, $media);
+
+ endforeach;
+
+ endforeach;
+
+ } elseif($this->combine) { // we're combining and minifying
+
+ foreach($this->css as $media => $refs):
+
+ // lets try to cache it, shall we?
+ $lastmodified = 0;
+ $files = array();
+ $filenames = '';
+ $not_combined = '';
+
+ foreach ($refs as $ref):
+
+ $lastmodified = max($lastmodified, filemtime( realpath( $this->style_path . $ref['dev'] ) ) );
+ $filenames .= $ref['dev'];
+
+ if($ref['combine'] == false):
+ $not_combined .= (isset($ref['prod'])) ? $this->_tag('css', $ref['prod'], $media) : $this->_tag('css', $ref['dev'], $media);
+ else:
+ $files[] = (isset($ref['prod'])) ? array('prod'=>$ref['prod'], 'dev'=>$ref['dev'] ) : array('dev'=>$ref['dev']);
+ endif;
+
+ endforeach;
+
+ $filename = $lastmodified . md5($filenames).'.css';
+
+ if( !file_exists($this->cache_path.$filename) ) $this->_combine('css', $files, $filename);
+
+ echo $not_combined;
+ echo $this->_tag('css', $filename, TRUE, $media);
+
+ endforeach;
+
+ } elseif(!$this->combine && $this->minify_css) { // we want to minify, but not combine
+
+ foreach($this->css as $media => $refs):
+
+ foreach($refs as $ref):
+
+ if( isset($ref['prod']) ){
+
+ $f = $this->style_uri . $ref['prod'];
+
+ } else {
+
+ $f = filemtime( realpath( $this->style_path . $ref['dev'] ) ) . md5($ref['dev']) . '.css';
+
+ if( !file_exists($this->cache_path.$f) ):
+
+ $c = $this->_minify( 'css', $ref['dev'] );
+ $this->_cache($f, $c);
+
+ endif;
+ }
+
+ echo $this->_tag('css', $f, TRUE, $media);
+
+ endforeach;
+
+ endforeach;
+
+ }else{ // we're in a production environment, but not minifying or combining
+
+ foreach($this->css as $media => $refs):
+
+ foreach($refs as $ref):
+
+ $f = (isset($ref['prod'])) ? $ref['prod'] : $ref['dev'];
+ echo $this->_tag('css', $f, FALSE, $media);
+
+ endforeach;
+
+ endforeach;
+
+ }
+
+ break;
+
+ }
+ }
+
+
+ /**
+ * Internal function for compressing/combining scripts
+ * @param Flag the asset type: css|js
+ * @param array of file references to be combined. Should contain arrays, as included in primary asset arrays: ('dev'=>$dev, 'prod'=>$prod)
+ * @param Filename of the file-to-be
+ */
+ private function _combine($flag, $files, $filename)
+ {
+
+ $file_data = '';
+
+ $path = ($flag == 'css') ? $this->style_path : $this->script_path;
+ $minify = ($flag == 'css') ? $this->minify_css : $this->minify_js;
+
+
+ foreach($files as $file):
+
+ if($minify):
+
+ $file_data .= $this->_minify( $flag, $file['dev'] ) . "\n";
+
+ else:
+
+ $file_data .= file_get_contents( realpath($path.$file['dev']) ) ."\n";
+
+ endif;
+
+ endforeach;
+
+ $this->_cache( $filename, $file_data );
+
+ }
+
+
+ /**
+ * Internal function for minifying assets
+ * @param Flag the asset type: css|js
+ * @param Contents to be minified
+ */
+ private function _minify($flag, $file_ref)
+ {
+
+ switch($flag){
+
+ case 'js':
+
+ $this->CI->load->library('jsmin');
+
+ $contents = file_get_contents( realpath($this->script_path.$file_ref) );
+ return $this->CI->jsmin->minify($contents);
+
+ break;
+
+
+ case 'css':
+
+ $this->CI->load->library('cssmin');
+ $this->CI->cssmin->config(array('relativePath'=>$this->style_uri));
+
+ $contents = file_get_contents( realpath($this->style_path.$file_ref) );
+ return $this->CI->cssmin->minify($contents);
+
+ break;
+ }
+
+ }
+
+
+ /**
+ * Internal function for writing cache files
+ * @param filename of the new file
+ * @param Contents of the new file
+ */
+ private function _cache($filename, $file_data)
+ {
+ $filepath = $this->cache_path . $filename;
+ //change ernscht: $filepath = realpath($this->cache_path . $filename);
+ file_put_contents( $filepath, $file_data );
+
+ }
+
+
+ /**
+ * Internal function for making tag strings
+ * @param flag for type: css|js
+ * @param Reference of file.
+ * @param Flag for cache dir. Defaults to FALSE.
+ * @param Media type for the tag. Only applies to CSS links. defaults to 'screen'
+ */
+ private function _tag($flag, $ref, $cache = FALSE, $media = 'screen')
+ {
+
+
+ switch($flag){
+
+ case 'css':
+
+ $dir = ($cache) ? $this->cache_uri : $this->style_uri;
+
+ echo ''."\r\n";
+
+ break;
+
+ case 'js':
+
+ $dir = ($cache) ? $this->cache_uri : $this->script_uri;
+
+ echo ''."\r\n";
+
+ break;
+
+ }
+
+ }
+
+
+ /**
+ * Function used to clear the asset cache. If no flag is set, both CSS and JS will be emptied.
+ * @param Flag the asset type: css|js|both
+ */
+ public function empty_cache($flag)
+ {
+
+ $this->CI->load->helper('file');
+
+ $files = get_filenames($this->cache_path);
+
+ switch($flag){
+
+ case 'js':
+ case 'css':
+
+ foreach( $files as $file ){
+
+ $ext = substr( strrchr( $file, '.' ), 1 );
+
+ if ( $ext == $flag ) {
+
+ unlink( $this->cache_path . $file );
+
+ }
+
+ }
+
+ break;
+
+
+ default:
+
+ foreach( $files as $file ){
+
+ $ext = substr( strrchr( $file, '.' ), 1 );
+
+ if ( $ext == 'js' || $ext == 'css') {
+
+ unlink( $this->cache_path . $file );
+
+ }
+
+ }
+
+ break;
+
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/htdocs/application/libraries/cssmin.php b/htdocs/application/libraries/cssmin.php
new file mode 100644
index 0000000..704f6f9
--- /dev/null
+++ b/htdocs/application/libraries/cssmin.php
@@ -0,0 +1,509 @@
+
+ * @version 1.1 (2009-01-28)
+ * @license http://www.opensource.org/licenses/bsd-license.php BSD license, as per the original Minify_CSS class
+ *
+ **/
+
+/*
+ ===============================================================================================
+ USAGE
+ ===============================================================================================
+
+ Load the library as normal:
+ -----------------------------------------------------------------------------------------------
+ $this->load->library('cssmin');
+ -----------------------------------------------------------------------------------------------
+
+ Minify a string like so:
+ -----------------------------------------------------------------------------------------------
+ $this->cssmin->minify( file_get_contents('styles.css') );
+ -----------------------------------------------------------------------------------------------
+
+
+ There are two options:
+
+ 'preserveComments'
+ Boolean flag for preserving comments. Only comments starting with /*! are preserved.
+ Defaults to true.
+
+ 'relativePath'
+ String that will be prepended to all relative URIs in import/url declarations.
+ Defaults to null.
+
+
+ The options can either be set globally using the config function:
+ -----------------------------------------------------------------------------------------------
+ $cssmin_options = array(
+ 'preserveComments'=> TRUE,
+ 'relativePath'=> 'http://www.example.com/styles/images/'
+ );
+
+ $this->cssmin->config($cssmin_options);
+ -----------------------------------------------------------------------------------------------
+
+
+ Or on individual calls to the minify function:
+ -----------------------------------------------------------------------------------------------
+ $this->cssmin->minify( $string, FALSE, $path );
+ -----------------------------------------------------------------------------------------------
+
+ NOTE: Global settings override settings in individual calls.
+ ===============================================================================================
+*/
+
+ class cssmin {
+
+ public function cssmin()
+ {
+ log_message('debug', 'CSS Minification library initialized.');
+ }
+
+
+ public function config($config)
+ {
+ foreach ($config as $key => $value)
+ {
+ $this->$key = $value;
+ }
+
+ }
+
+ public function minify($css, $preserveComments = TRUE, $relativePath = null)
+ {
+ $c = ( isset($this->preserveComments) ) ? $this->preserveComments : $preserveComments;
+ $p = ( isset($this->relativePath) ) ? $this->relativePath : $relativePath;
+
+ $min = new Minify_CSS();
+ return $min->minify($css, array('preserveComments'=> $c, 'prependRelativePath' => $p));
+ }
+
+ }
+
+
+/**
+ * Class Minify_CSS
+ * @package Minify
+ */
+
+/**
+ * Compress CSS
+ *
+ * This is a heavy regex-based removal of whitespace, unnecessary
+ * comments and tokens, and some CSS value minimization, where practical.
+ * Many steps have been taken to avoid breaking comment-based hacks,
+ * including the ie5/mac filter (and its inversion), but expect tricky
+ * hacks involving comment tokens in 'content' value strings to break
+ * minimization badly. A test suite is available.
+ *
+ * @package Minify
+ * @author Stephen Clay
+ * @author http://code.google.com/u/1stvamp/ (Issue 64 patch)
+ */
+class Minify_CSS {
+
+ /**
+ * Defines which class to call as part of callbacks, change this
+ * if you extend Minify_CSS
+ * @var string
+ */
+ protected static $className = 'Minify_CSS';
+
+ /**
+ * Minify a CSS string
+ *
+ * @param string $css
+ *
+ * @param array $options available options:
+ *
+ * 'preserveComments': (default true) multi-line comments that begin
+ * with "/*!" will be preserved with newlines before and after to
+ * enhance readability.
+ *
+ * 'prependRelativePath': (default null) if given, this string will be
+ * prepended to all relative URIs in import/url declarations
+ *
+ * 'currentDir': (default null) if given, this is assumed to be the
+ * directory of the current CSS file. Using this, minify will rewrite
+ * all relative URIs in import/url declarations to correctly point to
+ * the desired files. For this to work, the files *must* exist and be
+ * visible by the PHP process.
+ *
+ * @return string
+ */
+ public static function minify($css, $options = array())
+ {
+ if (isset($options['preserveComments'])
+ && !$options['preserveComments']) {
+ return self::_minify($css, $options);
+ }
+
+ // recursive calls don't preserve comments
+ $options['preserveComments'] = false;
+ return Minify_CommentPreserver::process(
+ $css
+ ,array(self::$className, 'minify')
+ ,array($options)
+ );
+ }
+
+ /**
+ * Minify a CSS string
+ *
+ * @param string $css
+ *
+ * @param array $options To enable URL rewriting, set the value
+ * for key 'prependRelativePath'.
+ *
+ * @return string
+ */
+ protected static function _minify($css, $options)
+ {
+ $css = str_replace("\r\n", "\n", $css);
+
+ // preserve empty comment after '>'
+ // http://www.webdevout.net/css-hacks#in_css-selectors
+ $css = preg_replace('@>/\\*\\s*\\*/@', '>/*keep*/', $css);
+
+ // preserve empty comment between property and value
+ // http://css-discuss.incutio.com/?page=BoxModelHack
+ $css = preg_replace('@/\\*\\s*\\*/\\s*:@', '/*keep*/:', $css);
+ $css = preg_replace('@:\\s*/\\*\\s*\\*/@', ':/*keep*/', $css);
+
+ // apply callback to all valid comments (and strip out surrounding ws
+ self::$_inHack = false;
+ $css = preg_replace_callback('@\\s*/\\*([\\s\\S]*?)\\*/\\s*@'
+ ,array(self::$className, '_commentCB'), $css);
+
+ // remove ws around { } and last semicolon in declaration block
+ $css = preg_replace('/\\s*{\\s*/', '{', $css);
+ $css = preg_replace('/;?\\s*}\\s*/', '}', $css);
+
+ // remove ws surrounding semicolons
+ $css = preg_replace('/\\s*;\\s*/', ';', $css);
+
+ // remove ws around urls
+ $css = preg_replace('/
+ url\\( # url(
+ \\s*
+ ([^\\)]+?) # 1 = the URL (really just a bunch of non right parenthesis)
+ \\s*
+ \\) # )
+ /x', 'url($1)', $css);
+
+ // remove ws between rules and colons
+ $css = preg_replace('/
+ \\s*
+ ([{;]) # 1 = beginning of block or rule separator
+ \\s*
+ ([\\*_]?[\\w\\-]+) # 2 = property (and maybe IE filter)
+ \\s*
+ :
+ \\s*
+ (\\b|[#\'"]) # 3 = first character of a value
+ /x', '$1$2:$3', $css);
+
+ // remove ws in selectors
+ $css = preg_replace_callback('/
+ (?: # non-capture
+ \\s*
+ [^~>+,\\s]+ # selector part
+ \\s*
+ [,>+~] # combinators
+ )+
+ \\s*
+ [^~>+,\\s]+ # selector part
+ { # open declaration block
+ /x'
+ ,array(self::$className, '_selectorsCB'), $css);
+
+ // minimize hex colors
+ $css = preg_replace('/([^=])#([a-f\\d])\\2([a-f\\d])\\3([a-f\\d])\\4([\\s;\\}])/i'
+ , '$1#$2$3$4$5', $css);
+
+ // remove spaces between font families
+ $css = preg_replace_callback('/font-family:([^;}]+)([;}])/'
+ ,array(self::$className, '_fontFamilyCB'), $css);
+
+ $css = preg_replace('/@import\\s+url/', '@import url', $css);
+
+ // replace any ws involving newlines with a single newline
+ $css = preg_replace('/[ \\t]*\\n+\\s*/', "\n", $css);
+
+ // separate common descendent selectors w/ newlines (to limit line lengths)
+ $css = preg_replace('/([\\w#\\.\\*]+)\\s+([\\w#\\.\\*]+){/', "$1\n$2{", $css);
+
+ // Use newline after 1st numeric value (to limit line lengths).
+ $css = preg_replace('/
+ ((?:padding|margin|border|outline):\\d+(?:px|em)?) # 1 = prop : 1st numeric value
+ \\s+
+ /x'
+ ,"$1\n", $css);
+
+ $rewrite = false;
+ if (isset($options['prependRelativePath'])) {
+ self::$_tempPrepend = $options['prependRelativePath'];
+ $rewrite = true;
+ } elseif (isset($options['currentDir'])) {
+ self::$_tempCurrentDir = $options['currentDir'];
+ $rewrite = true;
+ }
+ if ($rewrite) {
+ $css = preg_replace_callback('/@import\\s+([\'"])(.*?)[\'"]/'
+ ,array(self::$className, '_urlCB'), $css);
+ $css = preg_replace_callback('/url\\(\\s*([^\\)\\s]+)\\s*\\)/'
+ ,array(self::$className, '_urlCB'), $css);
+ }
+ self::$_tempPrepend = self::$_tempCurrentDir = '';
+ return trim($css);
+ }
+
+ /**
+ * Replace what looks like a set of selectors
+ *
+ * @param array $m regex matches
+ *
+ * @return string
+ */
+ protected static function _selectorsCB($m)
+ {
+ // remove ws around the combinators
+ return preg_replace('/\\s*([,>+~])\\s*/', '$1', $m[0]);
+ }
+
+ /**
+ * @var bool Are we "in" a hack?
+ *
+ * I.e. are some browsers targetted until the next comment?
+ */
+ protected static $_inHack = false;
+
+ /**
+ * @var string string to be prepended to relative URIs
+ */
+ protected static $_tempPrepend = '';
+
+ /**
+ * @var string directory of this stylesheet for rewriting purposes
+ */
+ protected static $_tempCurrentDir = '';
+
+ /**
+ * Process a comment and return a replacement
+ *
+ * @param array $m regex matches
+ *
+ * @return string
+ */
+ protected static function _commentCB($m)
+ {
+ $m = $m[1];
+ // $m is the comment content w/o the surrounding tokens,
+ // but the return value will replace the entire comment.
+ if ($m === 'keep') {
+ return '/**/';
+ }
+ if ($m === '" "') {
+ // component of http://tantek.com/CSS/Examples/midpass.html
+ return '/*" "*/';
+ }
+ if (preg_match('@";\\}\\s*\\}/\\*\\s+@', $m)) {
+ // component of http://tantek.com/CSS/Examples/midpass.html
+ return '/*";}}/* */';
+ }
+ if (self::$_inHack) {
+ // inversion: feeding only to one browser
+ if (preg_match('@
+ ^/ # comment started like /*/
+ \\s*
+ (\\S[\\s\\S]+?) # has at least some non-ws content
+ \\s*
+ /\\* # ends like /*/ or /**/
+ @x', $m, $n)) {
+ // end hack mode after this comment, but preserve the hack and comment content
+ self::$_inHack = false;
+ return "/*/{$n[1]}/**/";
+ }
+ }
+ if (substr($m, -1) === '\\') { // comment ends like \*/
+ // begin hack mode and preserve hack
+ self::$_inHack = true;
+ return '/*\\*/';
+ }
+ if ($m !== '' && $m[0] === '/') { // comment looks like /*/ foo */
+ // begin hack mode and preserve hack
+ self::$_inHack = true;
+ return '/*/*/';
+ }
+ if (self::$_inHack) {
+ // a regular comment ends hack mode but should be preserved
+ self::$_inHack = false;
+ return '/**/';
+ }
+ return ''; // remove all other comments
+ }
+
+ protected static function _urlCB($m)
+ {
+ $isImport = (0 === strpos($m[0], '@import'));
+ if ($isImport) {
+ $quote = $m[1];
+ $url = $m[2];
+ } else {
+ // is url()
+ // $m[1] is either quoted or not
+ $quote = ($m[1][0] === "'" || $m[1][0] === '"')
+ ? $m[1][0]
+ : '';
+ $url = ($quote === '')
+ ? $m[1]
+ : substr($m[1], 1, strlen($m[1]) - 2);
+ }
+ if ('/' !== $url[0]) {
+ if (strpos($url, '//') > 0) {
+ // probably starts with protocol, do not alter
+ } else {
+ // relative URI, rewrite!
+ if (self::$_tempPrepend) {
+ $url = self::$_tempPrepend . $url;
+ } else {
+ // rewrite absolute url from scratch!
+ // prepend path with current dir separator (OS-independent)
+ $path = self::$_tempCurrentDir
+ . DIRECTORY_SEPARATOR . strtr($url, '/', DIRECTORY_SEPARATOR);
+ // strip doc root
+ $path = substr($path, strlen(realpath($_SERVER['DOCUMENT_ROOT'])));
+ // fix to absolute URL
+ $url = strtr($path, DIRECTORY_SEPARATOR, '/');
+ // remove /./ and /../ where possible
+ $url = str_replace('/./', '/', $url);
+ // inspired by patch from Oleg Cherniy
+ do {
+ $url = preg_replace('@/[^/]+/\\.\\./@', '/', $url, -1, $changed);
+ } while ($changed);
+ }
+ }
+ }
+ return $isImport
+ ? "@import {$quote}{$url}{$quote}"
+ : "url({$quote}{$url}{$quote})";
+ }
+
+ /**
+ * Process a font-family listing and return a replacement
+ *
+ * @param array $m regex matches
+ *
+ * @return string
+ */
+ protected static function _fontFamilyCB($m)
+ {
+ $m[1] = preg_replace('/
+ \\s*
+ (
+ "[^"]+" # 1 = family in double qutoes
+ |\'[^\']+\' # or 1 = family in single quotes
+ |[\\w\\-]+ # or 1 = unquoted family
+ )
+ \\s*
+ /x', '$1', $m[1]);
+ return 'font-family:' . $m[1] . $m[2];
+ }
+}
+
+/**
+ * Class Minify_CommentPreserver
+ * @package Minify
+ */
+
+/**
+ * Process a string in pieces preserving C-style comments that begin with "/*!"
+ *
+ * @package Minify
+ * @author Stephen Clay
+ */
+class Minify_CommentPreserver {
+
+ /**
+ * String to be prepended to each preserved comment
+ *
+ * @var string
+ */
+ public static $prepend = "\n";
+
+ /**
+ * String to be appended to each preserved comment
+ *
+ * @var string
+ */
+ public static $append = "\n";
+
+ /**
+ * Process a string outside of C-style comments that begin with "/*!"
+ *
+ * On each non-empty string outside these comments, the given processor
+ * function will be called. The first "!" will be removed from the
+ * preserved comments, and the comments will be surrounded by
+ * Minify_CommentPreserver::$preprend and Minify_CommentPreserver::$append.
+ *
+ * @param string $content
+ * @param callback $processor function
+ * @param array $args array of extra arguments to pass to the processor
+ * function (default = array())
+ * @return string
+ */
+ public static function process($content, $processor, $args = array())
+ {
+ $ret = '';
+ while (true) {
+ list($beforeComment, $comment, $afterComment) = self::_nextComment($content);
+ if ('' !== $beforeComment) {
+ $callArgs = $args;
+ array_unshift($callArgs, $beforeComment);
+ $ret .= call_user_func_array($processor, $callArgs);
+ }
+ if (false === $comment) {
+ break;
+ }
+ $ret .= $comment;
+ $content = $afterComment;
+ }
+ return $ret;
+ }
+
+ /**
+ * Extract comments that YUI Compressor preserves.
+ *
+ * @param string $in input
+ *
+ * @return array 3 elements are returned. If a YUI comment is found, the
+ * 2nd element is the comment and the 1st and 2nd are the surrounding
+ * strings. If no comment is found, the entire string is returned as the
+ * 1st element and the other two are false.
+ */
+ private static function _nextComment($in)
+ {
+ if (
+ false === ($start = strpos($in, '/*!'))
+ || false === ($end = strpos($in, '*/', $start + 3))
+ ) {
+ return array($in, false, false);
+ }
+ $ret = array(
+ substr($in, 0, $start)
+ ,self::$prepend . '/*' . substr($in, $start + 3, $end - $start - 1) . self::$append
+ );
+ $endChars = (strlen($in) - $end - 2);
+ $ret[] = (0 === $endChars)
+ ? ''
+ : substr($in, -$endChars);
+ return $ret;
+ }
+}
\ No newline at end of file
diff --git a/htdocs/application/libraries/jsmin.php b/htdocs/application/libraries/jsmin.php
new file mode 100644
index 0000000..620514f
--- /dev/null
+++ b/htdocs/application/libraries/jsmin.php
@@ -0,0 +1,309 @@
+
+ **/
+
+/**
+ * jsmin.php - PHP implementation of Douglas Crockford's JSMin.
+ *
+ * This is pretty much a direct port of jsmin.c to PHP with just a few
+ * PHP-specific performance tweaks. Also, whereas jsmin.c reads from stdin and
+ * outputs to stdout, this library accepts a string as input and returns another
+ * string as output.
+ *
+ * PHP 5 or higher is required.
+ *
+ * Permission is hereby granted to use this version of the library under the
+ * same terms as jsmin.c, which has the following license:
+ *
+ * --
+ * Copyright (c) 2002 Douglas Crockford (www.crockford.com)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * The Software shall be used for Good, not Evil.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ * --
+ *
+ * @package JSMin
+ * @author Ryan Grove
+ * @copyright 2002 Douglas Crockford (jsmin.c)
+ * @copyright 2008 Ryan Grove (PHP port)
+ * @copyright 2009 Tony Dewan (CodeIgniter port)
+ * @license http://opensource.org/licenses/mit-license.php MIT License
+ * @version 1.1.1 (2008-03-02)
+ * @link http://code.google.com/p/jsmin-php/
+ */
+
+class JSMin {
+ const ORD_LF = 10;
+ const ORD_SPACE = 32;
+
+ protected $a = '';
+ protected $b = '';
+ protected $input = '';
+ protected $inputIndex = 0;
+ protected $inputLength = 0;
+ protected $lookAhead = null;
+ protected $output = '';
+
+ // -- Public Static Methods --------------------------------------------------
+
+ public static function minify($js) {
+ $jsmin = new JSMin($js);
+ return $jsmin->min();
+ }
+
+ // -- Public Instance Methods ------------------------------------------------
+
+ public function __construct($input = '') {
+
+ log_message('debug', 'JSMin library initialized.');
+
+ $this->input = str_replace("\r\n", "\n", $input);
+ $this->inputLength = strlen($this->input);
+ }
+
+ // -- Protected Instance Methods ---------------------------------------------
+
+ protected function action($d) {
+ switch($d) {
+ case 1:
+ $this->output .= $this->a;
+
+ case 2:
+ $this->a = $this->b;
+
+ if ($this->a === "'" || $this->a === '"') {
+ for (;;) {
+ $this->output .= $this->a;
+ $this->a = $this->get();
+
+ if ($this->a === $this->b) {
+ break;
+ }
+
+ if (ord($this->a) <= self::ORD_LF) {
+ throw new JSMinException('Unterminated string literal.');
+ }
+
+ if ($this->a === '\\') {
+ $this->output .= $this->a;
+ $this->a = $this->get();
+ }
+ }
+ }
+
+ case 3:
+ $this->b = $this->next();
+
+ if ($this->b === '/' && (
+ $this->a === '(' || $this->a === ',' || $this->a === '=' ||
+ $this->a === ':' || $this->a === '[' || $this->a === '!' ||
+ $this->a === '&' || $this->a === '|' || $this->a === '?')) {
+
+ $this->output .= $this->a . $this->b;
+
+ for (;;) {
+ $this->a = $this->get();
+
+ if ($this->a === '/') {
+ break;
+ } elseif ($this->a === '\\') {
+ $this->output .= $this->a;
+ $this->a = $this->get();
+ } elseif (ord($this->a) <= self::ORD_LF) {
+ throw new JSMinException('Unterminated regular expression '.
+ 'literal.');
+ }
+
+ $this->output .= $this->a;
+ }
+
+ $this->b = $this->next();
+ }
+ }
+ }
+
+ protected function get() {
+ $c = $this->lookAhead;
+ $this->lookAhead = null;
+
+ if ($c === null) {
+ if ($this->inputIndex < $this->inputLength) {
+ $c = $this->input[$this->inputIndex];
+ $this->inputIndex += 1;
+ } else {
+ $c = null;
+ }
+ }
+
+ if ($c === "\r") {
+ return "\n";
+ }
+
+ if ($c === null || $c === "\n" || ord($c) >= self::ORD_SPACE) {
+ return $c;
+ }
+
+ return ' ';
+ }
+
+ protected function isAlphaNum($c) {
+ return ord($c) > 126 || $c === '\\' || preg_match('/^[\w\$]$/', $c) === 1;
+ }
+
+ protected function min() {
+
+ $this->a = "\n";
+ $this->action(3);
+
+ while ($this->a !== null) {
+ switch ($this->a) {
+ case ' ':
+ if ($this->isAlphaNum($this->b)) {
+ $this->action(1);
+ } else {
+ $this->action(2);
+ }
+ break;
+
+ case "\n":
+ switch ($this->b) {
+ case '{':
+ case '[':
+ case '(':
+ case '+':
+ case '-':
+ $this->action(1);
+ break;
+
+ case ' ':
+ $this->action(3);
+ break;
+
+ default:
+ if ($this->isAlphaNum($this->b)) {
+ $this->action(1);
+ }
+ else {
+ $this->action(2);
+ }
+ }
+ break;
+
+ default:
+ switch ($this->b) {
+ case ' ':
+ if ($this->isAlphaNum($this->a)) {
+ $this->action(1);
+ break;
+ }
+
+ $this->action(3);
+ break;
+
+ case "\n":
+ switch ($this->a) {
+ case '}':
+ case ']':
+ case ')':
+ case '+':
+ case '-':
+ case '"':
+ case "'":
+ $this->action(1);
+ break;
+
+ default:
+ if ($this->isAlphaNum($this->a)) {
+ $this->action(1);
+ }
+ else {
+ $this->action(3);
+ }
+ }
+ break;
+
+ default:
+ $this->action(1);
+ break;
+ }
+ }
+ }
+
+ return $this->output;
+ }
+
+ protected function next() {
+ $c = $this->get();
+
+ if ($c === '/') {
+ switch($this->peek()) {
+ case '/':
+ for (;;) {
+ $c = $this->get();
+
+ if (ord($c) <= self::ORD_LF) {
+ return $c;
+ }
+ }
+
+ case '*':
+ $this->get();
+
+ for (;;) {
+ switch($this->get()) {
+ case '*':
+ if ($this->peek() === '/') {
+ $this->get();
+ return ' ';
+ }
+ break;
+
+ case null:
+ throw new JSMinException('Unterminated comment.');
+ }
+ }
+
+ default:
+ return $c;
+ }
+ }
+
+ return $c;
+ }
+
+ protected function peek() {
+ $this->lookAhead = $this->get();
+ return $this->lookAhead;
+ }
+}
+
+// -- Exceptions ---------------------------------------------------------------
+class JSMinException extends Exception {}
+?>
\ No newline at end of file