Revert "Fix MSIE conditionals regex in minify output func"

This reverts commit 8e12c787042396e172a7448c65bd16c3015ffb0f.
diff --git a/system/core/Output.php b/system/core/Output.php
index b452639..ce0500e 100644
--- a/system/core/Output.php
+++ b/system/core/Output.php
@@ -1,922 +1,922 @@
-<?php

-/**

- * CodeIgniter

- *

- * An open source application development framework for PHP 5.2.4 or newer

- *

- * NOTICE OF LICENSE

- *

- * Licensed under the Open Software License version 3.0

- *

- * This source file is subject to the Open Software License (OSL 3.0) that is

- * bundled with this package in the files license.txt / license.rst.  It is

- * also available through the world wide web at this URL:

- * http://opensource.org/licenses/OSL-3.0

- * If you did not receive a copy of the license and are unable to obtain it

- * through the world wide web, please send an email to

- * licensing@ellislab.com so we can send you a copy immediately.

- *

- * @package		CodeIgniter

- * @author		EllisLab Dev Team

- * @copyright	Copyright (c) 2008 - 2013, EllisLab, Inc. (http://ellislab.com/)

- * @license		http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)

- * @link		http://codeigniter.com

- * @since		Version 1.0

- * @filesource

- */

-defined('BASEPATH') OR exit('No direct script access allowed');

-

-/**

- * Output Class

- *

- * Responsible for sending final output to the browser.

- *

- * @package		CodeIgniter

- * @subpackage	Libraries

- * @category	Output

- * @author		EllisLab Dev Team

- * @link		http://codeigniter.com/user_guide/libraries/output.html

- */

-class CI_Output {

-

-	/**

-	 * Final output string

-	 *

-	 * @var	string

-	 */

-	public $final_output;

-

-	/**

-	 * Cache expiration time

-	 *

-	 * @var	int

-	 */

-	public $cache_expiration = 0;

-

-	/**

-	 * List of server headers

-	 *

-	 * @var	array

-	 */

-	public $headers =	array();

-

-	/**

-	 * List of mime types

-	 *

-	 * @var	array

-	 */

-	public $mimes =		array();

-

-	/**

-	 * Mime-type for the current page

-	 *

-	 * @var	string

-	 */

-	protected $mime_type	= 'text/html';

-

-	/**

-	 * Enable Profiler flag

-	 *

-	 * @var	bool

-	 */

-	public $enable_profiler = FALSE;

-

-	/**

-	 * zLib output compression flag

-	 *

-	 * @var	bool

-	 */

-	protected $_zlib_oc =		FALSE;

-

-	/**

-	 * List of profiler sections

-	 *

-	 * @var	array

-	 */

-	protected $_profiler_sections =	array();

-

-	/**

-	 * Parse markers flag

-	 *

-	 * Whether or not to parse variables like {elapsed_time} and {memory_usage}.

-	 *

-	 * @var	bool

-	 */

-	public $parse_exec_vars =	TRUE;

-

-	/**

-	 * Class constructor

-	 *

-	 * Determines whether zLib output compression will be used.

-	 *

-	 * @return	void

-	 */

-	public function __construct()

-	{

-		$this->_zlib_oc = (bool) @ini_get('zlib.output_compression');

-

-		// Get mime types for later

-		$this->mimes =& get_mimes();

-

-		log_message('debug', 'Output Class Initialized');

-	}

-

-	// --------------------------------------------------------------------

-

-	/**

-	 * Get Output

-	 *

-	 * Returns the current output string.

-	 *

-	 * @return	string

-	 */

-	public function get_output()

-	{

-		return $this->final_output;

-	}

-

-	// --------------------------------------------------------------------

-

-	/**

-	 * Set Output

-	 *

-	 * Sets the output string.

-	 *

-	 * @param	string	$output	Output data

-	 * @return	CI_Output

-	 */

-	public function set_output($output)

-	{

-		$this->final_output = $output;

-		return $this;

-	}

-

-	// --------------------------------------------------------------------

-

-	/**

-	 * Append Output

-	 *

-	 * Appends data onto the output string.

-	 *

-	 * @param	string	$output	Data to append

-	 * @return	CI_Output

-	 */

-	public function append_output($output)

-	{

-		if (empty($this->final_output))

-		{

-			$this->final_output = $output;

-		}

-		else

-		{

-			$this->final_output .= $output;

-		}

-

-		return $this;

-	}

-

-	// --------------------------------------------------------------------

-

-	/**

-	 * Set Header

-	 *

-	 * Lets you set a server header which will be sent with the final output.

-	 *

-	 * Note: If a file is cached, headers will not be sent.

-	 * @todo	We need to figure out how to permit headers to be cached.

-	 *

-	 * @param	string	$header		Header

-	 * @param	bool	$replace	Whether to replace the old header value, if already set

-	 * @return	CI_Output

-	 */

-	public function set_header($header, $replace = TRUE)

-	{

-		// If zlib.output_compression is enabled it will compress the output,

-		// but it will not modify the content-length header to compensate for

-		// the reduction, causing the browser to hang waiting for more data.

-		// We'll just skip content-length in those cases.

-		if ($this->_zlib_oc && strncasecmp($header, 'content-length', 14) === 0)

-		{

-			return $this;

-		}

-

-		$this->headers[] = array($header, $replace);

-		return $this;

-	}

-

-	// --------------------------------------------------------------------

-

-	/**

-	 * Set Content-Type Header

-	 *

-	 * @param	string	$mime_type	Extension of the file we're outputting

-	 * @param	string	$charset	Character set (default: NULL)

-	 * @return	CI_Output

-	 */

-	public function set_content_type($mime_type, $charset = NULL)

-	{

-		if (strpos($mime_type, '/') === FALSE)

-		{

-			$extension = ltrim($mime_type, '.');

-

-			// Is this extension supported?

-			if (isset($this->mimes[$extension]))

-			{

-				$mime_type =& $this->mimes[$extension];

-

-				if (is_array($mime_type))

-				{

-					$mime_type = current($mime_type);

-				}

-			}

-		}

-

-		$this->mime_type = $mime_type;

-

-		if (empty($charset))

-		{

-			$charset = config_item('charset');

-		}

-

-		$header = 'Content-Type: '.$mime_type

-			.(empty($charset) ? NULL : '; charset='.$charset);

-

-		$this->headers[] = array($header, TRUE);

-		return $this;

-	}

-

-	// --------------------------------------------------------------------

-

-	/**

-	 * Get Current Content-Type Header

-	 *

-	 * @return	string	'text/html', if not already set

-	 */

-	public function get_content_type()

-	{

-		for ($i = 0, $c = count($this->headers); $i < $c; $i++)

-		{

-			if (sscanf($this->headers[$i][0], 'Content-Type: %[^;]', $content_type) === 1)

-			{

-				return $content_type;

-			}

-		}

-

-		return 'text/html';

-	}

-

-	// --------------------------------------------------------------------

-

-	/**

-	 * Get Header

-	 *

-	 * @param	string	$header_name

-	 * @return	string

-	 */

-	public function get_header($header)

-	{

-		// Combine headers already sent with our batched headers

-		$headers = array_merge(

-			// We only need [x][0] from our multi-dimensional array

-			array_map('array_shift', $this->headers),

-			headers_list()

-		);

-

-		if (empty($headers) OR empty($header))

-		{

-			return NULL;

-		}

-

-		for ($i = 0, $c = count($headers); $i < $c; $i++)

-		{

-			if (strncasecmp($header, $headers[$i], $l = strlen($header)) === 0)

-			{

-				return trim(substr($headers[$i], $l+1));

-			}

-		}

-

-		return NULL;

-	}

-

-	// --------------------------------------------------------------------

-

-	/**

-	 * Set HTTP Status Header

-	 *

-	 * As of version 1.7.2, this is an alias for common function

-	 * set_status_header().

-	 *

-	 * @param	int	$code	Status code (default: 200)

-	 * @param	string	$text	Optional message

-	 * @return	CI_Output

-	 */

-	public function set_status_header($code = 200, $text = '')

-	{

-		set_status_header($code, $text);

-		return $this;

-	}

-

-	// --------------------------------------------------------------------

-

-	/**

-	 * Enable/disable Profiler

-	 *

-	 * @param	bool	$val	TRUE to enable or FALSE to disable

-	 * @return	CI_Output

-	 */

-	public function enable_profiler($val = TRUE)

-	{

-		$this->enable_profiler = is_bool($val) ? $val : TRUE;

-		return $this;

-	}

-

-	// --------------------------------------------------------------------

-

-	/**

-	 * Set Profiler Sections

-	 *

-	 * Allows override of default/config settings for

-	 * Profiler section display.

-	 *

-	 * @param	array	$sections	Profiler sections

-	 * @return	CI_Output

-	 */

-	public function set_profiler_sections($sections)

-	{

-		if (isset($sections['query_toggle_count']))

-		{

-			$this->_profiler_sections['query_toggle_count'] = (int) $sections['query_toggle_count'];

-			unset($sections['query_toggle_count']);

-		}

-

-		foreach ($sections as $section => $enable)

-		{

-			$this->_profiler_sections[$section] = ($enable !== FALSE);

-		}

-

-		return $this;

-	}

-

-	// --------------------------------------------------------------------

-

-	/**

-	 * Set Cache

-	 *

-	 * @param	int	$time	Cache expiration time in seconds

-	 * @return	CI_Output

-	 */

-	public function cache($time)

-	{

-		$this->cache_expiration = is_numeric($time) ? $time : 0;

-		return $this;

-	}

-

-	// --------------------------------------------------------------------

-

-	/**

-	 * Display Output

-	 *

-	 * Processes sends the sends finalized output data to the browser along

-	 * with any server headers and profile data. It also stops benchmark

-	 * timers so the page rendering speed and memory usage can be shown.

-	 *

-	 * Note: All "view" data is automatically put into $this->final_output

-	 *	 by controller class.

-	 *

-	 * @uses	CI_Output::$final_output

-	 * @param	string	$output	Output data override

-	 * @return	void

-	 */

-	public function _display($output = '')

-	{

-		// Note:  We use globals because we can't use $CI =& get_instance()

-		// since this function is sometimes called by the caching mechanism,

-		// which happens before the CI super object is available.

-		global $BM, $CFG;

-

-		// Grab the super object if we can.

-		if (class_exists('CI_Controller'))

-		{

-			$CI =& get_instance();

-		}

-

-		// --------------------------------------------------------------------

-

-		// Set the output data

-		if ($output === '')

-		{

-			$output =& $this->final_output;

-		}

-

-		// --------------------------------------------------------------------

-

-		// Is minify requested?

-		if ($CFG->item('minify_output') === TRUE)

-		{

-			$output = $this->minify($output, $this->mime_type);

-		}

-

-		// --------------------------------------------------------------------

-

-		// Do we need to write a cache file? Only if the controller does not have its

-		// own _output() method and we are not dealing with a cache file, which we

-		// can determine by the existence of the $CI object above

-		if ($this->cache_expiration > 0 && isset($CI) && ! method_exists($CI, '_output'))

-		{

-			$this->_write_cache($output);

-		}

-

-		// --------------------------------------------------------------------

-

-		// Parse out the elapsed time and memory usage,

-		// then swap the pseudo-variables with the data

-

-		$elapsed = $BM->elapsed_time('total_execution_time_start', 'total_execution_time_end');

-

-		if ($this->parse_exec_vars === TRUE)

-		{

-			$memory	= round(memory_get_usage() / 1024 / 1024, 2).'MB';

-

-			$output = str_replace(array('{elapsed_time}', '{memory_usage}'), array($elapsed, $memory), $output);

-		}

-

-		// --------------------------------------------------------------------

-

-		// Is compression requested?

-		if ($CFG->item('compress_output') === TRUE && $this->_zlib_oc === FALSE

-			&& extension_loaded('zlib')

-			&& isset($_SERVER['HTTP_ACCEPT_ENCODING']) && strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== FALSE)

-		{

-			ob_start('ob_gzhandler');

-		}

-

-		// --------------------------------------------------------------------

-

-		// Are there any server headers to send?

-		if (count($this->headers) > 0)

-		{

-			foreach ($this->headers as $header)

-			{

-				@header($header[0], $header[1]);

-			}

-		}

-

-		// --------------------------------------------------------------------

-

-		// Does the $CI object exist?

-		// If not we know we are dealing with a cache file so we'll

-		// simply echo out the data and exit.

-		if ( ! isset($CI))

-		{

-			echo $output;

-			log_message('debug', 'Final output sent to browser');

-			log_message('debug', 'Total execution time: '.$elapsed);

-			return;

-		}

-

-		// --------------------------------------------------------------------

-

-		// Do we need to generate profile data?

-		// If so, load the Profile class and run it.

-		if ($this->enable_profiler === TRUE)

-		{

-			$CI->load->library('profiler');

-			if ( ! empty($this->_profiler_sections))

-			{

-				$CI->profiler->set_sections($this->_profiler_sections);

-			}

-

-			// If the output data contains closing </body> and </html> tags

-			// we will remove them and add them back after we insert the profile data

-			$output = preg_replace('|</body>.*?</html>|is', '', $output, -1, $count).$CI->profiler->run();

-			if ($count > 0)

-			{

-				$output .= '</body></html>';

-			}

-		}

-

-		// Does the controller contain a function named _output()?

-		// If so send the output there.  Otherwise, echo it.

-		if (method_exists($CI, '_output'))

-		{

-			$CI->_output($output);

-		}

-		else

-		{

-			echo $output; // Send it to the browser!

-		}

-

-		log_message('debug', 'Final output sent to browser');

-		log_message('debug', 'Total execution time: '.$elapsed);

-	}

-

-	// --------------------------------------------------------------------

-

-	/**

-	 * Write Cache

-	 *

-	 * @param	string	$output	Output data to cache

-	 * @return	void

-	 */

-	public function _write_cache($output)

-	{

-		$CI =& get_instance();

-		$path = $CI->config->item('cache_path');

-		$cache_path = ($path === '') ? APPPATH.'cache/' : $path;

-

-		if ( ! is_dir($cache_path) OR ! is_really_writable($cache_path))

-		{

-			log_message('error', 'Unable to write cache file: '.$cache_path);

-			return;

-		}

-

-		$uri =	$CI->config->item('base_url').

-				$CI->config->item('index_page').

-				$CI->uri->uri_string();

-

-		$cache_path .= md5($uri);

-

-		if ( ! $fp = @fopen($cache_path, FOPEN_WRITE_CREATE_DESTRUCTIVE))

-		{

-			log_message('error', 'Unable to write cache file: '.$cache_path);

-			return;

-		}

-

-		$expire = time() + ($this->cache_expiration * 60);

-

-		if (flock($fp, LOCK_EX))

-		{

-			fwrite($fp, $expire.'TS--->'.$output);

-			flock($fp, LOCK_UN);

-		}

-		else

-		{

-			log_message('error', 'Unable to secure a file lock for file at: '.$cache_path);

-			return;

-		}

-		fclose($fp);

-		@chmod($cache_path, FILE_WRITE_MODE);

-

-		log_message('debug', 'Cache file written: '.$cache_path);

-

-		// Send HTTP cache-control headers to browser to match file cache settings.

-		$this->set_cache_header($_SERVER['REQUEST_TIME'], $expire);

-	}

-

-	// --------------------------------------------------------------------

-

-	/**

-	 * Update/serve cached output

-	 *

-	 * @uses	CI_Config

-	 * @uses	CI_URI

-	 *

-	 * @param	object	&$CFG	CI_Config class instance

-	 * @param	object	&$URI	CI_URI class instance

-	 * @return	bool	TRUE on success or FALSE on failure

-	 */

-	public function _display_cache(&$CFG, &$URI)

-	{

-		$cache_path = ($CFG->item('cache_path') === '') ? APPPATH.'cache/' : $CFG->item('cache_path');

-

-		// Build the file path. The file name is an MD5 hash of the full URI

-		$uri =	$CFG->item('base_url').$CFG->item('index_page').$URI->uri_string;

-		$filepath = $cache_path.md5($uri);

-

-		if ( ! @file_exists($filepath) OR ! $fp = @fopen($filepath, FOPEN_READ))

-		{

-			return FALSE;

-		}

-

-		flock($fp, LOCK_SH);

-

-		$cache = (filesize($filepath) > 0) ? fread($fp, filesize($filepath)) : '';

-

-		flock($fp, LOCK_UN);

-		fclose($fp);

-

-		// Strip out the embedded timestamp

-		if ( ! preg_match('/^(\d+)TS--->/', $cache, $match))

-		{

-			return FALSE;

-		}

-

-		$last_modified = filemtime($cache_path);

-		$expire = $match[1];

-

-		// Has the file expired?

-		if ($_SERVER['REQUEST_TIME'] >= $expire && is_really_writable($cache_path))

-		{

-			// If so we'll delete it.

-			@unlink($filepath);

-			log_message('debug', 'Cache file has expired. File deleted.');

-			return FALSE;

-		}

-		else

-		{

-			// Or else send the HTTP cache control headers.

-			$this->set_cache_header($last_modified, $expire);

-		}

-

-		// Display the cache

-		$this->_display(substr($cache, strlen($match[0])));

-		log_message('debug', 'Cache file is current. Sending it to browser.');

-		return TRUE;

-	}

-

-	// --------------------------------------------------------------------

-

-	/**

-	 * Delete cache

-	 *

-	 * @param	string	$uri	URI string

-	 * @return	bool

-	 */

-	public function delete_cache($uri = '')

-	{

-		$CI =& get_instance();

-		$cache_path = $CI->config->item('cache_path');

-		if ($cache_path === '')

-		{

-			$cache_path = APPPATH.'cache/';

-		}

-

-		if ( ! is_dir($cache_path))

-		{

-			log_message('error', 'Unable to find cache path: '.$cache_path);

-			return FALSE;

-		}

-

-		if (empty($uri))

-		{

-			$uri = $CI->uri->uri_string();

-		}

-

-		$cache_path .= md5($CI->config->item('base_url').$CI->config->item('index_page').$uri);

-

-		if ( ! @unlink($cache_path))

-		{

-			log_message('error', 'Unable to delete cache file for '.$uri);

-			return FALSE;

-		}

-

-		return TRUE;

-	}

-

-	// --------------------------------------------------------------------

-

-	/**

-	 * Set Cache Header

-	 *

-	 * Set the HTTP headers to match the server-side file cache settings

-	 * in order to reduce bandwidth.

-	 *

-	 * @param	int	$last_modified	Timestamp of when the page was last modified

-	 * @param	int	$expiration	Timestamp of when should the requested page expire from cache

-	 * @return	void

-	 */

-	public function set_cache_header($last_modified, $expiration)

-	{

-		$max_age = $expiration - $_SERVER['REQUEST_TIME'];

-

-		if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && $last_modified <= strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']))

-		{

-			$this->set_status_header(304);

-			exit;

-		}

-		else

-		{

-			header('Pragma: public');

-			header('Cache-Control: max-age=' . $max_age . ', public');

-			header('Expires: '.gmdate('D, d M Y H:i:s', $expiration).' GMT');

-			header('Last-modified: '.gmdate('D, d M Y H:i:s', $last_modified).' GMT');

-		}

-	}

-

-	// --------------------------------------------------------------------

-

-	/**

-	 * Minify

-	 *

-	 * Reduce excessive size of HTML/CSS/JavaScript content.

-	 *

-	 * @param	string	$output	Output to minify

-	 * @param	string	$type	Output content MIME type

-	 * @return	string	Minified output

-	 */

-	public function minify($output, $type = 'text/html')

-	{

-		switch ($type)

-		{

-			case 'text/html':

-

-				if (($size_before = strlen($output)) === 0)

-				{

-					return '';

-				}

-

-				// Find all the <pre>,<code>,<textarea>, and <javascript> tags

-				// We'll want to return them to this unprocessed state later.

-				preg_match_all('{<pre.+</pre>}msU', $output, $pres_clean);

-				preg_match_all('{<code.+</code>}msU', $output, $codes_clean);

-				preg_match_all('{<textarea.+</textarea>}msU', $output, $textareas_clean);

-				preg_match_all('{<script.+</script>}msU', $output, $javascript_clean);

-

-				// Minify the CSS in all the <style> tags.

-				preg_match_all('{<style.+</style>}msU', $output, $style_clean);

-				foreach ($style_clean[0] as $s)

-				{

-					$output = str_replace($s, $this->_minify_script_style($s, TRUE), $output);

-				}

-

-				// Minify the javascript in <script> tags.

-				foreach ($javascript_clean[0] as $s)

-				{

-					$javascript_mini[] = $this->_minify_script_style($s, TRUE);

-				}

-

-				// Replace multiple spaces with a single space.

-				$output = preg_replace('!\s{2,}!', ' ', $output);

-

-				// Remove comments (non-MSIE conditionals)

-				$output = preg_replace('{\s*<!--[^\[<>].*(?<!!)-->\s*}msU', '', $output);

-

-				// Remove spaces around block-level elements.

-				$output = preg_replace('/\s*(<\/?(html|head|title|meta|script|link|style|body|h[1-6]|div|p|br)[^>]*>)\s*/is', '$1', $output);

-

-				// Replace mangled <pre> etc. tags with unprocessed ones.

-

-				if ( ! empty($pres_clean))

-				{

-					preg_match_all('{<pre.+</pre>}msU', $output, $pres_messed);

-					$output = str_replace($pres_messed[0], $pres_clean[0], $output);

-				}

-

-				if ( ! empty($codes_clean))

-				{

-					preg_match_all('{<code.+</code>}msU', $output, $codes_messed);

-					$output = str_replace($codes_messed[0], $codes_clean[0], $output);

-				}

-

-				if ( ! empty($codes_clean))

-				{

-					preg_match_all('{<textarea.+</textarea>}msU', $output, $textareas_messed);

-					$output = str_replace($textareas_messed[0], $textareas_clean[0], $output);

-				}

-

-				if (isset($javascript_mini))

-				{

-					preg_match_all('{<script.+</script>}msU', $output, $javascript_messed);

-					$output = str_replace($javascript_messed[0], $javascript_mini, $output);

-				}

-

-				$size_removed = $size_before - strlen($output);

-				$savings_percent = round(($size_removed / $size_before * 100));

-

-				log_message('debug', 'Minifier shaved '.($size_removed / 1000).'KB ('.$savings_percent.'%) off final HTML output.');

-

-			break;

-

-			case 'text/css':

-			case 'text/javascript':

-

-				$output = $this->_minify_script_style($output);

-

-			break;

-

-			default: break;

-		}

-

-		return $output;

-	}

-

-	// --------------------------------------------------------------------

-

-	/**

-	 * Minify Style and Script

-	 *

-	 * Reduce excessive size of CSS/JavaScript content.  To remove spaces this

-	 * script walks the string as an array and determines if the pointer is inside

-	 * a string created by single quotes or double quotes.  spaces inside those

-	 * strings are not stripped.  Opening and closing tags are severed from

-	 * the string initially and saved without stripping whitespace to preserve

-	 * the tags and any associated properties if tags are present

-	 *

-	 * Minification logic/workflow is similar to methods used by Douglas Crockford

-	 * in JSMIN. http://www.crockford.com/javascript/jsmin.html

-	 *

-	 * KNOWN ISSUE: ending a line with a closing parenthesis ')' and no semicolon

-	 * where there should be one will break the Javascript. New lines after a

-	 * closing parenthesis are not recognized by the script. For best results

-	 * be sure to terminate lines with a semicolon when appropriate.

-	 *

-	 * @param	string	$output		Output to minify

-	 * @param	bool	$has_tags	Specify if the output has style or script tags

-	 * @return	string	Minified output

-	 */

-	protected function _minify_script_style($output, $has_tags = FALSE)

-	{

-		// We only need this if there are tags in the file

-		if ($has_tags === TRUE)

-		{

-			// Remove opening tag and save for later

-			$pos = strpos($output, '>') + 1;

-			$open_tag = substr($output, 0, $pos);

-			$output = substr_replace($output, '', 0, $pos);

-

-			// Remove closing tag and save it for later

-			$end_pos = strlen($output);

-			$pos = strpos($output, '</');

-			$closing_tag = substr($output, $pos, $end_pos);

-			$output = substr_replace($output, '', $pos);

-		}

-

-		// Remove CSS comments

-		$output = preg_replace('!/\*[^*]*\*+([^/][^*]*\*+)*/!i', '', $output);

-

-		// Remove spaces around curly brackets, colons,

-		// semi-colons, parenthesis, commas

-		$output = preg_replace('!\s*(:|;|,|}|{|\(|\))\s*!i', '$1', $output);

-

-		// Replace tabs with spaces

-		// Replace carriage returns & multiple new lines with single new line

-		// and trim any leading or trailing whitespace

-		$output = trim(preg_replace(array('/\t+/', '/\r/', '/\n+/'), array(' ', "\n", "\n"), $output));

-

-		// Remove spaces when safe to do so.

-		$in_string = $in_dstring = $prev = FALSE;

-		$array_output = str_split($output);

-		foreach ($array_output as $key => $value)

-		{

-			if ($in_string === FALSE && $in_dstring === FALSE)

-			{

-				if ($value === ' ')

-				{

-					// Get the next element in the array for comparisons

-					$next = $array_output[$key + 1];

-

-					// Strip spaces preceded/followed by a non-ASCII character

-					// or not preceded/followed by an alphanumeric

-					// or not preceded/followed \ $ and _

-					if ((preg_match('/^[\x20-\x7f]*$/D', $next) OR preg_match('/^[\x20-\x7f]*$/D', $prev))

-						&& ( ! ctype_alnum($next) OR ! ctype_alnum($prev))

-						&& ! in_array($next, array('\\', '_', '$'), TRUE)

-						&& ! in_array($prev, array('\\', '_', '$'), TRUE)

-					)

-					{

-						unset($array_output[$key]);

-					}

-				}

-				else

-				{

-					// Save this value as previous for the next iteration

-					// if it is not a blank space

-					$prev = $value;

-				}

-			}

-

-			if ($value === "'")

-			{

-				$in_string = ! $in_string;

-			}

-			elseif ($value === '"')

-			{

-				$in_dstring = ! $in_dstring;

-			}

-		}

-

-		// Put the string back together after spaces have been stripped

-		$output = implode($array_output);

-

-		// Remove new line characters unless previous or next character is

-		// printable or Non-ASCII

-		preg_match_all('/[\n]/', $output, $lf, PREG_OFFSET_CAPTURE);

-		$removed_lf = 0;

-		foreach ($lf as $feed_position)

-		{

-			foreach ($feed_position as $position)

-			{

-				$position = $position[1] - $removed_lf;

-				$next = $output[$position + 1];

-				$prev = $output[$position - 1];

-				if ( ! ctype_print($next) && ! ctype_print($prev)

-					&& ! preg_match('/^[\x20-\x7f]*$/D', $next)

-					&& ! preg_match('/^[\x20-\x7f]*$/D', $prev)

-				)

-				{

-					$output = substr_replace($output, '', $position, 1);

-					$removed_lf++;

-				}

-			}

-		}

-

-		// Put the opening and closing tags back if applicable

-		return isset($open_tag)

-			? $open_tag.$output.$closing_tag

-			: $output;

-	}

-

-}

-

-/* End of file Output.php */

+<?php
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.2.4 or newer
+ *
+ * NOTICE OF LICENSE
+ *
+ * Licensed under the Open Software License version 3.0
+ *
+ * This source file is subject to the Open Software License (OSL 3.0) that is
+ * bundled with this package in the files license.txt / license.rst.  It is
+ * also available through the world wide web at this URL:
+ * http://opensource.org/licenses/OSL-3.0
+ * If you did not receive a copy of the license and are unable to obtain it
+ * through the world wide web, please send an email to
+ * licensing@ellislab.com so we can send you a copy immediately.
+ *
+ * @package		CodeIgniter
+ * @author		EllisLab Dev Team
+ * @copyright	Copyright (c) 2008 - 2013, EllisLab, Inc. (http://ellislab.com/)
+ * @license		http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
+ * @link		http://codeigniter.com
+ * @since		Version 1.0
+ * @filesource
+ */
+defined('BASEPATH') OR exit('No direct script access allowed');
+
+/**
+ * Output Class
+ *
+ * Responsible for sending final output to the browser.
+ *
+ * @package		CodeIgniter
+ * @subpackage	Libraries
+ * @category	Output
+ * @author		EllisLab Dev Team
+ * @link		http://codeigniter.com/user_guide/libraries/output.html
+ */
+class CI_Output {
+
+	/**
+	 * Final output string
+	 *
+	 * @var	string
+	 */
+	public $final_output;
+
+	/**
+	 * Cache expiration time
+	 *
+	 * @var	int
+	 */
+	public $cache_expiration = 0;
+
+	/**
+	 * List of server headers
+	 *
+	 * @var	array
+	 */
+	public $headers =	array();
+
+	/**
+	 * List of mime types
+	 *
+	 * @var	array
+	 */
+	public $mimes =		array();
+
+	/**
+	 * Mime-type for the current page
+	 *
+	 * @var	string
+	 */
+	protected $mime_type	= 'text/html';
+
+	/**
+	 * Enable Profiler flag
+	 *
+	 * @var	bool
+	 */
+	public $enable_profiler = FALSE;
+
+	/**
+	 * zLib output compression flag
+	 *
+	 * @var	bool
+	 */
+	protected $_zlib_oc =		FALSE;
+
+	/**
+	 * List of profiler sections
+	 *
+	 * @var	array
+	 */
+	protected $_profiler_sections =	array();
+
+	/**
+	 * Parse markers flag
+	 *
+	 * Whether or not to parse variables like {elapsed_time} and {memory_usage}.
+	 *
+	 * @var	bool
+	 */
+	public $parse_exec_vars =	TRUE;
+
+	/**
+	 * Class constructor
+	 *
+	 * Determines whether zLib output compression will be used.
+	 *
+	 * @return	void
+	 */
+	public function __construct()
+	{
+		$this->_zlib_oc = (bool) @ini_get('zlib.output_compression');
+
+		// Get mime types for later
+		$this->mimes =& get_mimes();
+
+		log_message('debug', 'Output Class Initialized');
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Get Output
+	 *
+	 * Returns the current output string.
+	 *
+	 * @return	string
+	 */
+	public function get_output()
+	{
+		return $this->final_output;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Set Output
+	 *
+	 * Sets the output string.
+	 *
+	 * @param	string	$output	Output data
+	 * @return	CI_Output
+	 */
+	public function set_output($output)
+	{
+		$this->final_output = $output;
+		return $this;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Append Output
+	 *
+	 * Appends data onto the output string.
+	 *
+	 * @param	string	$output	Data to append
+	 * @return	CI_Output
+	 */
+	public function append_output($output)
+	{
+		if (empty($this->final_output))
+		{
+			$this->final_output = $output;
+		}
+		else
+		{
+			$this->final_output .= $output;
+		}
+
+		return $this;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Set Header
+	 *
+	 * Lets you set a server header which will be sent with the final output.
+	 *
+	 * Note: If a file is cached, headers will not be sent.
+	 * @todo	We need to figure out how to permit headers to be cached.
+	 *
+	 * @param	string	$header		Header
+	 * @param	bool	$replace	Whether to replace the old header value, if already set
+	 * @return	CI_Output
+	 */
+	public function set_header($header, $replace = TRUE)
+	{
+		// If zlib.output_compression is enabled it will compress the output,
+		// but it will not modify the content-length header to compensate for
+		// the reduction, causing the browser to hang waiting for more data.
+		// We'll just skip content-length in those cases.
+		if ($this->_zlib_oc && strncasecmp($header, 'content-length', 14) === 0)
+		{
+			return $this;
+		}
+
+		$this->headers[] = array($header, $replace);
+		return $this;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Set Content-Type Header
+	 *
+	 * @param	string	$mime_type	Extension of the file we're outputting
+	 * @param	string	$charset	Character set (default: NULL)
+	 * @return	CI_Output
+	 */
+	public function set_content_type($mime_type, $charset = NULL)
+	{
+		if (strpos($mime_type, '/') === FALSE)
+		{
+			$extension = ltrim($mime_type, '.');
+
+			// Is this extension supported?
+			if (isset($this->mimes[$extension]))
+			{
+				$mime_type =& $this->mimes[$extension];
+
+				if (is_array($mime_type))
+				{
+					$mime_type = current($mime_type);
+				}
+			}
+		}
+
+		$this->mime_type = $mime_type;
+
+		if (empty($charset))
+		{
+			$charset = config_item('charset');
+		}
+
+		$header = 'Content-Type: '.$mime_type
+			.(empty($charset) ? NULL : '; charset='.$charset);
+
+		$this->headers[] = array($header, TRUE);
+		return $this;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Get Current Content-Type Header
+	 *
+	 * @return	string	'text/html', if not already set
+	 */
+	public function get_content_type()
+	{
+		for ($i = 0, $c = count($this->headers); $i < $c; $i++)
+		{
+			if (sscanf($this->headers[$i][0], 'Content-Type: %[^;]', $content_type) === 1)
+			{
+				return $content_type;
+			}
+		}
+
+		return 'text/html';
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Get Header
+	 *
+	 * @param	string	$header_name
+	 * @return	string
+	 */
+	public function get_header($header)
+	{
+		// Combine headers already sent with our batched headers
+		$headers = array_merge(
+			// We only need [x][0] from our multi-dimensional array
+			array_map('array_shift', $this->headers),
+			headers_list()
+		);
+
+		if (empty($headers) OR empty($header))
+		{
+			return NULL;
+		}
+
+		for ($i = 0, $c = count($headers); $i < $c; $i++)
+		{
+			if (strncasecmp($header, $headers[$i], $l = strlen($header)) === 0)
+			{
+				return trim(substr($headers[$i], $l+1));
+			}
+		}
+
+		return NULL;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Set HTTP Status Header
+	 *
+	 * As of version 1.7.2, this is an alias for common function
+	 * set_status_header().
+	 *
+	 * @param	int	$code	Status code (default: 200)
+	 * @param	string	$text	Optional message
+	 * @return	CI_Output
+	 */
+	public function set_status_header($code = 200, $text = '')
+	{
+		set_status_header($code, $text);
+		return $this;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Enable/disable Profiler
+	 *
+	 * @param	bool	$val	TRUE to enable or FALSE to disable
+	 * @return	CI_Output
+	 */
+	public function enable_profiler($val = TRUE)
+	{
+		$this->enable_profiler = is_bool($val) ? $val : TRUE;
+		return $this;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Set Profiler Sections
+	 *
+	 * Allows override of default/config settings for
+	 * Profiler section display.
+	 *
+	 * @param	array	$sections	Profiler sections
+	 * @return	CI_Output
+	 */
+	public function set_profiler_sections($sections)
+	{
+		if (isset($sections['query_toggle_count']))
+		{
+			$this->_profiler_sections['query_toggle_count'] = (int) $sections['query_toggle_count'];
+			unset($sections['query_toggle_count']);
+		}
+
+		foreach ($sections as $section => $enable)
+		{
+			$this->_profiler_sections[$section] = ($enable !== FALSE);
+		}
+
+		return $this;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Set Cache
+	 *
+	 * @param	int	$time	Cache expiration time in seconds
+	 * @return	CI_Output
+	 */
+	public function cache($time)
+	{
+		$this->cache_expiration = is_numeric($time) ? $time : 0;
+		return $this;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Display Output
+	 *
+	 * Processes sends the sends finalized output data to the browser along
+	 * with any server headers and profile data. It also stops benchmark
+	 * timers so the page rendering speed and memory usage can be shown.
+	 *
+	 * Note: All "view" data is automatically put into $this->final_output
+	 *	 by controller class.
+	 *
+	 * @uses	CI_Output::$final_output
+	 * @param	string	$output	Output data override
+	 * @return	void
+	 */
+	public function _display($output = '')
+	{
+		// Note:  We use globals because we can't use $CI =& get_instance()
+		// since this function is sometimes called by the caching mechanism,
+		// which happens before the CI super object is available.
+		global $BM, $CFG;
+
+		// Grab the super object if we can.
+		if (class_exists('CI_Controller'))
+		{
+			$CI =& get_instance();
+		}
+
+		// --------------------------------------------------------------------
+
+		// Set the output data
+		if ($output === '')
+		{
+			$output =& $this->final_output;
+		}
+
+		// --------------------------------------------------------------------
+
+		// Is minify requested?
+		if ($CFG->item('minify_output') === TRUE)
+		{
+			$output = $this->minify($output, $this->mime_type);
+		}
+
+		// --------------------------------------------------------------------
+
+		// Do we need to write a cache file? Only if the controller does not have its
+		// own _output() method and we are not dealing with a cache file, which we
+		// can determine by the existence of the $CI object above
+		if ($this->cache_expiration > 0 && isset($CI) && ! method_exists($CI, '_output'))
+		{
+			$this->_write_cache($output);
+		}
+
+		// --------------------------------------------------------------------
+
+		// Parse out the elapsed time and memory usage,
+		// then swap the pseudo-variables with the data
+
+		$elapsed = $BM->elapsed_time('total_execution_time_start', 'total_execution_time_end');
+
+		if ($this->parse_exec_vars === TRUE)
+		{
+			$memory	= round(memory_get_usage() / 1024 / 1024, 2).'MB';
+
+			$output = str_replace(array('{elapsed_time}', '{memory_usage}'), array($elapsed, $memory), $output);
+		}
+
+		// --------------------------------------------------------------------
+
+		// Is compression requested?
+		if ($CFG->item('compress_output') === TRUE && $this->_zlib_oc === FALSE
+			&& extension_loaded('zlib')
+			&& isset($_SERVER['HTTP_ACCEPT_ENCODING']) && strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== FALSE)
+		{
+			ob_start('ob_gzhandler');
+		}
+
+		// --------------------------------------------------------------------
+
+		// Are there any server headers to send?
+		if (count($this->headers) > 0)
+		{
+			foreach ($this->headers as $header)
+			{
+				@header($header[0], $header[1]);
+			}
+		}
+
+		// --------------------------------------------------------------------
+
+		// Does the $CI object exist?
+		// If not we know we are dealing with a cache file so we'll
+		// simply echo out the data and exit.
+		if ( ! isset($CI))
+		{
+			echo $output;
+			log_message('debug', 'Final output sent to browser');
+			log_message('debug', 'Total execution time: '.$elapsed);
+			return;
+		}
+
+		// --------------------------------------------------------------------
+
+		// Do we need to generate profile data?
+		// If so, load the Profile class and run it.
+		if ($this->enable_profiler === TRUE)
+		{
+			$CI->load->library('profiler');
+			if ( ! empty($this->_profiler_sections))
+			{
+				$CI->profiler->set_sections($this->_profiler_sections);
+			}
+
+			// If the output data contains closing </body> and </html> tags
+			// we will remove them and add them back after we insert the profile data
+			$output = preg_replace('|</body>.*?</html>|is', '', $output, -1, $count).$CI->profiler->run();
+			if ($count > 0)
+			{
+				$output .= '</body></html>';
+			}
+		}
+
+		// Does the controller contain a function named _output()?
+		// If so send the output there.  Otherwise, echo it.
+		if (method_exists($CI, '_output'))
+		{
+			$CI->_output($output);
+		}
+		else
+		{
+			echo $output; // Send it to the browser!
+		}
+
+		log_message('debug', 'Final output sent to browser');
+		log_message('debug', 'Total execution time: '.$elapsed);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Write Cache
+	 *
+	 * @param	string	$output	Output data to cache
+	 * @return	void
+	 */
+	public function _write_cache($output)
+	{
+		$CI =& get_instance();
+		$path = $CI->config->item('cache_path');
+		$cache_path = ($path === '') ? APPPATH.'cache/' : $path;
+
+		if ( ! is_dir($cache_path) OR ! is_really_writable($cache_path))
+		{
+			log_message('error', 'Unable to write cache file: '.$cache_path);
+			return;
+		}
+
+		$uri =	$CI->config->item('base_url').
+				$CI->config->item('index_page').
+				$CI->uri->uri_string();
+
+		$cache_path .= md5($uri);
+
+		if ( ! $fp = @fopen($cache_path, FOPEN_WRITE_CREATE_DESTRUCTIVE))
+		{
+			log_message('error', 'Unable to write cache file: '.$cache_path);
+			return;
+		}
+
+		$expire = time() + ($this->cache_expiration * 60);
+
+		if (flock($fp, LOCK_EX))
+		{
+			fwrite($fp, $expire.'TS--->'.$output);
+			flock($fp, LOCK_UN);
+		}
+		else
+		{
+			log_message('error', 'Unable to secure a file lock for file at: '.$cache_path);
+			return;
+		}
+		fclose($fp);
+		@chmod($cache_path, FILE_WRITE_MODE);
+
+		log_message('debug', 'Cache file written: '.$cache_path);
+
+		// Send HTTP cache-control headers to browser to match file cache settings.
+		$this->set_cache_header($_SERVER['REQUEST_TIME'], $expire);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Update/serve cached output
+	 *
+	 * @uses	CI_Config
+	 * @uses	CI_URI
+	 *
+	 * @param	object	&$CFG	CI_Config class instance
+	 * @param	object	&$URI	CI_URI class instance
+	 * @return	bool	TRUE on success or FALSE on failure
+	 */
+	public function _display_cache(&$CFG, &$URI)
+	{
+		$cache_path = ($CFG->item('cache_path') === '') ? APPPATH.'cache/' : $CFG->item('cache_path');
+
+		// Build the file path. The file name is an MD5 hash of the full URI
+		$uri =	$CFG->item('base_url').$CFG->item('index_page').$URI->uri_string;
+		$filepath = $cache_path.md5($uri);
+
+		if ( ! @file_exists($filepath) OR ! $fp = @fopen($filepath, FOPEN_READ))
+		{
+			return FALSE;
+		}
+
+		flock($fp, LOCK_SH);
+
+		$cache = (filesize($filepath) > 0) ? fread($fp, filesize($filepath)) : '';
+
+		flock($fp, LOCK_UN);
+		fclose($fp);
+
+		// Strip out the embedded timestamp
+		if ( ! preg_match('/^(\d+)TS--->/', $cache, $match))
+		{
+			return FALSE;
+		}
+
+		$last_modified = filemtime($cache_path);
+		$expire = $match[1];
+
+		// Has the file expired?
+		if ($_SERVER['REQUEST_TIME'] >= $expire && is_really_writable($cache_path))
+		{
+			// If so we'll delete it.
+			@unlink($filepath);
+			log_message('debug', 'Cache file has expired. File deleted.');
+			return FALSE;
+		}
+		else
+		{
+			// Or else send the HTTP cache control headers.
+			$this->set_cache_header($last_modified, $expire);
+		}
+
+		// Display the cache
+		$this->_display(substr($cache, strlen($match[0])));
+		log_message('debug', 'Cache file is current. Sending it to browser.');
+		return TRUE;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Delete cache
+	 *
+	 * @param	string	$uri	URI string
+	 * @return	bool
+	 */
+	public function delete_cache($uri = '')
+	{
+		$CI =& get_instance();
+		$cache_path = $CI->config->item('cache_path');
+		if ($cache_path === '')
+		{
+			$cache_path = APPPATH.'cache/';
+		}
+
+		if ( ! is_dir($cache_path))
+		{
+			log_message('error', 'Unable to find cache path: '.$cache_path);
+			return FALSE;
+		}
+
+		if (empty($uri))
+		{
+			$uri = $CI->uri->uri_string();
+		}
+
+		$cache_path .= md5($CI->config->item('base_url').$CI->config->item('index_page').$uri);
+
+		if ( ! @unlink($cache_path))
+		{
+			log_message('error', 'Unable to delete cache file for '.$uri);
+			return FALSE;
+		}
+
+		return TRUE;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Set Cache Header
+	 *
+	 * Set the HTTP headers to match the server-side file cache settings
+	 * in order to reduce bandwidth.
+	 *
+	 * @param	int	$last_modified	Timestamp of when the page was last modified
+	 * @param	int	$expiration	Timestamp of when should the requested page expire from cache
+	 * @return	void
+	 */
+	public function set_cache_header($last_modified, $expiration)
+	{
+		$max_age = $expiration - $_SERVER['REQUEST_TIME'];
+
+		if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && $last_modified <= strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']))
+		{
+			$this->set_status_header(304);
+			exit;
+		}
+		else
+		{
+			header('Pragma: public');
+			header('Cache-Control: max-age=' . $max_age . ', public');
+			header('Expires: '.gmdate('D, d M Y H:i:s', $expiration).' GMT');
+			header('Last-modified: '.gmdate('D, d M Y H:i:s', $last_modified).' GMT');
+		}
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Minify
+	 *
+	 * Reduce excessive size of HTML/CSS/JavaScript content.
+	 *
+	 * @param	string	$output	Output to minify
+	 * @param	string	$type	Output content MIME type
+	 * @return	string	Minified output
+	 */
+	public function minify($output, $type = 'text/html')
+	{
+		switch ($type)
+		{
+			case 'text/html':
+
+				if (($size_before = strlen($output)) === 0)
+				{
+					return '';
+				}
+
+				// Find all the <pre>,<code>,<textarea>, and <javascript> tags
+				// We'll want to return them to this unprocessed state later.
+				preg_match_all('{<pre.+</pre>}msU', $output, $pres_clean);
+				preg_match_all('{<code.+</code>}msU', $output, $codes_clean);
+				preg_match_all('{<textarea.+</textarea>}msU', $output, $textareas_clean);
+				preg_match_all('{<script.+</script>}msU', $output, $javascript_clean);
+
+				// Minify the CSS in all the <style> tags.
+				preg_match_all('{<style.+</style>}msU', $output, $style_clean);
+				foreach ($style_clean[0] as $s)
+				{
+					$output = str_replace($s, $this->_minify_script_style($s, TRUE), $output);
+				}
+
+				// Minify the javascript in <script> tags.
+				foreach ($javascript_clean[0] as $s)
+				{
+					$javascript_mini[] = $this->_minify_script_style($s, TRUE);
+				}
+
+				// Replace multiple spaces with a single space.
+				$output = preg_replace('!\s{2,}!', ' ', $output);
+
+				// Remove comments (non-MSIE conditionals)
+				$output = preg_replace('{\s*<!--[^\[].*-->\s*}msU', '', $output);
+
+				// Remove spaces around block-level elements.
+				$output = preg_replace('/\s*(<\/?(html|head|title|meta|script|link|style|body|h[1-6]|div|p|br)[^>]*>)\s*/is', '$1', $output);
+
+				// Replace mangled <pre> etc. tags with unprocessed ones.
+
+				if ( ! empty($pres_clean))
+				{
+					preg_match_all('{<pre.+</pre>}msU', $output, $pres_messed);
+					$output = str_replace($pres_messed[0], $pres_clean[0], $output);
+				}
+
+				if ( ! empty($codes_clean))
+				{
+					preg_match_all('{<code.+</code>}msU', $output, $codes_messed);
+					$output = str_replace($codes_messed[0], $codes_clean[0], $output);
+				}
+
+				if ( ! empty($codes_clean))
+				{
+					preg_match_all('{<textarea.+</textarea>}msU', $output, $textareas_messed);
+					$output = str_replace($textareas_messed[0], $textareas_clean[0], $output);
+				}
+
+				if (isset($javascript_mini))
+				{
+					preg_match_all('{<script.+</script>}msU', $output, $javascript_messed);
+					$output = str_replace($javascript_messed[0], $javascript_mini, $output);
+				}
+
+				$size_removed = $size_before - strlen($output);
+				$savings_percent = round(($size_removed / $size_before * 100));
+
+				log_message('debug', 'Minifier shaved '.($size_removed / 1000).'KB ('.$savings_percent.'%) off final HTML output.');
+
+			break;
+
+			case 'text/css':
+			case 'text/javascript':
+
+				$output = $this->_minify_script_style($output);
+
+			break;
+
+			default: break;
+		}
+
+		return $output;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Minify Style and Script
+	 *
+	 * Reduce excessive size of CSS/JavaScript content.  To remove spaces this
+	 * script walks the string as an array and determines if the pointer is inside
+	 * a string created by single quotes or double quotes.  spaces inside those
+	 * strings are not stripped.  Opening and closing tags are severed from
+	 * the string initially and saved without stripping whitespace to preserve
+	 * the tags and any associated properties if tags are present
+	 *
+	 * Minification logic/workflow is similar to methods used by Douglas Crockford
+	 * in JSMIN. http://www.crockford.com/javascript/jsmin.html
+	 *
+	 * KNOWN ISSUE: ending a line with a closing parenthesis ')' and no semicolon
+	 * where there should be one will break the Javascript. New lines after a
+	 * closing parenthesis are not recognized by the script. For best results
+	 * be sure to terminate lines with a semicolon when appropriate.
+	 *
+	 * @param	string	$output		Output to minify
+	 * @param	bool	$has_tags	Specify if the output has style or script tags
+	 * @return	string	Minified output
+	 */
+	protected function _minify_script_style($output, $has_tags = FALSE)
+	{
+		// We only need this if there are tags in the file
+		if ($has_tags === TRUE)
+		{
+			// Remove opening tag and save for later
+			$pos = strpos($output, '>') + 1;
+			$open_tag = substr($output, 0, $pos);
+			$output = substr_replace($output, '', 0, $pos);
+
+			// Remove closing tag and save it for later
+			$end_pos = strlen($output);
+			$pos = strpos($output, '</');
+			$closing_tag = substr($output, $pos, $end_pos);
+			$output = substr_replace($output, '', $pos);
+		}
+
+		// Remove CSS comments
+		$output = preg_replace('!/\*[^*]*\*+([^/][^*]*\*+)*/!i', '', $output);
+
+		// Remove spaces around curly brackets, colons,
+		// semi-colons, parenthesis, commas
+		$output = preg_replace('!\s*(:|;|,|}|{|\(|\))\s*!i', '$1', $output);
+
+		// Replace tabs with spaces
+		// Replace carriage returns & multiple new lines with single new line
+		// and trim any leading or trailing whitespace
+		$output = trim(preg_replace(array('/\t+/', '/\r/', '/\n+/'), array(' ', "\n", "\n"), $output));
+
+		// Remove spaces when safe to do so.
+		$in_string = $in_dstring = $prev = FALSE;
+		$array_output = str_split($output);
+		foreach ($array_output as $key => $value)
+		{
+			if ($in_string === FALSE && $in_dstring === FALSE)
+			{
+				if ($value === ' ')
+				{
+					// Get the next element in the array for comparisons
+					$next = $array_output[$key + 1];
+
+					// Strip spaces preceded/followed by a non-ASCII character
+					// or not preceded/followed by an alphanumeric
+					// or not preceded/followed \ $ and _
+					if ((preg_match('/^[\x20-\x7f]*$/D', $next) OR preg_match('/^[\x20-\x7f]*$/D', $prev))
+						&& ( ! ctype_alnum($next) OR ! ctype_alnum($prev))
+						&& ! in_array($next, array('\\', '_', '$'), TRUE)
+						&& ! in_array($prev, array('\\', '_', '$'), TRUE)
+					)
+					{
+						unset($array_output[$key]);
+					}
+				}
+				else
+				{
+					// Save this value as previous for the next iteration
+					// if it is not a blank space
+					$prev = $value;
+				}
+			}
+
+			if ($value === "'")
+			{
+				$in_string = ! $in_string;
+			}
+			elseif ($value === '"')
+			{
+				$in_dstring = ! $in_dstring;
+			}
+		}
+
+		// Put the string back together after spaces have been stripped
+		$output = implode($array_output);
+
+		// Remove new line characters unless previous or next character is
+		// printable or Non-ASCII
+		preg_match_all('/[\n]/', $output, $lf, PREG_OFFSET_CAPTURE);
+		$removed_lf = 0;
+		foreach ($lf as $feed_position)
+		{
+			foreach ($feed_position as $position)
+			{
+				$position = $position[1] - $removed_lf;
+				$next = $output[$position + 1];
+				$prev = $output[$position - 1];
+				if ( ! ctype_print($next) && ! ctype_print($prev)
+					&& ! preg_match('/^[\x20-\x7f]*$/D', $next)
+					&& ! preg_match('/^[\x20-\x7f]*$/D', $prev)
+				)
+				{
+					$output = substr_replace($output, '', $position, 1);
+					$removed_lf++;
+				}
+			}
+		}
+
+		// Put the opening and closing tags back if applicable
+		return isset($open_tag)
+			? $open_tag.$output.$closing_tag
+			: $output;
+	}
+
+}
+
+/* End of file Output.php */
 /* Location: ./system/core/Output.php */
\ No newline at end of file