Merge branch 'develop' of github.com:EllisLab/CodeIgniter into develop
diff --git a/application/config/config.php b/application/config/config.php
index a5fe339..726e3a7 100644
--- a/application/config/config.php
+++ b/application/config/config.php
@@ -204,7 +204,7 @@
 |	4 = All Messages
 |
 | You can also pass in a array with threshold levels to show individual error types
-| 
+|
 | 	array(2) = Debug Messages, without Error Messages
 |
 | For a live site you'll usually only enable Errors (1) to be logged otherwise
@@ -253,7 +253,7 @@
 |
 | If you use the Encryption class or the Session class you
 | MUST set an encryption key.  See the user guide for info.
-|  
+|
 | http://codeigniter.com/user_guide/libraries/encryption.html
 | http://codeigniter.com/user_guide/libraries/sessions.html
 |
@@ -297,7 +297,7 @@
 | 'cookie_domain' = Set to .your-domain.com for site-wide cookies
 | 'cookie_path'   =  Typically will be a forward slash
 | 'cookie_secure' =  Cookies will only be set if a secure HTTPS connection exists.
-| 'cookie_httponly' = Cookie will only be accessible via HTTP(S) (no javascript) 
+| 'cookie_httponly' = Cookie will only be accessible via HTTP(S) (no javascript)
 |
 */
 $config['cookie_prefix']	= "";
@@ -374,10 +374,10 @@
 | Master Time Reference
 |--------------------------------------------------------------------------
 |
-| Options are 'local' or 'gmt'.  This pref tells the system whether to use
-| your server's local time as the master 'now' reference, or convert it to
-| GMT.  See the 'date helper' page of the user guide for information
-| regarding date handling.
+| Options are 'local' or any PHP supported timezone. This preference tells
+| the system whether to use your server's local time as the master 'now'
+| reference, or convert it to the configured one timezone. See the 'date
+| helper' page of the user guide for information regarding date handling.
 |
 */
 $config['time_reference'] = 'local';
diff --git a/application/config/mimes.php b/application/config/mimes.php
index b9160d9..15493af 100644
--- a/application/config/mimes.php
+++ b/application/config/mimes.php
@@ -162,7 +162,8 @@
 	'flac'  =>	'audio/x-flac',
 	'ogg'   =>	'audio/ogg',
 	'kmz'	=>	array('application/vnd.google-earth.kmz', 'application/zip', 'application/x-zip'),
-	'kml'	=>	array('application/vnd.google-earth.kml+xml', 'application/xml', 'text/xml')
+	'kml'	=>	array('application/vnd.google-earth.kml+xml', 'application/xml', 'text/xml'),
+	'ics'	=>	'text/calendar'
 );
 
 /* End of file mimes.php */
diff --git a/application/config/user_agents.php b/application/config/user_agents.php
index 7611461..416ef56 100644
--- a/application/config/user_agents.php
+++ b/application/config/user_agents.php
@@ -29,11 +29,10 @@
 | -------------------------------------------------------------------
 | USER AGENT TYPES
 | -------------------------------------------------------------------
-| This file contains four arrays of user agent data.  It is used by the
+| This file contains four arrays of user agent data. It is used by the
 | User Agent Class to help identify browser, platform, robot, and
-| mobile device data.  The array keys are used to identify the device
+| mobile device data. The array keys are used to identify the device
 | and the array values are used to set the actual name of the item.
-|
 */
 
 $platforms = array(
@@ -179,6 +178,7 @@
 	'operamini'		=> 'Opera Mini',
 	'opera mini'	=> 'Opera Mini',
 	'opera mobi'	=> 'Opera Mobile',
+	'fennec'	=> 'Firefox Mobile',
 
 	// Other
 	'digital paths'	=> 'Digital Paths',
diff --git a/index.php b/index.php
index 3b00dd3..ad98013 100644
--- a/index.php
+++ b/index.php
@@ -174,17 +174,20 @@
 		chdir(dirname(__FILE__));
 	}
 
-	if (realpath($system_path) !== FALSE)
+	if (($_temp = realpath($system_path)) !== FALSE)
 	{
-		$system_path = realpath($system_path).'/';
+		$system_path = $_temp.'/';
 	}
-
-	// ensure there's a trailing slash
-	$system_path = rtrim($system_path, '/').'/';
+	else
+	{
+		// Ensure there's a trailing slash
+		$system_path = rtrim($system_path, '/').'/';
+	}
 
 	// Is the system path correct?
 	if ( ! is_dir($system_path))
 	{
+		header('HTTP/1.1 503 Service Unavailable.', TRUE, 503);
 		exit('Your system folder path does not appear to be set correctly. Please open the following file and correct this: '.pathinfo(__FILE__, PATHINFO_BASENAME));
 	}
 
@@ -196,10 +199,6 @@
 	// The name of THIS file
 	define('SELF', pathinfo(__FILE__, PATHINFO_BASENAME));
 
-	// The PHP file extension
-	// this global constant is deprecated.
-	define('EXT', '.php');
-
 	// Path to the system folder
 	define('BASEPATH', str_replace('\\', '/', $system_path));
 
@@ -212,13 +211,18 @@
 	// The path to the "application" folder
 	if (is_dir($application_folder))
 	{
+		if (($_temp = realpath($application_folder)) !== FALSE)
+		{
+			$application_folder = $_temp;
+		}
+
 		define('APPPATH', $application_folder.'/');
 	}
 	else
 	{
 		if ( ! is_dir(BASEPATH.$application_folder.'/'))
 		{
-			header('HTTP/1.1 503 Service Unavailable.', TRUE, '503');
+			header('HTTP/1.1 503 Service Unavailable.', TRUE, 503);
 			exit('Your application folder path does not appear to be set correctly. Please open the following file and correct this: '.SELF);
 		}
 
@@ -226,21 +230,34 @@
 	}
 
 	// The path to the "views" folder
-	if (is_dir($view_folder))
+	if ( ! is_dir($view_folder))
 	{
-		define ('VIEWPATH', $view_folder .'/');
+		if ( ! empty($view_folder) && is_dir(APPPATH.$view_folder.'/'))
+		{
+			$view_folder = APPPATH.$view_folder;
+		}
+		elseif ( ! is_dir(APPPATH.'views/'))
+		{
+			header('HTTP/1.1 503 Service Unavailable.', TRUE, 503);
+			exit('Your view folder path does not appear to be set correctly. Please open the following file and correct this: '.SELF);
+		}
+		else
+		{
+			$view_folder = APPPATH.'views';
+		}
+	}
+
+	if (($_temp = realpath($view_folder)) !== FALSE)
+	{
+		$view_folder = realpath($view_folder).'/';
 	}
 	else
 	{
-		if ( ! is_dir(APPPATH.'views/'))
-		{
-			header('HTTP/1.1 503 Service Unavailable.', TRUE, '503');
-			exit('Your view folder path does not appear to be set correctly. Please open the following file and correct this: '.SELF);
-		}
-
-		define ('VIEWPATH', APPPATH.'views/' );
+		$view_folder = rtrim($view_folder, '/').'/';
 	}
 
+	define('VIEWPATH', $view_folder);
+
 /*
  * --------------------------------------------------------------------
  * LOAD THE BOOTSTRAP FILE
@@ -251,4 +268,4 @@
 require_once BASEPATH.'core/CodeIgniter.php';
 
 /* End of file index.php */
-/* Location: ./index.php */
+/* Location: ./index.php */
\ No newline at end of file
diff --git a/readme.rst b/readme.rst
index 4707847..7b718fe 100644
--- a/readme.rst
+++ b/readme.rst
@@ -183,8 +183,6 @@
 
 -  `User Guide <http://codeigniter.com/user_guide/>`_
 -  `Community Forums <http://codeigniter.com/forums/>`_
--  `User
-   Voice <http://codeigniter.uservoice.com/forums/40508-codeigniter-reactor>`_
 -  `Community Wiki <http://codeigniter.com/wiki/>`_
 -  `Community IRC <http://codeigniter.com/irc/>`_
 
diff --git a/system/core/Benchmark.php b/system/core/Benchmark.php
old mode 100755
new mode 100644
diff --git a/system/core/CodeIgniter.php b/system/core/CodeIgniter.php
old mode 100755
new mode 100644
index b3e984d..8159b19
--- a/system/core/CodeIgniter.php
+++ b/system/core/CodeIgniter.php
@@ -73,9 +73,9 @@
  */
 	set_error_handler('_exception_handler');
 
-	if ( ! is_php('5.3'))
+	if ( ! is_php('5.4'))
 	{
-		@set_magic_quotes_runtime(0); // Kill magic quotes
+		@ini_set('magic_quotes_runtime', 0); // Kill magic quotes
 	}
 
 /*
diff --git a/system/core/Common.php b/system/core/Common.php
index 8af7d63..1708653 100644
--- a/system/core/Common.php
+++ b/system/core/Common.php
@@ -44,13 +44,13 @@
 	/**
 	 * Determines if the current version of PHP is greater then the supplied value
 	 *
-	 * Since there are a few places where we conditionally test for PHP > 5
+	 * Since there are a few places where we conditionally test for PHP > 5.3
 	 * we'll set a static variable.
 	 *
 	 * @param	string
 	 * @return	bool	TRUE if the current version is $version or higher
 	 */
-	function is_php($version = '5.0.0')
+	function is_php($version = '5.3.0')
 	{
 		static $_is_php;
 		$version = (string) $version;
@@ -233,18 +233,18 @@
 
 		$file_path = APPPATH.'config/config.php';
 		$found = FALSE;
-		if (file_exists($file_path)) 
+		if (file_exists($file_path))
 		{
 			$found = TRUE;
 			require($file_path);
 		}
 
 		// Is the config file in the environment folder?
-		if (defined(ENVIRONMENT) && file_exists($file_path = APPPATH.'config/'.ENVIRONMENT.'/config.php'))
+		if (defined('ENVIRONMENT') && file_exists($file_path = APPPATH.'config/'.ENVIRONMENT.'/config.php'))
 		{
-			require($file_path);			
-		} 
-		elseif ( ! $found) 
+			require($file_path);
+		}
+		elseif ( ! $found)
 		{
 			set_status_header(503);
 			exit('The configuration file does not exist.');
@@ -304,6 +304,32 @@
 
 // ------------------------------------------------------------------------
 
+if ( ! function_exists('get_mimes'))
+{
+	/**
+	 * Returns the MIME types array from config/mimes.php
+	 *
+	 * @return	array
+	 */
+	function &get_mimes()
+	{
+		static $_mimes = array();
+
+		if (defined('ENVIRONMENT') && is_file(APPPATH.'config/'.ENVIRONMENT.'/mimes.php'))
+		{
+			$_mimes = include(APPPATH.'config/'.ENVIRONMENT.'/mimes.php');
+		}
+		elseif (is_file(APPPATH.'config/mimes.php'))
+		{
+			$_mimes = include(APPPATH.'config/mimes.php');
+		}
+
+		return $_mimes;
+	}
+}
+
+// ------------------------------------------------------------------------
+
 if ( ! function_exists('show_error'))
 {
 	/**
diff --git a/system/core/Config.php b/system/core/Config.php
old mode 100755
new mode 100644
diff --git a/system/core/Exceptions.php b/system/core/Exceptions.php
old mode 100755
new mode 100644
diff --git a/system/core/Hooks.php b/system/core/Hooks.php
old mode 100755
new mode 100644
diff --git a/system/core/Input.php b/system/core/Input.php
old mode 100755
new mode 100644
index 73f46ba..162e40c
--- a/system/core/Input.php
+++ b/system/core/Input.php
@@ -376,14 +376,26 @@
 	/**
 	 * Validate IP Address
 	 *
-	 * Updated version suggested by Geert De Deckere
-	 *
 	 * @param	string
+	 * @param	string	'ipv4' or 'ipv6'
 	 * @return	bool
 	 */
-	public function valid_ip($ip)
+	public function valid_ip($ip, $which = '')
 	{
-		return (bool) filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4);
+		switch (strtolower($which))
+		{
+			case 'ipv4':
+				$which = FILTER_FLAG_IPV4;
+				break;
+			case 'ipv6':
+				$which = FILTER_FLAG_IPV6;
+				break;
+			default:
+				$which = NULL;
+				break;
+		}
+
+		return (bool) filter_var($ip, FILTER_VALIDATE_IP, $which);
 	}
 
 	// --------------------------------------------------------------------
diff --git a/system/core/Lang.php b/system/core/Lang.php
old mode 100755
new mode 100644
diff --git a/system/core/Loader.php b/system/core/Loader.php
index 09e9487..94739c7 100644
--- a/system/core/Loader.php
+++ b/system/core/Loader.php
@@ -668,7 +668,7 @@
 	 * @param 	bool
 	 * @return	void
 	 */
-	public function add_package_path($path, $view_cascade=TRUE)
+	public function add_package_path($path, $view_cascade = TRUE)
 	{
 		$path = rtrim($path, '/').'/';
 
diff --git a/system/core/Model.php b/system/core/Model.php
old mode 100755
new mode 100644
diff --git a/system/core/Output.php b/system/core/Output.php
old mode 100755
new mode 100644
index b5484ac..8a0f14e
--- a/system/core/Output.php
+++ b/system/core/Output.php
@@ -64,7 +64,7 @@
 	 *
 	 * @var array
 	 */
-	public $mime_types =	array();
+	public $mimes =		array();
 
 	/**
 	 * Mime-type for the current page
@@ -110,14 +110,7 @@
 		$this->_zlib_oc = (bool) @ini_get('zlib.output_compression');
 
 		// Get mime types for later
-		if (defined('ENVIRONMENT') && file_exists(APPPATH.'config/'.ENVIRONMENT.'/mimes.php'))
-		{
-			$this->mime_types = include APPPATH.'config/'.ENVIRONMENT.'/mimes.php';
-		}
-		else
-		{
-			$this->mime_types = include APPPATH.'config/mimes.php';
-		}
+		$this->mimes =& get_mimes();
 
 		log_message('debug', 'Output Class Initialized');
 	}
@@ -213,16 +206,16 @@
 	 * @param	string	extension of the file we're outputting
 	 * @return	void
 	 */
-	public function set_content_type($mime_type)
+	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->mime_types[$extension]))
+			if (isset($this->mimes[$extension]))
 			{
-				$mime_type =& $this->mime_types[$extension];
+				$mime_type =& $this->mimes[$extension];
 
 				if (is_array($mime_type))
 				{
@@ -233,7 +226,13 @@
 		
 		$this->mime_type = $mime_type;
 
-		$header = 'Content-Type: '.$mime_type;
+		if (empty($charset))
+		{
+			$charset = config_item('charset');
+		}
+
+		$header = 'Content-Type: '.$mime_type
+			.(empty($charset) ? NULL : '; charset='.strtolower($charset));
 
 		$this->headers[] = array($header, TRUE);
 		return $this;
@@ -388,7 +387,7 @@
 
 		if ($this->parse_exec_vars === TRUE)
 		{
-			$memory	= function_exists('memory_get_usage') ? round(memory_get_usage()/1024/1024, 2).'MB' : '0';
+			$memory	= round(memory_get_usage() / 1024 / 1024, 2).'MB';
 
 			$output = str_replace(array('{elapsed_time}', '{memory_usage}'), array($elapsed, $memory), $output);
 		}
diff --git a/system/core/Router.php b/system/core/Router.php
old mode 100755
new mode 100644
diff --git a/system/core/Security.php b/system/core/Security.php
old mode 100755
new mode 100644
diff --git a/system/core/URI.php b/system/core/URI.php
old mode 100755
new mode 100644
index a575bc3..a997525
--- a/system/core/URI.php
+++ b/system/core/URI.php
@@ -119,7 +119,7 @@
 			}
 
 			// No PATH_INFO?... What about QUERY_STRING?
-			$path = (isset($_SERVER['QUERY_STRING'])) ? $_SERVER['QUERY_STRING'] : @getenv('QUERY_STRING');
+			$path = isset($_SERVER['QUERY_STRING']) ? $_SERVER['QUERY_STRING'] : @getenv('QUERY_STRING');
 			if (trim($path, '/') !== '')
 			{
 				$this->_set_uri_string($path);
@@ -163,7 +163,7 @@
 	 * @param 	string
 	 * @return	void
 	 */
-	public function _set_uri_string($str)
+	protected function _set_uri_string($str)
 	{
 		// Filter out control characters
 		$str = remove_invisible_characters($str, FALSE);
@@ -177,8 +177,8 @@
 	/**
 	 * Detects the URI
 	 *
-	 * This function will detect the URI automatically and fix the query string
-	 * if necessary.
+	 * This function will detect the URI automatically
+	 * and fix the query string if necessary.
 	 *
 	 * @return	string
 	 */
@@ -189,23 +189,27 @@
 			return '';
 		}
 
-		$uri = $_SERVER['REQUEST_URI'];
-		if (strpos($uri, $_SERVER['SCRIPT_NAME']) === 0)
+		if (strpos($_SERVER['REQUEST_URI'], $_SERVER['SCRIPT_NAME']) === 0)
 		{
-			$uri = substr($uri, strlen($_SERVER['SCRIPT_NAME']));
+			$uri = substr($_SERVER['REQUEST_URI'], strlen($_SERVER['SCRIPT_NAME']));
 		}
-		elseif (strpos($uri, dirname($_SERVER['SCRIPT_NAME'])) === 0)
+		elseif (strpos($_SERVER['REQUEST_URI'], dirname($_SERVER['SCRIPT_NAME'])) === 0)
 		{
-			$uri = substr($uri, strlen(dirname($_SERVER['SCRIPT_NAME'])));
+			$uri = substr($_SERVER['REQUEST_URI'], strlen(dirname($_SERVER['SCRIPT_NAME'])));
+		}
+		else
+		{
+			$uri = $_SERVER['REQUEST_URI'];
 		}
 
 		// This section ensures that even on servers that require the URI to be in the query string (Nginx) a correct
 		// URI is found, and also fixes the QUERY_STRING server var and $_GET array.
-		if (strncmp($uri, '?/', 2) === 0)
+		if (strpos($uri, '?/') === 0)
 		{
 			$uri = substr($uri, 2);
 		}
-		$parts = preg_split('#\?#i', $uri, 2);
+
+		$parts = explode('?', $uri, 2);
 		$uri = $parts[0];
 		if (isset($parts[1]))
 		{
@@ -223,7 +227,7 @@
 			return '/';
 		}
 
-		$uri = parse_url($uri, PHP_URL_PATH);
+		$uri = parse_url('pseudo://hostname/'.$uri, PHP_URL_PATH);
 
 		// Do some final cleaning of the URI and return it
 		return str_replace(array('//', '../'), '/', trim($uri, '/'));
diff --git a/system/database/DB.php b/system/database/DB.php
old mode 100755
new mode 100644
diff --git a/system/database/DB_cache.php b/system/database/DB_cache.php
index 14f3c21..ba91103 100644
--- a/system/database/DB_cache.php
+++ b/system/database/DB_cache.php
@@ -99,7 +99,7 @@
 		$segment_two = ($this->CI->uri->segment(2) == FALSE) ? 'index' : $this->CI->uri->segment(2);
 		$filepath = $this->db->cachedir.$segment_one.'+'.$segment_two.'/'.md5($sql);
 
-		if (FALSE === ($cachedata = read_file($filepath)))
+		if (FALSE === ($cachedata = file_get_contents($filepath)))
 		{
 			return FALSE;
 		}
diff --git a/system/database/DB_driver.php b/system/database/DB_driver.php
index 39c19cd..d056bdb 100644
--- a/system/database/DB_driver.php
+++ b/system/database/DB_driver.php
@@ -596,35 +596,53 @@
 	 */
 	public function compile_binds($sql, $binds)
 	{
-		if (strpos($sql, $this->bind_marker) === FALSE)
+		if (empty($binds) OR empty($this->bind_marker) OR strpos($sql, $this->bind_marker) === FALSE)
+		{
+			return $sql;
+		}
+		elseif ( ! is_array($binds))
+		{
+			$binds = array($binds);
+			$bind_count = 1;
+		}
+		else
+		{
+			// Make sure we're using numeric keys
+			$binds = array_values($binds);
+			$bind_count = count($binds);
+		}
+
+		// We'll need the marker length later
+		$ml = strlen($this->bind_marker);
+
+		// Make sure not to replace a chunk inside a string that happens to match the bind marker
+		if ($c = preg_match_all("/'[^']*'/i", $sql, $matches))
+		{
+			$c = preg_match_all('/'.preg_quote($this->bind_marker).'/i',
+				str_replace($matches[0],
+					str_replace($this->bind_marker, str_repeat(' ', $ml), $matches[0]),
+					$sql, $c),
+				$matches, PREG_OFFSET_CAPTURE);
+
+			// Bind values' count must match the count of markers in the query
+			if ($bind_count !== $c)
+			{
+				return $sql;
+			}
+		}
+		elseif (($c = preg_match_all('/'.preg_quote($this->bind_marker).'/i', $sql, $matches, PREG_OFFSET_CAPTURE)) !== $bind_count)
 		{
 			return $sql;
 		}
 
-		if ( ! is_array($binds))
+		do
 		{
-			$binds = array($binds);
+			$c--;
+			$sql = substr_replace($sql, $this->escape($binds[$c]), $matches[0][$c][1], $ml);
 		}
+		while ($c !== 0);
 
-		// Get the sql segments around the bind markers
-		$segments = explode($this->bind_marker, $sql);
-
-		// The count of bind should be 1 less then the count of segments
-		// If there are more bind arguments trim it down
-		if (count($binds) >= count($segments))
-		{
-			$binds = array_slice($binds, 0, count($segments)-1);
-		}
-
-		// Construct the binded query
-		$result = $segments[0];
-		$i = 0;
-		foreach ($binds as $bind)
-		{
-			$result .= $this->escape($bind).$segments[++$i];
-		}
-
-		return $result;
+		return $sql;
 	}
 
 	// --------------------------------------------------------------------
@@ -934,8 +952,8 @@
 	 *
 	 * This function escapes column and table names
 	 *
-	 * @param	string
-	 * @return	string
+	 * @param	mixed
+	 * @return	mixed
 	 */
 	public function escape_identifiers($item)
 	{
@@ -943,25 +961,39 @@
 		{
 			return $item;
 		}
+		elseif (is_array($item))
+		{
+			foreach ($item as $key => $value)
+			{
+				$item[$key] = $this->escape_identifiers($value);
+			}
+
+			return $item;
+		}
+
+		static $preg_ec = array();
+
+		if (empty($preg_ec))
+		{
+			if (is_array($this->_escape_char))
+			{
+				$preg_ec = array(preg_quote($this->_escape_char[0]), preg_quote($this->_escape_char[1]));
+			}
+			else
+			{
+				$preg_ec[0] = $preg_ec[1] = preg_quote($this->_escape_char);
+			}
+		}
 
 		foreach ($this->_reserved_identifiers as $id)
 		{
 			if (strpos($item, '.'.$id) !== FALSE)
 			{
-				$item = str_replace('.', $this->_escape_char.'.', $item);
-
-				// remove duplicates if the user already included the escape
-				return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $this->_escape_char.$item);
+				return preg_replace('/'.$preg_ec[0].'?([^'.$preg_ec[1].'\.]+)'.$preg_ec[1].'?\./i', $preg_ec[0].'$1'.$preg_ec[1].'.', $item);
 			}
 		}
 
-		if (strpos($item, '.') !== FALSE)
-		{
-			$item = str_replace('.', $this->_escape_char.'.'.$this->_escape_char, $item);
-		}
-
-		// remove duplicates if the user already included the escape
-		return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $this->_escape_char.$item.$this->_escape_char);
+		return preg_replace('/'.$preg_ec[0].'?([^'.$preg_ec[1].'\.]+)'.$preg_ec[1].'?(\.)?/i', $preg_ec[0].'$1'.$preg_ec[1].'$2', $item);
 	}
 
 	// --------------------------------------------------------------------
@@ -1048,7 +1080,7 @@
 	 */
 	protected function _has_operator($str)
 	{
-		return (bool) preg_match('/(\s|<|>|!|=|IS NULL|IS NOT NULL)/i', trim($str));
+		return (bool) preg_match('/(\s|<|>|!|=|IS NULL|IS NOT NULL|BETWEEN)/i', trim($str));
 	}
 
 	// --------------------------------------------------------------------
@@ -1286,34 +1318,61 @@
 			$escaped_array = array();
 			foreach ($item as $k => $v)
 			{
-				$escaped_array[$this->protect_identifiers($k)] = $this->protect_identifiers($v);
+				$escaped_array[$this->protect_identifiers($k)] = $this->protect_identifiers($v, $prefix_single, $protect_identifiers, $field_exists);
 			}
 
 			return $escaped_array;
 		}
 
-		// Convert tabs or multiple spaces into single spaces
-		$item = preg_replace('/[\t ]+/', ' ', $item);
-
-		// If the item has an alias declaration we remove it and set it aside.
-		// Basically we remove everything to the right of the first space
-		if (strpos($item, ' ') !== FALSE)
-		{
-			$alias = strstr($item, ' ');
-			$item = substr($item, 0, - strlen($alias));
-		}
-		else
-		{
-			$alias = '';
-		}
-
 		// This is basically a bug fix for queries that use MAX, MIN, etc.
 		// If a parenthesis is found we know that we do not need to
 		// escape the data or add a prefix. There's probably a more graceful
 		// way to deal with this, but I'm not thinking of it -- Rick
 		if (strpos($item, '(') !== FALSE)
 		{
-			return $item.$alias;
+			return $item;
+		}
+
+		// Convert tabs or multiple spaces into single spaces
+		$item = preg_replace('/\s+/', ' ', $item);
+
+		static $preg_ec = array();
+
+		if (empty($preg_ec))
+		{
+			if (is_array($this->_escape_char))
+			{
+				$preg_ec = array(preg_quote($this->_escape_char[0]), preg_quote($this->_escape_char[1]));
+			}
+			else
+			{
+				$preg_ec[0] = $preg_ec[1] = preg_quote($this->_escape_char);
+			}
+		}
+
+		// If the item has an alias declaration we remove it and set it aside.
+		// Basically we remove everything to the right of the first space
+		preg_match('/^(('.$preg_ec[0].'[^'.$preg_ec[1].']+'.$preg_ec[1].')|([^'.$preg_ec[0].'][^\s]+))( AS)*(.+)*$/i', $item, $matches);
+
+		if (isset($matches[4]))
+		{
+			$item = $matches[1];
+
+			// Escape the alias, if needed
+			if ($protect_identifiers === TRUE)
+			{
+				$alias = empty($matches[5])
+					? ' '.$this->escape_identifiers(ltrim($matches[4]))
+					: $matches[4].' '.$this->escape_identifiers(ltrim($matches[5]));
+			}
+			else
+			{
+				$alias = $matches[4].$matches[5];
+			}
+		}
+		else
+		{
+			$alias = '';
 		}
 
 		// Break the string apart if it contains periods, then insert the table prefix
diff --git a/system/database/DB_forge.php b/system/database/DB_forge.php
index ff5eb3f..9b76392 100644
--- a/system/database/DB_forge.php
+++ b/system/database/DB_forge.php
@@ -72,6 +72,11 @@
 			return ($this->db->db_debug) ? $this->db->display_error('db_unable_to_drop') : FALSE;
 		}
 
+		if ( ! empty($this->db->data_cache['db_names']))
+		{
+			$this->db->data_cache['db_names'][] = $db_name;
+		}
+
 		return TRUE;
 	}
 
@@ -99,6 +104,15 @@
 			return ($this->db->db_debug) ? $this->db->display_error('db_unable_to_drop') : FALSE;
 		}
 
+		if ( ! empty($this->db->data_cache['db_names']))
+		{
+			$key = array_search(strtolower($db_name), array_map('strtolower', $this->db->data_cache['db_names']), TRUE);
+			if ($key !== FALSE)
+			{
+				unset($this->db->data_cache['db_names'][$key]);
+			}
+		}
+
 		return TRUE;
 	}
 
@@ -209,7 +223,18 @@
 
 		$sql = $this->_create_table($this->db->dbprefix.$table, $this->fields, $this->primary_keys, $this->keys, $if_not_exists);
 		$this->_reset();
-		return is_bool($sql) ? $sql : $this->db->query($sql);
+
+		if (is_bool($sql))
+		{
+			return $sql;
+		}
+
+		if (($result = $this->db->query($sql)) !== FALSE && ! empty($this->db->data_cache['table_names']))
+		{
+			$this->db->data_cache['table_names'][] = $$this->db->dbprefix.$table;
+		}
+
+		return $result;
 	}
 
 	// --------------------------------------------------------------------
@@ -231,7 +256,19 @@
 			return ($this->db->db_debug) ? $this->db->display_error('db_unsuported_feature') : FALSE;
 		}
 
-		return $this->db->query(sprintf($this->_drop_table, $this->db->escape_identifiers($this->db->dbprefix.$table_name)));
+		$result = $this->db->query(sprintf($this->_drop_table, $this->db->escape_identifiers($this->db->dbprefix.$table_name)));
+
+		// Update table list cache
+		if ($result && ! empty($this->db->data_cache['table_names']))
+		{
+			$key = array_search(strtolower($this->db->dbprefix.$table_name), array_map('strtolower', $this->db->data_cache['table_names']), TRUE);
+			if ($key !== FALSE)
+			{
+				unset($this->db->data_cache['table_names'][$key]);
+			}
+		}
+
+		return $result;
 	}
 
 	// --------------------------------------------------------------------
@@ -255,10 +292,21 @@
 			return ($this->db->db_debug) ? $this->db->display_error('db_unsuported_feature') : FALSE;
 		}
 
-		return $this->db->query(sprintf($this->_rename_table,
+		$result = $this->db->query(sprintf($this->_rename_table,
 						$this->db->escape_identifiers($this->db->dbprefix.$table_name),
 						$this->db->escape_identifiers($this->db->dbprefix.$new_table_name))
 					);
+
+		if ($result && ! empty($this->db->data_cache['table_names']))
+		{
+			$key = array_search(strtolower($this->db->dbprefix.$table_name), array_map('strtolower', $this->db->data_cache['table_names']), TRUE);
+			if ($key !== FALSE)
+			{
+				$this->db->data_cache['table_names'][$key] = $this->db->dbprefix.$new_table_name;
+			}
+		}
+
+		return $result;
 	}
 
 	// --------------------------------------------------------------------
diff --git a/system/database/DB_query_builder.php b/system/database/DB_query_builder.php
index 7a0ea0c..488b294 100644
--- a/system/database/DB_query_builder.php
+++ b/system/database/DB_query_builder.php
@@ -53,7 +53,6 @@
 	protected $qb_keys			= array();
 	protected $qb_limit			= FALSE;
 	protected $qb_offset			= FALSE;
-	protected $qb_order			= FALSE;
 	protected $qb_orderby			= array();
 	protected $qb_set			= array();
 	protected $qb_wherein			= array();
@@ -84,6 +83,7 @@
 	 * Generates the SELECT portion of the query
 	 *
 	 * @param	string
+	 * @param	mixed
 	 * @return	object
 	 */
 	public function select($select = '*', $escape = NULL)
@@ -93,6 +93,9 @@
 			$select = explode(',', $select);
 		}
 
+		// If the escape value was not set will will base it on the global setting
+		is_bool($escape) OR $escape = $this->_protect_identifiers;
+
 		foreach ($select as $val)
 		{
 			$val = trim($val);
@@ -321,15 +324,16 @@
 	 * @param	string
 	 * @param	string	the join condition
 	 * @param	string	the type of join
+	 * @param	string	wether not to try to escape identifiers
 	 * @return	object
 	 */
-	public function join($table, $cond, $type = '')
+	public function join($table, $cond, $type = '', $escape = TRUE)
 	{
 		if ($type !== '')
 		{
 			$type = strtoupper(trim($type));
 
-			if ( ! in_array($type, array('LEFT', 'RIGHT', 'OUTER', 'INNER', 'LEFT OUTER', 'RIGHT OUTER')))
+			if ( ! in_array($type, array('LEFT', 'RIGHT', 'OUTER', 'INNER', 'LEFT OUTER', 'RIGHT OUTER'), TRUE))
 			{
 				$type = '';
 			}
@@ -343,12 +347,39 @@
 		// in the protect_identifiers to know whether to add a table prefix
 		$this->_track_aliases($table);
 
-		// Strip apart the condition and protect the identifiers
-		if (preg_match('/([\[\w\.]+)([\W\s]+)(.+)/', $cond, $match))
+		// Split multiple conditions
+		if ($escape === TRUE && preg_match_all('/\sAND\s|\sOR\s/i', $cond, $m, PREG_SET_ORDER | PREG_OFFSET_CAPTURE))
+		{
+			$newcond = '';
+			$m[0][] = array('', strlen($cond));
+
+			for ($i = 0, $c = count($m[0]), $s = 0;
+				$i < $c;
+				$s += $m[0][$i][1] + strlen($m[0][$i][0]), $i++)
+			{
+				$temp = substr($cond, $s, $m[0][$i][1]);
+
+				$newcond .= preg_match('/([\[\w\.-]+)([\W\s]+)(.+)/i', $temp, $match)
+						? $this->protect_identifiers($match[1]).$match[2].$this->protect_identifiers($match[3])
+						: $temp;
+
+				$newcond .= $m[0][$i][0];
+			}
+
+			$cond = $newcond;
+		}
+		// Split apart the condition and protect the identifiers
+		elseif ($escape === TRUE && preg_match('/([\[\w\.-]+)([\W\s]+)(.+)/i', $cond, $match))
 		{
 			$cond = $this->protect_identifiers($match[1]).$match[2].$this->protect_identifiers($match[3]);
 		}
 
+		// Do we want to escape the table name?
+		if ($escape === TRUE)
+		{
+			$table = $this->protect_identifiers($table, TRUE, NULL, FALSE);
+		}
+
 		// Assemble the JOIN statement
 		$this->qb_join[] = $join = $type.'JOIN '.$this->protect_identifiers($table, TRUE, NULL, FALSE).' ON '.$cond;
 
@@ -371,6 +402,7 @@
 	 *
 	 * @param	mixed
 	 * @param	mixed
+	 * @param	bool
 	 * @return	object
 	 */
 	public function where($key, $value = NULL, $escape = TRUE)
@@ -388,6 +420,7 @@
 	 *
 	 * @param	mixed
 	 * @param	mixed
+	 * @param	bool
 	 * @return	object
 	 */
 	public function or_where($key, $value = NULL, $escape = TRUE)
@@ -405,6 +438,7 @@
 	 * @param	mixed
 	 * @param	mixed
 	 * @param	string
+	 * @param	mixed
 	 * @return	object
 	 */
 	protected function _where($key, $value = NULL, $type = 'AND ', $escape = NULL)
@@ -417,15 +451,16 @@
 		}
 
 		// If the escape value was not set will will base it on the global setting
-		if ( ! is_bool($escape))
-		{
-			$escape = $this->_protect_identifiers;
-		}
+		$escape = $this->_protect_identifiers;
 
 		foreach ($key as $k => $v)
 		{
 			$prefix = (count($this->qb_where) === 0 && count($this->qb_cache_where) === 0) ? '' : $type;
 
+			$k = $this->_has_operator($k)
+				? $this->protect_identifiers(substr($k, 0, strpos(rtrim($k), ' ')), FALSE, $escape).strchr(rtrim($k), ' ')
+				: $this->protect_identifiers($k, FALSE, $escape);
+
 			if (is_null($v) && ! $this->_has_operator($k))
 			{
 				// value appears not to have been set, assign the test to IS NULL
@@ -436,7 +471,6 @@
 			{
 				if ($escape === TRUE)
 				{
-					$k = $this->protect_identifiers($k, FALSE, $escape);
 					$v = ' '.$this->escape($v);
 				}
 
@@ -445,10 +479,6 @@
 					$k .= ' = ';
 				}
 			}
-			else
-			{
-				$k = $this->protect_identifiers($k, FALSE, $escape);
-			}
 
 			$this->qb_where[] = $prefix.$k.$v;
 			if ($this->qb_caching === TRUE)
@@ -547,7 +577,7 @@
 	{
 		if ($key === NULL OR $values === NULL)
 		{
-			return;
+			return $this;
 		}
 
 		$type = $this->_group_get_type($type);
@@ -853,6 +883,7 @@
 	 *
 	 * @param	string
 	 * @param	string
+	 * @param	bool
 	 * @return	object
 	 */
 	public function having($key, $value = '', $escape = TRUE)
@@ -869,6 +900,7 @@
 	 *
 	 * @param	string
 	 * @param	string
+	 * @param	bool
 	 * @return	object
 	 */
 	public function or_having($key, $value = '', $escape = TRUE)
@@ -885,6 +917,8 @@
 	 *
 	 * @param	string
 	 * @param	string
+	 * @param	string
+	 * @param	bool
 	 * @return	object
 	 */
 	protected function _having($key, $value = '', $type = 'AND ', $escape = TRUE)
@@ -943,7 +977,7 @@
 		}
 		elseif (trim($direction) !== '')
 		{
-			$direction = (in_array(strtoupper(trim($direction)), array('ASC', 'DESC'), TRUE)) ? ' '.$direction : ' ASC';
+			$direction = in_array(strtoupper(trim($direction)), array('ASC', 'DESC'), TRUE) ? ' '.$direction : ' ASC';
 		}
 
 
@@ -955,7 +989,9 @@
 				$part = trim($part);
 				if ( ! in_array($part, $this->qb_aliased_tables))
 				{
-					$part = $this->protect_identifiers(trim($part));
+					$part = preg_match('/^(.+)\s+(ASC|DESC)$/i', $part, $matches)
+						? $this->protect_identifiers(rtrim($matches[1])).' '.$matches[2]
+						: $this->protect_identifiers($part);
 				}
 
 				$temp[] = $part;
@@ -963,12 +999,11 @@
 
 			$orderby = implode(', ', $temp);
 		}
-		elseif ($direction !== $this->_random_keyword)
+		elseif ($direction !== $this->_random_keyword && $escape === TRUE)
 		{
-			if ($escape === TRUE)
-			{
-				$orderby = $this->protect_identifiers($orderby);
-			}
+			$orderby = preg_match('/^(.+)\s+(ASC|DESC)$/i', $orderby, $matches)
+				? $this->protect_identifiers(rtrim($matches[1])).' '.$matches[2]
+				: $this->protect_identifiers($orderby);
 		}
 
 		$this->qb_orderby[] = $orderby_statement = $orderby.$direction;
@@ -995,7 +1030,7 @@
 	{
 		$this->qb_limit = (int) $value;
 
-		if ( ! is_null($offset))
+		if ( ! empty($offset))
 		{
 			$this->qb_offset = (int) $offset;
 		}
@@ -1070,7 +1105,7 @@
 			$this->from($table);
 		}
 
-		$select =  $this->_compile_select();
+		$select = $this->_compile_select();
 
 		if ($reset === TRUE)
 		{
@@ -1093,7 +1128,7 @@
 	 * @param	string	the offset clause
 	 * @return	object
 	 */
-	public function get($table = '', $limit = null, $offset = null)
+	public function get($table = '', $limit = NULL, $offset = NULL)
 	{
 		if ($table !== '')
 		{
@@ -1101,7 +1136,7 @@
 			$this->from($table);
 		}
 
-		if ( ! is_null($limit))
+		if ( ! empty($limit))
 		{
 			$this->limit($limit, $offset);
 		}
@@ -1166,7 +1201,7 @@
 			$this->where($where);
 		}
 
-		if ( ! is_null($limit))
+		if ( ! empty($limit))
 		{
 			$this->limit($limit, $offset);
 		}
@@ -1275,11 +1310,7 @@
 
 			ksort($row); // puts $row in the same order as our keys
 
-			if ($escape === FALSE)
-			{
-				$this->qb_set[] =  '('.implode(',', $row).')';
-			}
-			else
+			if ($escape !== FALSE)
 			{
 				$clean = array();
 				foreach ($row as $value)
@@ -1287,8 +1318,10 @@
 					$clean[] = $this->escape($value);
 				}
 
-				$this->qb_set[] =  '('.implode(',', $clean).')';
+				$row = $clean;
 			}
+
+			$this->qb_set[] =  '('.implode(',', $row).')';
 		}
 
 		foreach ($keys as $k)
@@ -1475,6 +1508,24 @@
 	// --------------------------------------------------------------------
 
 	/**
+	 * From Tables
+	 *
+	 * This public function implicitly groups FROM tables so there is no confusion
+	 * about operator precedence in harmony with SQL standards
+	 *
+	 * @param       array
+	 * @return      string
+	 */
+	protected function _from_tables($tables)
+	{
+		is_array($tables) OR $tables = array($tables);
+
+		return (count($tables) === 1) ? $tables[0] : '('.implode(', ', $tables).')';
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
 	 * Get UPDATE query string
 	 *
 	 * Compiles an update query and returns the sql
@@ -1535,7 +1586,7 @@
 			$this->where($where);
 		}
 
-		if ($limit != NULL)
+		if ( ! empty($limit))
 		{
 			$this->limit($limit);
 		}
@@ -1856,7 +1907,7 @@
 			$this->where($where);
 		}
 
-		if ($limit != NULL)
+		if ( ! empty($limit))
 		{
 			$this->limit($limit);
 		}
@@ -1897,7 +1948,7 @@
 
 		return 'DELETE FROM '.$table
 			.(count($conditions) > 0 ? ' WHERE '.implode(' AND ', $conditions) : '')
-			.($limit ? ' LIMIT '.$limit : '');
+			.($limit ? ' LIMIT '.(int) $limit : '');
 	}
 
 	// --------------------------------------------------------------------
@@ -1967,7 +2018,7 @@
 		if (strpos($table, ' ') !== FALSE)
 		{
 			// if the alias is written with the AS keyword, remove it
-			$table = preg_replace('/ AS /i', ' ', $table);
+			$table = preg_replace('/\s+AS\s+/i', ' ', $table);
 
 			// Grab the alias
 			$table = trim(strrchr($table, ' '));
@@ -2070,10 +2121,6 @@
 		if (count($this->qb_orderby) > 0)
 		{
 			$sql .= "\nORDER BY ".implode(', ', $this->qb_orderby);
-			if ($this->qb_order !== FALSE)
-			{
-				$sql .= ($this->qb_order === 'desc') ? ' DESC' : ' ASC';
-			}
 		}
 
 		// Write the "LIMIT" portion of the query
@@ -2303,8 +2350,7 @@
 					'qb_no_escape'		=> array(),
 					'qb_distinct'		=> FALSE,
 					'qb_limit'		=> FALSE,
-					'qb_offset'		=> FALSE,
-					'qb_order'		=> FALSE
+					'qb_offset'		=> FALSE
 					)
 				);
 	}
@@ -2327,8 +2373,7 @@
 			'qb_like'	=> array(),
 			'qb_orderby'	=> array(),
 			'qb_keys'	=> array(),
-			'qb_limit'	=> FALSE,
-			'qb_order'	=> FALSE
+			'qb_limit'	=> FALSE
 			)
 		);
 	}
diff --git a/system/database/DB_utility.php b/system/database/DB_utility.php
index 02c9218..6a3b407 100644
--- a/system/database/DB_utility.php
+++ b/system/database/DB_utility.php
@@ -35,7 +35,6 @@
 abstract class CI_DB_utility extends CI_DB_forge {
 
 	public $db;
-	public $data_cache		= array();
 
 	// Platform specific SQL strings
 	// Just setting those defaults to FALSE as they are mostly MySQL-specific
@@ -60,29 +59,29 @@
 	public function list_databases()
 	{
 		// Is there a cached result?
-		if (isset($this->data_cache['db_names']))
+		if (isset($this->db->data_cache['db_names']))
 		{
-			return $this->data_cache['db_names'];
+			return $this->db->data_cache['db_names'];
 		}
 		elseif ($this->_list_databases === FALSE)
 		{
 			return ($this->db->db_debug) ? $this->db->display_error('db_unsuported_feature') : FALSE;
 		}
 
-		$this->data_cache['db_names'] = array();
+		$this->db->data_cache['db_names'] = array();
 
 		$query = $this->db->query($this->_list_databases);
 		if ($query === FALSE)
 		{
-			return $this->data_cache['db_names'];
+			return $this->db->data_cache['db_names'];
 		}
 
 		for ($i = 0, $c = count($query); $i < $c; $i++)
 		{
-			$this->data_cache['db_names'] = current($query[$i]);
+			$this->db->data_cache['db_names'] = current($query[$i]);
 		}
 
-		return $this->data_cache['db_names'];
+		return $this->db->data_cache['db_names'];
 	}
 
 	// --------------------------------------------------------------------
diff --git a/system/database/drivers/cubrid/cubrid_driver.php b/system/database/drivers/cubrid/cubrid_driver.php
index 6b9286f..6b67b75 100644
--- a/system/database/drivers/cubrid/cubrid_driver.php
+++ b/system/database/drivers/cubrid/cubrid_driver.php
@@ -396,27 +396,6 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 * From Tables
-	 *
-	 * This function implicitly groups FROM tables so there is no confusion
-	 * about operator precedence in harmony with SQL standards
-	 *
-	 * @param	array
-	 * @return	string
-	 */
-	protected function _from_tables($tables)
-	{
-		if ( ! is_array($tables))
-		{
-			$tables = array($tables);
-		}
-
-		return '('.implode(', ', $tables).')';
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
 	 * Update_Batch statement
 	 *
 	 * Generates a platform-specific batch update string from the supplied data
diff --git a/system/database/drivers/cubrid/cubrid_forge.php b/system/database/drivers/cubrid/cubrid_forge.php
index fb97162..d328aa2 100644
--- a/system/database/drivers/cubrid/cubrid_forge.php
+++ b/system/database/drivers/cubrid/cubrid_forge.php
@@ -60,8 +60,10 @@
 			else
 			{
 				$attributes = array_change_key_case($attributes, CASE_UPPER);
-				$sql .= "\n\t".$this->db->protect_identifiers($field)
-					.( ! empty($attributes['NAME']) ? ' '.$this->db->protect_identifiers($attributes['NAME']).' ' : '');
+
+				$sql .= "\n\t".$this->db->escape_identifiers($field);
+
+				empty($attributes['NAME']) OR $sql .= ' '.$this->db->escape_identifiers($attributes['NAME']).' ';
 
 				if ( ! empty($attributes['TYPE']))
 				{
@@ -69,7 +71,7 @@
 
 					if ( ! empty($attributes['CONSTRAINT']))
 					{
-						switch ($attributes['TYPE'])
+						switch (strtolower($attributes['TYPE']))
 						{
 							case 'decimal':
 							case 'float':
@@ -98,10 +100,23 @@
 				}
 			 */
 
-				$sql .= (isset($attributes['DEFAULT']) ? " DEFAULT '".$attributes['DEFAULT']."'" : '')
-					.(( ! empty($attributes['NULL']) && $attributes['NULL'] === TRUE) ? ' NULL' : ' NOT NULL')
-					.(( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE) ? ' AUTO_INCREMENT' : '')
-					.(( ! empty($attributes['UNIQUE']) && $attributes['UNIQUE'] === TRUE) ? ' UNIQUE' : '');
+				if (isset($attributes['DEFAULT']))
+				{
+					$sql .= " DEFAULT '".$attributes['DEFAULT']."'";
+				}
+
+				$sql .= ( ! empty($attributes['NULL']) && $attributes['NULL'] === TRUE)
+					? ' NULL' : ' NOT NULL';
+
+				if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE)
+				{
+					$sql .= ' AUTO_INCREMENT';
+				}
+
+				if ( ! empty($attributes['UNIQUE']) && $attributes['UNIQUE'] === TRUE)
+				{
+					$sql .= ' UNIQUE';
+				}
 			}
 
 			// don't add a comma on the end of the last field
@@ -142,8 +157,8 @@
 		// If there is a PK defined
 		if (count($primary_keys) > 0)
 		{
-			$key_name = $this->db->protect_identifiers('pk_'.$table.'_'.implode('_', $primary_keys));
-			$sql .= ",\n\tCONSTRAINT ".$key_name.' PRIMARY KEY('.implode(', ', $this->db->protect_identifiers($primary_keys)).')';
+			$key_name = $this->db->escape_identifiers('pk_'.$table.'_'.implode('_', $primary_keys));
+			$sql .= ",\n\tCONSTRAINT ".$key_name.' PRIMARY KEY('.implode(', ', $this->db->escape_identifiers($primary_keys)).')';
 		}
 
 		if (is_array($keys) && count($keys) > 0)
@@ -152,12 +167,12 @@
 			{
 				if (is_array($key))
 				{
-					$key_name = $this->db->protect_identifiers('idx_'.$table.implode('_', $key));
-					$key = $this->db->protect_identifiers($key);
+					$key_name = $this->db->escape_identifiers('idx_'.$table.implode('_', $key));
+					$key = $this->db->escape_identifiers($key);
 				}
 				else
 				{
-					$key_name = $this->db->protect_identifiers('idx_'.$table.$key);
+					$key_name = $this->db->escape_identifiers('idx_'.$table.$key);
 					$key = array($key_name);
 				}
 
@@ -184,16 +199,16 @@
 	 */
 	protected function _alter_table($alter_type, $table, $fields, $after_field = '')
 	{
-		$sql = 'ALTER TABLE '.$this->db->protect_identifiers($table).' '.$alter_type.' ';
+		$sql = 'ALTER TABLE '.$this->db->escape_identifiers($table).' '.$alter_type.' ';
 
 		// DROP has everything it needs now.
 		if ($alter_type === 'DROP')
 		{
-			return $sql.$this->db->protect_identifiers($fields);
+			return $sql.$this->db->escape_identifiers($fields);
 		}
 
 		return $sql.$this->_process_fields($fields)
-			.($after_field !== '' ? ' AFTER '.$this->db->protect_identifiers($after_field) : '');
+			.($after_field !== '' ? ' AFTER '.$this->db->escape_identifiers($after_field) : '');
 	}
 
 }
diff --git a/system/database/drivers/cubrid/cubrid_utility.php b/system/database/drivers/cubrid/cubrid_utility.php
index c8cee99..ea8feb4 100644
--- a/system/database/drivers/cubrid/cubrid_utility.php
+++ b/system/database/drivers/cubrid/cubrid_utility.php
@@ -41,12 +41,12 @@
 	 */
 	public function list_databases()
 	{
-		if (isset($this->data_cache['db_names']))
+		if (isset($this->db->data_cache['db_names']))
 		{
-			return $this->data_cache['db_names'];
+			return $this->db->data_cache['db_names'];
 		}
 
-		return $this->data_cache['db_names'] = cubrid_list_dbs($this->db->conn_id);
+		return $this->db->data_cache['db_names'] = cubrid_list_dbs($this->db->conn_id);
 	}
 
 	// --------------------------------------------------------------------
diff --git a/system/database/drivers/interbase/interbase_driver.php b/system/database/drivers/interbase/interbase_driver.php
index 8cbbfa1..5a03607 100644
--- a/system/database/drivers/interbase/interbase_driver.php
+++ b/system/database/drivers/interbase/interbase_driver.php
@@ -324,13 +324,7 @@
 	 */
 	protected function _from_tables($tables)
 	{
-		if ( ! is_array($tables))
-		{
-			$tables = array($tables);
-		}
-
-		//Interbase/Firebird doesn't like grouped tables
-		return implode(', ', $tables);
+		return is_array($tables) ? implode(', ', $tables) : $tables;
 	}
 
 	// --------------------------------------------------------------------
diff --git a/system/database/drivers/interbase/interbase_forge.php b/system/database/drivers/interbase/interbase_forge.php
index 5470179..d1b006e 100644
--- a/system/database/drivers/interbase/interbase_forge.php
+++ b/system/database/drivers/interbase/interbase_forge.php
@@ -67,6 +67,14 @@
 		{
 			return ($this->db->db_debug) ? $this->db->display_error('db_unable_to_drop') : FALSE;
 		}
+		elseif ( ! empty($this->db->data_cache['db_names']))
+		{
+			$key = array_search(strtolower($this->db->database), array_map('strtolower', $this->db->data_cache['db_names']), TRUE);
+			if ($key !== FALSE)
+			{
+				unset($this->db->data_cache['db_names'][$key]);
+			}
+		}
 
 		return TRUE;
 	}
@@ -87,7 +95,7 @@
 	{
 		$sql = 'CREATE TABLE ';
 
-		$sql .= $this->db->protect_identifiers($table)."(";
+		$sql .= $this->db->escape_identifiers($table).'(';
 		$current_field_count = 0;
 
 		foreach ($fields as $field => $attributes)
@@ -97,41 +105,30 @@
 			// entered the field information, so we'll simply add it to the list
 			if (is_numeric($field))
 			{
-				$sql .= "\n\t$attributes";
+				$sql .= "\n\t".$attributes;
 			}
 			else
 			{
 				$attributes = array_change_key_case($attributes, CASE_UPPER);
 
-				$sql .= "\n\t".$this->db->protect_identifiers($field);
+				$sql .= "\n\t".$this->db->escape_identifiers($field).' '.$attributes['TYPE'];
 
-				$sql .=  ' '.$attributes['TYPE'];
+				empty($attributes['CONSTRAINT']) OR $sql .= '('.$attributes['CONSTRAINT'].')';
 
-				if (array_key_exists('CONSTRAINT', $attributes))
-				{
-					$sql .= '('.$attributes['CONSTRAINT'].')';
-				}
-
-				if (array_key_exists('UNSIGNED', $attributes) && $attributes['UNSIGNED'] === TRUE)
+				if ( ! empty($attributes['UNSIGNED']) && $attributes['UNSIGNED'] === TRUE)
 				{
 					$sql .= ' UNSIGNED';
 				}
 
-				if (array_key_exists('DEFAULT', $attributes))
+				if (isset($attributes['DEFAULT']))
 				{
-					$sql .= ' DEFAULT \''.$attributes['DEFAULT'].'\'';
+					$sql .= " DEFAULT '".$attributes['DEFAULT']."'";
 				}
 
-				if (array_key_exists('NULL', $attributes) && $attributes['NULL'] === TRUE)
-				{
-					$sql .= ' NULL';
-				}
-				else
-				{
-					$sql .= ' NOT NULL';
-				}
+				$sql .= ( ! empty($attributes['NULL']) && $attributes['NULL'] === TRUE)
+					? ' NULL' : ' NOT NULL';
 
-				if (array_key_exists('AUTO_INCREMENT', $attributes) && $attributes['AUTO_INCREMENT'] === TRUE)
+				if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE)
 				{
 					$sql .= ' AUTO_INCREMENT';
 				}
@@ -146,30 +143,23 @@
 
 		if (count($primary_keys) > 0)
 		{
-			$primary_keys = $this->db->protect_identifiers($primary_keys);
-			$sql .= ",\n\tPRIMARY KEY (" . implode(', ', $primary_keys) . ")";
+			$primary_keys = $this->db->escape_identifiers($primary_keys);
+			$sql .= ",\n\tPRIMARY KEY (".implode(', ', $primary_keys).')';
 		}
 
 		if (is_array($keys) && count($keys) > 0)
 		{
 			foreach ($keys as $key)
 			{
-				if (is_array($key))
-				{
-					$key = $this->db->protect_identifiers($key);
-				}
-				else
-				{
-					$key = array($this->db->protect_identifiers($key));
-				}
+				$key = is_array($key)
+					? $this->db->escape_identifiers($key)
+					: array($this->db->escape_identifiers($key));
 
-				$sql .= ",\n\tUNIQUE (" . implode(', ', $key) . ")";
+				$sql .= ",\n\tUNIQUE (".implode(', ', $key).')';
 			}
 		}
 
-		$sql .= "\n)";
-
-		return $sql;
+		return $sql."\n)";
 	}
 
 	// --------------------------------------------------------------------
@@ -191,31 +181,11 @@
 	 */
 	protected function _alter_table($alter_type, $table, $column_name, $column_definition = '', $default_value = '', $null = '', $after_field = '')
 	{
-		$sql = 'ALTER TABLE '.$this->db->protect_identifiers($table)." $alter_type ".$this->db->protect_identifiers($column_name);
-
-		$sql .= " {$column_definition}";
-
-		if ($default_value !== '')
-		{
-			$sql .= " DEFAULT \"{$default_value}\"";
-		}
-
-		if ($null === NULL)
-		{
-			$sql .= ' NULL';
-		}
-		else
-		{
-			$sql .= ' NOT NULL';
-		}
-
-		if ($after_field !== '')
-		{
-			$sql .= ' AFTER ' . $this->db->protect_identifiers($after_field);
-		}
-
-		return $sql;
-
+		return 'ALTER TABLE '.$this->db->escape_identifiers($table).' '.$alter_type.' '.$this->db->escape_identifiers($column_name)
+			.' '.$column_definition
+			.($default_value !== '' ? ' DEFAULT "'.$default_value.'"' : '')
+			.($null === NULL ? ' NULL' : ' NOT NULL')
+			.($after_field !== '' ? ' AFTER '.$this->db->escape_identifiers($after_field) : '');
 	}
 
 }
diff --git a/system/database/drivers/mssql/mssql_driver.php b/system/database/drivers/mssql/mssql_driver.php
index 697b2fd..47dc558 100644
--- a/system/database/drivers/mssql/mssql_driver.php
+++ b/system/database/drivers/mssql/mssql_driver.php
@@ -43,7 +43,7 @@
 	public $dbdriver = 'mssql';
 
 	// The character used for escaping
-	protected $_escape_char = '';
+	protected $_escape_char = '"';
 
 	// clause and character used for LIKE escape sequences
 	protected $_like_escape_str = " ESCAPE '%s' ";
@@ -57,6 +57,29 @@
 	protected $_count_string = 'SELECT COUNT(*) AS ';
 	protected $_random_keyword = ' NEWID()';
 
+	// MSSQL-specific properties
+	protected $_quoted_identifier = TRUE;
+
+	/*
+	 * Constructor
+	 *
+	 * Appends the port number to the hostname, if needed.
+	 *
+	 * @param	array
+	 * @return	void
+	 */
+	public function __construct($params)
+	{
+		parent::__construct($params);
+
+		if ( ! empty($this->port))
+		{
+			$this->hostname .= (DIRECTORY_SEPARATOR === '\\' ? ',' : ':').$this->port;
+		}
+	}
+
+	// --------------------------------------------------------------------
+
 	/**
 	 * Non-persistent database connection
 	 *
@@ -64,12 +87,7 @@
 	 */
 	public function db_connect()
 	{
-		if ( ! empty($this->port))
-		{
-			$this->hostname .= ','.$this->port;
-		}
-
-		return @mssql_connect($this->hostname, $this->username, $this->password);
+		return $this->_mssql_connect();
 	}
 
 	// --------------------------------------------------------------------
@@ -81,12 +99,35 @@
 	 */
 	public function db_pconnect()
 	{
-		if ( ! empty($this->port))
+		return $this->_mssql_connect(TRUE);
+	}
+
+	// --------------------------------------------------------------------
+
+	/*
+	 * MSSQL Connect
+	 *
+	 * @param	bool
+	 * @return	resource
+	 */
+	protected function _mssql_connect($persistent = FALSE)
+	{
+		$conn_id = ($persistent)
+				? @mssql_pconnect($this->hostname, $this->username, $this->password)
+				: @mssql_connect($this->hostname, $this->username, $this->password);
+
+		if ( ! $conn_id)
 		{
-			$this->hostname .= ','.$this->port;
+			return FALSE;
 		}
 
-		return @mssql_pconnect($this->hostname, $this->username, $this->password);
+		// Determine how identifiers are escaped
+		$query = $this->query('SELECT CASE WHEN (@@OPTIONS | 256) = @@OPTIONS THEN 1 ELSE 0 END AS qi');
+		$query = $query->row_array();
+		$this->_quoted_identifier = empty($query) ? FALSE : (bool) $query->qi;
+		$this->_escape_char = ($this->_quoted_identifier) ? '"' : array('[', ']');
+
+		return $conn_id;
 	}
 
 	// --------------------------------------------------------------------
@@ -106,7 +147,7 @@
 
 		// Note: The brackets are required in the event that the DB name
 		// contains reserved characters
-		if (@mssql_select_db('['.$database.']', $this->conn_id))
+		if (@mssql_select_db($this->escape_identifiers($database), $this->conn_id))
 		{
 			$this->database = $database;
 			return TRUE;
@@ -121,7 +162,7 @@
 	 * Execute the query
 	 *
 	 * @param	string	an SQL query
-	 * @return	resource
+	 * @return	mixed	resource if rows are returned, bool otherwise
 	 */
 	protected function _execute($sql)
 	{
@@ -137,13 +178,8 @@
 	 */
 	public function trans_begin($test_mode = FALSE)
 	{
-		if ( ! $this->trans_enabled)
-		{
-			return TRUE;
-		}
-
 		// When transactions are nested we only begin/commit/rollback the outermost ones
-		if ($this->_trans_depth > 0)
+		if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
 		{
 			return TRUE;
 		}
@@ -151,10 +187,9 @@
 		// Reset the transaction failure flag.
 		// If the $test_mode flag is set to TRUE transactions will be rolled back
 		// even if the queries produce a successful result.
-		$this->_trans_failure = ($test_mode === TRUE) ? TRUE : FALSE;
+		$this->_trans_failure = ($test_mode === TRUE);
 
-		$this->simple_query('BEGIN TRAN');
-		return TRUE;
+		return $this->simple_query('BEGIN TRAN');
 	}
 
 	// --------------------------------------------------------------------
@@ -166,19 +201,13 @@
 	 */
 	public function trans_commit()
 	{
-		if ( ! $this->trans_enabled)
-		{
-			return TRUE;
-		}
-
 		// When transactions are nested we only begin/commit/rollback the outermost ones
-		if ($this->_trans_depth > 0)
+		if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
 		{
 			return TRUE;
 		}
 
-		$this->simple_query('COMMIT TRAN');
-		return TRUE;
+		return $this->simple_query('COMMIT TRAN');
 	}
 
 	// --------------------------------------------------------------------
@@ -190,19 +219,13 @@
 	 */
 	public function trans_rollback()
 	{
-		if ( ! $this->trans_enabled)
-		{
-			return TRUE;
-		}
-
 		// When transactions are nested we only begin/commit/rollback the outermost ones
-		if ($this->_trans_depth > 0)
+		if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
 		{
 			return TRUE;
 		}
 
-		$this->simple_query('ROLLBACK TRAN');
-		return TRUE;
+		return $this->simple_query('ROLLBACK TRAN');
 	}
 
 	// --------------------------------------------------------------------
@@ -232,7 +255,7 @@
 		// escape LIKE condition wildcards
 		if ($like === TRUE)
 		{
-			$str = str_replace(
+			return str_replace(
 				array($this->_like_escape_chr, '%', '_'),
 				array($this->_like_escape_chr.$this->_like_escape_chr, $this->_like_escape_chr.'%', $this->_like_escape_chr.'_'),
 				$str
@@ -265,11 +288,13 @@
 	 */
 	public function insert_id()
 	{
-		$ver = self::_parse_major_version($this->version());
-		$sql = ($ver >= 8 ? "SELECT SCOPE_IDENTITY() AS last_id" : "SELECT @@IDENTITY AS last_id");
-		$query = $this->query($sql);
-		$row = $query->row();
-		return $row->last_id;
+		$query = (self::_parse_major_version($this->version()) > 7)
+			? 'SELECT SCOPE_IDENTITY() AS last_id'
+			: 'SELECT @@IDENTITY AS last_id';
+
+		$query = $this->query($query);
+		$query = $query->row();
+		return $query->last_id;
 	}
 
 	// --------------------------------------------------------------------
@@ -352,7 +377,7 @@
 	 */
 	protected function _field_data($table)
 	{
-		return "SELECT TOP 1 * FROM ".$table;
+		return 'SELECT TOP 1 * FROM '.$table;
 	}
 
 	// --------------------------------------------------------------------
@@ -385,12 +410,7 @@
 	 */
 	protected function _from_tables($tables)
 	{
-		if ( ! is_array($tables))
-		{
-			$tables = array($tables);
-		}
-
-		return implode(', ', $tables);
+		return is_array($tables) ? implode(', ', $tables) : $tables;
 	}
 
 	// --------------------------------------------------------------------
@@ -484,9 +504,30 @@
 	 */
 	protected function _limit($sql, $limit, $offset)
 	{
-		$i = $limit + $offset;
+		// As of SQL Server 2012 (11.0.*) OFFSET is supported
+		if (version_compare($this->version(), '11', '>='))
+		{
+			return $sql.' OFFSET '.(int) $offset.' ROWS FETCH NEXT '.(int) $limit.' ROWS ONLY';
+		}
 
-		return preg_replace('/(^\SELECT (DISTINCT)?)/i','\\1 TOP '.$i.' ', $sql);
+		$limit = $offset + $limit;
+
+		// As of SQL Server 2005 (9.0.*) ROW_NUMBER() is supported,
+		// however an ORDER BY clause is required for it to work
+		if (version_compare($this->version(), '9', '>=') && $offset && ! empty($this->qb_orderby))
+		{
+			$orderby = 'ORDER BY '.implode(', ', $this->qb_orderby);
+
+			// We have to strip the ORDER BY clause
+			$sql = trim(substr($sql, 0, strrpos($sql, 'ORDER BY '.$orderby)));
+
+			return 'SELECT '.(count($this->qb_select) === 0 ? '*' : implode(', ', $this->qb_select))." FROM (\n"
+				.preg_replace('/^(SELECT( DISTINCT)?)/i', '\\1 ROW_NUMBER() OVER('.$orderby.') AS '.$this->escape_identifiers('CI_rownum').', ', $sql)
+				."\n) ".$this->escape_identifiers('CI_subquery')
+				."\nWHERE ".$this->escape_identifiers('CI_rownum').' BETWEEN '.((int) $offset + 1).' AND '.$limit;
+		}
+
+		return preg_replace('/(^\SELECT (DISTINCT)?)/i','\\1 TOP '.$limit.' ', $sql);
 	}
 
 	// --------------------------------------------------------------------
diff --git a/system/database/drivers/mssql/mssql_forge.php b/system/database/drivers/mssql/mssql_forge.php
index 3708c22..3a3528f 100644
--- a/system/database/drivers/mssql/mssql_forge.php
+++ b/system/database/drivers/mssql/mssql_forge.php
@@ -70,31 +70,25 @@
 
 				$sql .= "\n\t".$this->db->escape_identifiers($field).' '.$attributes['TYPE'];
 
-				if (array_key_exists('CONSTRAINT', $attributes))
+				if (stripos($attributes['TYPE'], 'INT') === FALSE && ! empty($attributes['CONSTRAINT']))
 				{
 					$sql .= '('.$attributes['CONSTRAINT'].')';
 				}
 
-				if (array_key_exists('UNSIGNED', $attributes) && $attributes['UNSIGNED'] === TRUE)
+				if ( ! empty($attributes['UNSIGNED']) && $attributes['UNSIGNED'] === TRUE)
 				{
 					$sql .= ' UNSIGNED';
 				}
 
-				if (array_key_exists('DEFAULT', $attributes))
+				if (isset($attributes['DEFAULT']))
 				{
-					$sql .= ' DEFAULT \''.$attributes['DEFAULT'].'\'';
+					$sql .= " DEFAULT '".$attributes['DEFAULT']."'";
 				}
 
-				if (array_key_exists('NULL', $attributes) && $attributes['NULL'] === TRUE)
-				{
-					$sql .= ' NULL';
-				}
-				else
-				{
-					$sql .= ' NOT NULL';
-				}
+				$sql .= ( ! empty($attributes['NULL']) && $attributes['NULL'] === TRUE)
+					? ' NULL' : ' NOT NULL';
 
-				if (array_key_exists('AUTO_INCREMENT', $attributes) && $attributes['AUTO_INCREMENT'] === TRUE)
+				if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE)
 				{
 					$sql .= ' AUTO_INCREMENT';
 				}
@@ -109,22 +103,16 @@
 
 		if (count($primary_keys) > 0)
 		{
-			$primary_keys = $this->db->protect_identifiers($primary_keys);
-			$sql .= ",\n\tPRIMARY KEY (".implode(', ', $primary_keys).')';
+			$sql .= ",\n\tPRIMARY KEY (".implode(', ', $this->db->escape_identifiers($primary_keys)).')';
 		}
 
 		if (is_array($keys) && count($keys) > 0)
 		{
 			foreach ($keys as $key)
 			{
-				if (is_array($key))
-				{
-					$key = $this->db->protect_identifiers($key);
-				}
-				else
-				{
-					$key = array($this->db->protect_identifiers($key));
-				}
+				$key = is_array($key)
+					? $this->db->escape_identifiers($key)
+					: array($this->db->escape_identifiers($key));
 
 				$sql .= ",\n\tFOREIGN KEY (".implode(', ', $key).')';
 			}
@@ -152,7 +140,7 @@
 	 */
 	protected function _alter_table($alter_type, $table, $column_name, $column_definition = '', $default_value = '', $null = '', $after_field = '')
 	{
-		$sql = 'ALTER TABLE '.$this->db->protect_identifiers($table).' '.$alter_type.' '.$this->db->protect_identifiers($column_name);
+		$sql = 'ALTER TABLE '.$this->db->escape_identifiers($table).' '.$alter_type.' '.$this->db->escape_identifiers($column_name);
 
 		// DROP has everything it needs now.
 		if ($alter_type === 'DROP')
@@ -160,21 +148,10 @@
 			return $sql;
 		}
 
-		$sql .= " ".$column_definition;
-
-		if ($default_value !== '')
-		{
-			$sql .= " DEFAULT '".$default_value."'";
-		}
-
-		$sql .= ($null === NULL) ? ' NULL' : ' NOT NULL';
-
-		if ($after_field !== '')
-		{
-			return $sql.' AFTER '.$this->db->protect_identifiers($after_field);
-		}
-
-		return $sql;
+		return $sql.' '.$column_definition
+			.($default_value != '' ? ' DEFAULT "'.$default_value.'"' : '')
+			.($null === NULL ? ' NULL' : ' NOT NULL')
+			.($after_field != '' ? ' AFTER '.$this->db->escape_identifiers($after_field) : '');
 	}
 
 }
diff --git a/system/database/drivers/mssql/mssql_result.php b/system/database/drivers/mssql/mssql_result.php
index 4cc87f4..5929306 100644
--- a/system/database/drivers/mssql/mssql_result.php
+++ b/system/database/drivers/mssql/mssql_result.php
@@ -92,12 +92,12 @@
 		$retval = array();
 		while ($field = mssql_fetch_field($this->result_id))
 		{
-			$F				= new stdClass();
-			$F->name		= $field->name;
-			$F->type		= $field->type;
+			$F		= new stdClass();
+			$F->name	= $field->name;
+			$F->type	= $field->type;
 			$F->max_length	= $field->max_length;
 			$F->primary_key = 0;
-			$F->default		= '';
+			$F->default	= '';
 
 			$retval[] = $F;
 		}
diff --git a/system/database/drivers/mssql/mssql_utility.php b/system/database/drivers/mssql/mssql_utility.php
index 6d47618..69fcec5 100644
--- a/system/database/drivers/mssql/mssql_utility.php
+++ b/system/database/drivers/mssql/mssql_utility.php
@@ -41,7 +41,7 @@
 	 * MSSQL Export
 	 *
 	 * @param	array	Preferences
-	 * @return	mixed
+	 * @return	bool
 	 */
 	protected function _backup($params = array())
 	{
diff --git a/system/database/drivers/mysql/mysql_driver.php b/system/database/drivers/mysql/mysql_driver.php
index 5937b22..8938d22 100644
--- a/system/database/drivers/mysql/mysql_driver.php
+++ b/system/database/drivers/mysql/mysql_driver.php
@@ -412,27 +412,6 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 * From Tables
-	 *
-	 * This function implicitly groups FROM tables so there is no confusion
-	 * about operator precedence in harmony with SQL standards
-	 *
-	 * @param	string	table name
-	 * @return	string
-	 */
-	protected function _from_tables($tables)
-	{
-		if ( ! is_array($tables))
-		{
-			$tables = array($tables);
-		}
-
-		return '('.implode(', ', $tables).')';
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
 	 * Update_Batch statement
 	 *
 	 * Generates a platform-specific batch update string from the supplied data
diff --git a/system/database/drivers/mysql/mysql_forge.php b/system/database/drivers/mysql/mysql_forge.php
index ffd374f..d22454d 100644
--- a/system/database/drivers/mysql/mysql_forge.php
+++ b/system/database/drivers/mysql/mysql_forge.php
@@ -60,8 +60,9 @@
 			{
 				$attributes = array_change_key_case($attributes, CASE_UPPER);
 
-				$sql .= "\n\t".$this->db->protect_identifiers($field)
-					.( ! empty($attributes['NAME']) ? ' '.$this->db->protect_identifiers($attributes['NAME']).' ' : '');
+				$sql .= "\n\t".$this->db->escape_identifiers($field);
+
+				empty($attributes['NAME']) OR ' '.$this->db->escape_identifiers($attributes['NAME']).' ';
 
 				if ( ! empty($attributes['TYPE']))
 				{
@@ -86,10 +87,23 @@
 					}
 				}
 
-				$sql .= (( ! empty($attributes['UNSIGNED']) && $attributes['UNSIGNED'] === TRUE) ? ' UNSIGNED' : '')
-					.(isset($attributes['DEFAULT']) ? " DEFAULT '".$attributes['DEFAULT']."'" : '')
-					.(( ! empty($attributes['NULL']) && $attributes['NULL'] === TRUE) ? ' NULL' : ' NOT NULL')
-					.(( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE) ? ' AUTO_INCREMENT' : '');
+				if ( ! empty($attributes['UNSIGNED']) && $attributes['UNSIGNED'] === TRUE)
+				{
+					$sql .= ' UNSIGNED';
+				}
+
+				if (isset($attributes['DEFAULT']))
+				{
+					$sql .= " DEFAULT '".$attributes['DEFAULT']."'";
+				}
+
+				$sql .= ( ! empty($attributes['NULL']) && $attributes['NULL'] === TRUE)
+					? ' NULL' : ' NOT NULL';
+
+				if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE)
+				{
+					$sql .= ' AUTO_INCREMENT';
+				}
 			}
 
 			// don't add a comma on the end of the last field
@@ -123,12 +137,12 @@
 			$sql .= 'IF NOT EXISTS ';
 		}
 
-		$sql .= $this->db->protect_identifiers($table).' ('.$this->_process_fields($fields);
+		$sql .= $this->db->escape_identifiers($table).' ('.$this->_process_fields($fields);
 
 		if (count($primary_keys) > 0)
 		{
-			$key_name = $this->db->protect_identifiers(implode('_', $primary_keys));
-			$sql .= ",\n\tPRIMARY KEY ".$key_name.' ('.implode(', ', $this->db->protect_identifiers($primary_keys)).')';
+			$key_name = $this->db->escape_identifiers(implode('_', $primary_keys));
+			$sql .= ",\n\tPRIMARY KEY ".$key_name.' ('.implode(', ', $this->db->escape_identifiers($primary_keys)).')';
 		}
 
 		if (is_array($keys) && count($keys) > 0)
@@ -137,12 +151,12 @@
 			{
 				if (is_array($key))
 				{
-					$key_name = $this->db->protect_identifiers(implode('_', $key));
-					$key = $this->db->protect_identifiers($key);
+					$key_name = $this->db->escape_identifiers(implode('_', $key));
+					$key = $this->db->escape_identifiers($key);
 				}
 				else
 				{
-					$key_name = $this->db->protect_identifiers($key);
+					$key_name = $this->db->escape_identifiers($key);
 					$key = array($key_name);
 				}
 
@@ -169,16 +183,16 @@
 	 */
 	protected function _alter_table($alter_type, $table, $fields, $after_field = '')
 	{
-		$sql = 'ALTER TABLE '.$this->db->protect_identifiers($table).' '.$alter_type.' ';
+		$sql = 'ALTER TABLE '.$this->db->escape_identifiers($table).' '.$alter_type.' ';
 
 		// DROP has everything it needs now.
 		if ($alter_type === 'DROP')
 		{
-			return $sql.$this->db->protect_identifiers($fields);
+			return $sql.$this->db->escape_identifiers($fields);
 		}
 
 		return $sql.$this->_process_fields($fields)
-			.($after_field !== '' ? ' AFTER '.$this->db->protect_identifiers($after_field) : '');
+			.($after_field !== '' ? ' AFTER '.$this->db->escape_identifiers($after_field) : '');
 	}
 
 }
diff --git a/system/database/drivers/mysql/mysql_utility.php b/system/database/drivers/mysql/mysql_utility.php
index 643682f..f0bbc66 100644
--- a/system/database/drivers/mysql/mysql_utility.php
+++ b/system/database/drivers/mysql/mysql_utility.php
@@ -65,7 +65,7 @@
 			}
 
 			// Get the table schema
-			$query = $this->db->query('SHOW CREATE TABLE '.$this->db->protect_identifiers($this->db->database).'.'.$this->db->protect_identifiers($table));
+			$query = $this->db->query('SHOW CREATE TABLE '.$this->db->escape_identifiers($this->db->database.'.'.$table));
 
 			// No result means the table name was invalid
 			if ($query === FALSE)
@@ -120,7 +120,7 @@
 							TRUE);
 
 				// Create a string of field names
-				$field_str .= $this->db->protect_identifiers($field->name).', ';
+				$field_str .= $this->db->escape_identifiers($field->name).', ';
 				$i++;
 			}
 
diff --git a/system/database/drivers/mysqli/mysqli_driver.php b/system/database/drivers/mysqli/mysqli_driver.php
index 02f8937..d3fb77a 100644
--- a/system/database/drivers/mysqli/mysqli_driver.php
+++ b/system/database/drivers/mysqli/mysqli_driver.php
@@ -412,27 +412,6 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 * From Tables
-	 *
-	 * This function implicitly groups FROM tables so there is no confusion
-	 * about operator precedence in harmony with SQL standards
-	 *
-	 * @param	string
-	 * @return	string
-	 */
-	protected function _from_tables($tables)
-	{
-		if ( ! is_array($tables))
-		{
-			$tables = array($tables);
-		}
-
-		return '('.implode(', ', $tables).')';
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
 	 * Update_Batch statement
 	 *
 	 * Generates a platform-specific batch update string from the supplied data
diff --git a/system/database/drivers/mysqli/mysqli_forge.php b/system/database/drivers/mysqli/mysqli_forge.php
index b00bfde..b74c775 100644
--- a/system/database/drivers/mysqli/mysqli_forge.php
+++ b/system/database/drivers/mysqli/mysqli_forge.php
@@ -60,13 +60,13 @@
 			{
 				$attributes = array_change_key_case($attributes, CASE_UPPER);
 
-				$sql .= "\n\t".$this->db->protect_identifiers($field)
-					.( ! empty($attributes['NAME']) ? ' '.$this->db->protect_identifiers($attributes['NAME']).' ' : '')
-				;
+				$sql .= "\n\t".$this->db->escape_identifiers($field);
+
+				empty($attributes['NAME']) OR $sql .= ' '.$this->db->escape_identifiers($attributes['NAME']).' ';
 
 				if ( ! empty($attributes['TYPE']))
 				{
-					$sql .=  ' '.$attributes['TYPE'];
+					$sql .= ' '.$attributes['TYPE'];
 
 					if ( ! empty($attributes['CONSTRAINT']))
 					{
@@ -87,10 +87,23 @@
 					}
 				}
 
-				$sql .= (( ! empty($attributes['UNSIGNED']) && $attributes['UNSIGNED'] === TRUE) ? ' UNSIGNED' : '')
-					.(isset($attributes['DEFAULT']) ? " DEFAULT '".$attributes['DEFAULT']."'" : '')
-					.(( ! empty($attributes['NULL']) && $attributes['NULL'] === TRUE) ? ' NULL' : ' NOT NULL')
-					.(( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE) ? ' AUTO_INCREMENT' : '');
+				if ( ! empty($attributes['UNSIGNED']) && $attributes['UNSIGNED'] === TRUE)
+				{
+					$sql .= ' UNSIGNED';
+				}
+
+				if (isset($attributes['DEFAULT']))
+				{
+					$sql .= " DEFAULT '".$attributes['DEFAULT']."'";
+				}
+
+				$sql .= ( ! empty($attributes['NULL']) && $attributes['NULL'] === TRUE)
+					? ' NULL' : ' NOT NULL';
+
+				if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE)
+				{
+					$sql .= ' AUTO_INCREMENT';
+				}
 			}
 
 			// don't add a comma on the end of the last field
@@ -128,8 +141,8 @@
 
 		if (count($primary_keys) > 0)
 		{
-			$key_name = $this->db->protect_identifiers(implode('_', $primary_keys));
-			$sql .= ",\n\tPRIMARY KEY ".$key_name.' ('.implode(', ', $this->db->protect_identifiers($primary_keys)).')';
+			$key_name = $this->db->escape_identifiers(implode('_', $primary_keys));
+			$sql .= ",\n\tPRIMARY KEY ".$key_name.' ('.implode(', ', $this->db->escape_identifiers($primary_keys)).')';
 		}
 
 		if (is_array($keys) && count($keys) > 0)
@@ -138,12 +151,12 @@
 			{
 				if (is_array($key))
 				{
-					$key_name = $this->db->protect_identifiers(implode('_', $key));
-					$key = $this->db->protect_identifiers($key);
+					$key_name = $this->db->escape_identifiers(implode('_', $key));
+					$key = $this->db->escape_identifiers($key);
 				}
 				else
 				{
-					$key_name = $this->db->protect_identifiers($key);
+					$key_name = $this->db->escape_identifiers($key);
 					$key = array($key_name);
 				}
 
@@ -170,16 +183,16 @@
 	 */
 	protected function _alter_table($alter_type, $table, $fields, $after_field = '')
 	{
-		$sql = 'ALTER TABLE '.$this->db->protect_identifiers($table).' '.$alter_type.' ';
+		$sql = 'ALTER TABLE '.$this->db->escape_identifiers($table).' '.$alter_type.' ';
 
 		// DROP has everything it needs now.
 		if ($alter_type === 'DROP')
 		{
-			return $sql.$this->db->protect_identifiers($fields);
+			return $sql.$this->db->escape_identifiers($fields);
 		}
 
 		return $sql.$this->_process_fields($fields)
-			.($after_field !== '' ? ' AFTER '.$this->db->protect_identifiers($after_field) : '');
+			.($after_field !== '' ? ' AFTER '.$this->db->escape_identifiers($after_field) : '');
 	}
 
 }
diff --git a/system/database/drivers/mysqli/mysqli_utility.php b/system/database/drivers/mysqli/mysqli_utility.php
index 27d4ef8..5d2bdbc 100644
--- a/system/database/drivers/mysqli/mysqli_utility.php
+++ b/system/database/drivers/mysqli/mysqli_utility.php
@@ -46,9 +46,124 @@
 	 */
 	protected function _backup($params = array())
 	{
-		// Currently unsupported
-		return $this->db->display_error('db_unsuported_feature');
+		if (count($params) === 0)
+		{
+			return FALSE;
+		}
+
+		// Extract the prefs for simplicity
+		extract($params);
+
+		// Build the output
+		$output = '';
+		foreach ( (array) $tables as $table)
+		{
+			// Is the table in the "ignore" list?
+			if (in_array($table, (array) $ignore, TRUE))
+			{
+				continue;
+			}
+
+			// Get the table schema
+			$query = $this->db->query('SHOW CREATE TABLE '.$this->db->escape_identifiers($this->db->database.'.'.$table));
+
+			// No result means the table name was invalid
+			if ($query === FALSE)
+			{
+				continue;
+			}
+
+			// Write out the table schema
+			$output .= '#'.$newline.'# TABLE STRUCTURE FOR: '.$table.$newline.'#'.$newline.$newline;
+
+			if ($add_drop === TRUE)
+			{
+				$output .= 'DROP TABLE IF EXISTS '.$this->db->protect_identifiers($table).';'.$newline.$newline;
+			}
+
+			$i = 0;
+			$result = $query->result_array();
+			foreach ($result[0] as $val)
+			{
+				if ($i++ % 2)
+				{
+					$output .= $val.';'.$newline.$newline;
+				}
+			}
+
+			// If inserts are not needed we're done...
+			if ($add_insert === FALSE)
+			{
+				continue;
+			}
+
+			// Grab all the data from the current table
+			$query = $this->db->query('SELECT * FROM '.$this->db->protect_identifiers($table));
+
+			if ($query->num_rows() === 0)
+			{
+				continue;
+			}
+
+			// Fetch the field names and determine if the field is an
+			// integer type. We use this info to decide whether to
+			// surround the data with quotes or not
+
+			$i = 0;
+			$field_str = '';
+			$is_int = array();
+			while ($field = $query->result_id->fetch_field())
+			{
+				// Most versions of MySQL store timestamp as a string
+				$is_int[$i] = in_array(strtolower($field->type),
+							array('tinyint', 'smallint', 'mediumint', 'int', 'bigint'), //, 'timestamp'),
+							TRUE);
+
+				// Create a string of field names
+				$field_str .= $this->db->escape_identifiers($field->name).', ';
+				$i++;
+			}
+
+			// Trim off the end comma
+			$field_str = preg_replace('/, $/' , '', $field_str);
+
+			// Build the insert string
+			foreach ($query->result_array() as $row)
+			{
+				$val_str = '';
+
+				$i = 0;
+				foreach ($row as $v)
+				{
+					// Is the value NULL?
+					if ($v === NULL)
+					{
+						$val_str .= 'NULL';
+					}
+					else
+					{
+						// Escape the data if it's not an integer
+						$val_str .= ($is_int[$i] === FALSE) ? $this->db->escape($v) : $v;
+					}
+
+					// Append a comma
+					$val_str .= ', ';
+					$i++;
+				}
+
+				// Remove the comma at the end of the string
+				$val_str = preg_replace('/, $/' , '', $val_str);
+
+				// Build the INSERT string
+				$output .= 'INSERT INTO '.$this->db->protect_identifiers($table).' ('.$field_str.') VALUES ('.$val_str.');'.$newline;
+			}
+
+			$output .= $newline.$newline;
+		}
+
+		return $output;
 	}
+
 }
 
 /* End of file mysqli_utility.php */
diff --git a/system/database/drivers/oci8/oci8_forge.php b/system/database/drivers/oci8/oci8_forge.php
index 837e7ea..92e8c02 100644
--- a/system/database/drivers/oci8/oci8_forge.php
+++ b/system/database/drivers/oci8/oci8_forge.php
@@ -73,11 +73,22 @@
 			{
 				$attributes = array_change_key_case($attributes, CASE_UPPER);
 
-				$sql .= "\n\t".$this->db->protect_identifiers($field).' '.$attributes['TYPE']
-					.((isset($attributes['UNSINGED']) && $attributes['UNSIGNED'] === TRUE) ? ' UNSIGNED' : '')
-					.(isset($attributes['DEFAULT']) ? " DEFAULT '".$attributes['DEFAULT']."'" : '')
-					.((isset($attributes['NULL']) && $attributes['NULL'] === TRUE) ? '' : ' NOT NULL')
-					.(isset($attributes['CONSTRAINT']) ? ' CONSTRAINT '.$attributes['CONSTRAINT'] : '');
+				$sql .= "\n\t".$this->db->escape_identifiers($field).' '.$attributes['TYPE'];
+
+				if (isset($attributes['UNSINGED']) && $attributes['UNSIGNED'] === TRUE)
+				{
+					$sql .= ' UNSIGNED';
+				}
+
+				if (isset($attributes['DEFAULT']))
+				{
+					$sql .= " DEFAULT '".$attributes['DEFAULT']."'";
+				}
+
+				$sql .= (isset($attributes['NULL']) && $attributes['NULL'] === TRUE)
+					? '' : ' NOT NULL';
+
+				empty($attributes['CONSTRAINT']) OR ' CONSTRAINT '.$attributes['CONSTRAINT'];
 			}
 
 			// don't add a comma on the end of the last field
@@ -89,22 +100,16 @@
 
 		if (count($primary_keys) > 0)
 		{
-			$primary_keys = $this->db->protect_identifiers($primary_keys);
-			$sql .= ",\n\tCONSTRAINT ".$table.' PRIMARY KEY ('.implode(', ', $primary_keys).')';
+			$sql .= ",\n\tCONSTRAINT ".$table.' PRIMARY KEY ('.implode(', ', $this->db->escape_identifiers($primary_keys)).')';
 		}
 
 		if (is_array($keys) && count($keys) > 0)
 		{
 			foreach ($keys as $key)
 			{
-				if (is_array($key))
-				{
-					$key = $this->db->protect_identifiers($key);
-				}
-				else
-				{
-					$key = array($this->db->protect_identifiers($key));
-				}
+				$key = is_array($key)
+					? $this->db->escape_identifiers($key)
+					: array($this->db->escape_identifiers($key));
 
 				$sql .= ",\n\tUNIQUE COLUMNS (".implode(', ', $key).')';
 			}
@@ -132,7 +137,7 @@
 	 */
 	protected function _alter_table($alter_type, $table, $column_name, $column_definition = '', $default_value = '', $null = '', $after_field = '')
 	{
-		$sql = 'ALTER TABLE '.$this->db->protect_identifiers($table).' '.$alter_type.' '.$this->db->protect_identifiers($column_name);
+		$sql = 'ALTER TABLE '.$this->db->escape_identifiers($table).' '.$alter_type.' '.$this->db->escape_identifiers($column_name);
 
 		// DROP has everything it needs now.
 		if ($alter_type === 'DROP')
@@ -143,7 +148,7 @@
 		return $sql.' '.$column_definition
 			.($default_value !== '' ? ' DEFAULT "'.$default_value.'"' : '')
 			.($null === NULL ? ' NULL' : ' NOT NULL')
-			.($after_field !== '' ? ' AFTER '.$this->db->protect_identifiers($after_field) : '');
+			.($after_field !== '' ? ' AFTER '.$this->db->escape_identifiers($after_field) : '');
 
 	}
 
diff --git a/system/database/drivers/odbc/odbc_driver.php b/system/database/drivers/odbc/odbc_driver.php
index c3735da..222c311 100644
--- a/system/database/drivers/odbc/odbc_driver.php
+++ b/system/database/drivers/odbc/odbc_driver.php
@@ -114,13 +114,8 @@
 	 */
 	public function trans_begin($test_mode = FALSE)
 	{
-		if ( ! $this->trans_enabled)
-		{
-			return TRUE;
-		}
-
 		// When transactions are nested we only begin/commit/rollback the outermost ones
-		if ($this->_trans_depth > 0)
+		if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
 		{
 			return TRUE;
 		}
@@ -128,7 +123,7 @@
 		// Reset the transaction failure flag.
 		// If the $test_mode flag is set to TRUE transactions will be rolled back
 		// even if the queries produce a successful result.
-		$this->_trans_failure = ($test_mode === TRUE) ? TRUE : FALSE;
+		$this->_trans_failure = ($test_mode === TRUE);
 
 		return odbc_autocommit($this->conn_id, FALSE);
 	}
@@ -142,13 +137,8 @@
 	 */
 	public function trans_commit()
 	{
-		if ( ! $this->trans_enabled)
-		{
-			return TRUE;
-		}
-
 		// When transactions are nested we only begin/commit/rollback the outermost ones
-		if ($this->_trans_depth > 0)
+		if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
 		{
 			return TRUE;
 		}
@@ -167,13 +157,8 @@
 	 */
 	public function trans_rollback()
 	{
-		if ( ! $this->trans_enabled)
-		{
-			return TRUE;
-		}
-
 		// When transactions are nested we only begin/commit/rollback the outermost ones
-		if ($this->_trans_depth > 0)
+		if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
 		{
 			return TRUE;
 		}
@@ -204,7 +189,6 @@
 			return $str;
 		}
 
-		// ODBC doesn't require escaping
 		$str = remove_invisible_characters($str);
 
 		// escape LIKE condition wildcards
@@ -277,7 +261,7 @@
 	 */
 	protected function _list_columns($table = '')
 	{
-		return "SHOW COLUMNS FROM ".$table;
+		return 'SHOW COLUMNS FROM '.$table;
 	}
 
 	// --------------------------------------------------------------------
@@ -292,7 +276,7 @@
 	 */
 	protected function _field_data($table)
 	{
-		return "SELECT TOP 1 FROM ".$table;
+		return 'SELECT TOP 1 FROM '.$table;
 	}
 
 	// --------------------------------------------------------------------
@@ -323,12 +307,7 @@
 	 */
 	protected function _from_tables($tables)
 	{
-		if ( ! is_array($tables))
-		{
-			$tables = array($tables);
-		}
-
-		return '('.implode(', ', $tables).')';
+		return is_array($tables) ? implode(', ', $tables) : $tables;
 	}
 
 	// --------------------------------------------------------------------
@@ -363,8 +342,7 @@
 	 */
 	protected function _limit($sql, $limit, $offset)
 	{
-		// Does ODBC doesn't use the LIMIT clause?
-		return $sql;
+		return $sql.($offset == 0 ? '' : $offset.', ').$limit;
 	}
 
 	// --------------------------------------------------------------------
diff --git a/system/database/drivers/odbc/odbc_forge.php b/system/database/drivers/odbc/odbc_forge.php
index ce7a1d2..b074c58 100644
--- a/system/database/drivers/odbc/odbc_forge.php
+++ b/system/database/drivers/odbc/odbc_forge.php
@@ -66,41 +66,30 @@
 			// entered the field information, so we'll simply add it to the list
 			if (is_numeric($field))
 			{
-				$sql .= "\n\t$attributes";
+				$sql .= "\n\t".$attributes;
 			}
 			else
 			{
 				$attributes = array_change_key_case($attributes, CASE_UPPER);
 
-				$sql .= "\n\t".$this->db->protect_identifiers($field);
+				$sql .= "\n\t".$this->db->escape_identifiers($field).' '.$attributes['TYPE'];
 
-				$sql .=  ' '.$attributes['TYPE'];
+				empty($attributes['CONSTRAINT']) OR $sql .= '('.$attributes['CONSTRAINT'].')';
 
-				if (array_key_exists('CONSTRAINT', $attributes))
-				{
-					$sql .= '('.$attributes['CONSTRAINT'].')';
-				}
-
-				if (array_key_exists('UNSIGNED', $attributes) && $attributes['UNSIGNED'] === TRUE)
+				if ( ! empty($attributes['UNSIGNED']) && $attributes['UNSIGNED'] === TRUE)
 				{
 					$sql .= ' UNSIGNED';
 				}
 
-				if (array_key_exists('DEFAULT', $attributes))
+				if (isset($attributes['DEFAULT']))
 				{
-					$sql .= ' DEFAULT \''.$attributes['DEFAULT'].'\'';
+					$sql .= " DEFAULT '".$attributes['DEFAULT']."'";
 				}
 
-				if (array_key_exists('NULL', $attributes) && $attributes['NULL'] === TRUE)
-				{
-					$sql .= ' NULL';
-				}
-				else
-				{
-					$sql .= ' NOT NULL';
-				}
+				$sql .= ( ! empty($attributes['NULL']) && $attributes['NULL'] === TRUE)
+					? ' NULL' : ' NOT NULL';
 
-				if (array_key_exists('AUTO_INCREMENT', $attributes) && $attributes['AUTO_INCREMENT'] === TRUE)
+				if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE)
 				{
 					$sql .= ' AUTO_INCREMENT';
 				}
@@ -115,30 +104,22 @@
 
 		if (count($primary_keys) > 0)
 		{
-			$primary_keys = $this->db->protect_identifiers($primary_keys);
-			$sql .= ",\n\tPRIMARY KEY (" . implode(', ', $primary_keys) . ")";
+			$sql .= ",\n\tPRIMARY KEY (".implode(', ', $this->escape_identifiers($primary_keys)).')';
 		}
 
 		if (is_array($keys) && count($keys) > 0)
 		{
 			foreach ($keys as $key)
 			{
-				if (is_array($key))
-				{
-					$key = $this->db->protect_identifiers($key);
-				}
-				else
-				{
-					$key = array($this->db->protect_identifiers($key));
-				}
+				$key = is_array($key)
+					? $this->db->escape_identifiers($key)
+					: array($this->db->escape_identifiers($key));
 
-				$sql .= ",\n\tFOREIGN KEY (" . implode(', ', $key) . ")";
+				$sql .= ",\n\tFOREIGN KEY (".implode(', ', $key).')';
 			}
 		}
 
-		$sql .= "\n)";
-
-		return $sql;
+		return $sql."\n)";
 	}
 
 	// --------------------------------------------------------------------
@@ -160,7 +141,7 @@
 	 */
 	protected function _alter_table($alter_type, $table, $column_name, $column_definition = '', $default_value = '', $null = '', $after_field = '')
 	{
-		$sql = 'ALTER TABLE '.$this->db->protect_identifiers($table).' '.$alter_type.' '.$this->db->protect_identifiers($column_name);
+		$sql = 'ALTER TABLE '.$this->db->escape_identifiers($table).' '.$alter_type.' '.$this->db->escape_identifiers($column_name);
 
 		// DROP has everything it needs now.
 		if ($alter_type === 'DROP')
@@ -168,29 +149,10 @@
 			return $sql;
 		}
 
-		$sql .= " $column_definition";
-
-		if ($default_value !== '')
-		{
-			$sql .= " DEFAULT \"$default_value\"";
-		}
-
-		if ($null === NULL)
-		{
-			$sql .= ' NULL';
-		}
-		else
-		{
-			$sql .= ' NOT NULL';
-		}
-
-		if ($after_field !== '')
-		{
-			return $sql.' AFTER '.$this->db->protect_identifiers($after_field);
-		}
-
-		return $sql;
-
+		return $sql.' '.$column_definition
+			.($default_value != '' ? ' DEFAULT "'.$default_value.'"' : '')
+			.($null === NULL ? ' NULL' : ' NOT NULL')
+			.($after_field != '' ? ' AFTER '.$this->db->escape_identifiers($after_field) : '');
 	}
 
 }
diff --git a/system/database/drivers/odbc/odbc_result.php b/system/database/drivers/odbc/odbc_result.php
index ecba597..227fe4f 100644
--- a/system/database/drivers/odbc/odbc_result.php
+++ b/system/database/drivers/odbc/odbc_result.php
@@ -59,8 +59,6 @@
 		return $this->num_rows;
 	}
 
-	// --------------------------------------------------------------------
-
 	/**
 	 * Number of fields in the result set
 	 *
@@ -148,14 +146,9 @@
 	 */
 	protected function _fetch_assoc()
 	{
-		if (function_exists('odbc_fetch_array'))
-		{
-			return odbc_fetch_array($this->result_id);
-		}
-		else
-		{
-			return $this->_odbc_fetch_array($this->result_id);
-		}
+		return function_exists('odbc_fetch_array')
+			? odbc_fetch_array($this->result_id)
+			: $this->_odbc_fetch_array($this->result_id);
 	}
 
 	// --------------------------------------------------------------------
@@ -169,14 +162,9 @@
 	 */
 	protected function _fetch_object()
 	{
-		if (function_exists('odbc_fetch_object'))
-		{
-			return odbc_fetch_object($this->result_id);
-		}
-		else
-		{
-			return $this->_odbc_fetch_object($this->result_id);
-		}
+		return function_exists('odbc_fetch_object')
+			? odbc_fetch_object($this->result_id)
+			: $this->_odbc_fetch_object($this->result_id);
 	}
 
 	// --------------------------------------------------------------------
@@ -192,15 +180,18 @@
 	protected function _odbc_fetch_object(& $odbc_result)
 	{
 		$rs = array();
-		$rs_obj = FALSE;
-		if (odbc_fetch_into($odbc_result, $rs))
+		if ( ! odbc_fetch_into($odbc_result, $rs))
 		{
-			foreach ($rs as $k => $v)
-			{
-				$field_name = odbc_field_name($odbc_result, $k+1);
-				$rs_obj->$field_name = $v;
-			}
+			return FALSE;
 		}
+
+		$rs_obj = new stdClass();
+		foreach ($rs as $k => $v)
+		{
+			$field_name = odbc_field_name($odbc_result, $k+1);
+			$rs_obj->$field_name = $v;
+		}
+
 		return $rs_obj;
 	}
 
@@ -217,16 +208,18 @@
 	protected function _odbc_fetch_array(& $odbc_result)
 	{
 		$rs = array();
-		$rs_assoc = FALSE;
-		if (odbc_fetch_into($odbc_result, $rs))
+		if ( ! odbc_fetch_into($odbc_result, $rs))
 		{
-			$rs_assoc = array();
-			foreach ($rs as $k => $v)
-			{
-				$field_name = odbc_field_name($odbc_result, $k+1);
-				$rs_assoc[$field_name] = $v;
-			}
+			return FALSE;
 		}
+
+		$rs_assoc = array();
+		foreach ($rs as $k => $v)
+		{
+			$field_name = odbc_field_name($odbc_result, $k+1);
+			$rs_assoc[$field_name] = $v;
+		}
+
 		return $rs_assoc;
 	}
 
diff --git a/system/database/drivers/pdo/pdo_driver.php b/system/database/drivers/pdo/pdo_driver.php
index b4ad52a..e25013a 100644
--- a/system/database/drivers/pdo/pdo_driver.php
+++ b/system/database/drivers/pdo/pdo_driver.php
@@ -519,27 +519,6 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 * From Tables
-	 *
-	 * This function implicitly groups FROM tables so there is no confusion
-	 * about operator precedence in harmony with SQL standards
-	 *
-	 * @param	array
-	 * @return	string
-	 */
-	protected function _from_tables($tables)
-	{
-		if ( ! is_array($tables))
-		{
-			$tables = array($tables);
-		}
-
-		return (count($tables) === 1) ? $tables[0] : '('.implode(', ', $tables).')';
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
 	 * Update_Batch statement
 	 *
 	 * Generates a platform-specific batch update string from the supplied data
diff --git a/system/database/drivers/pdo/pdo_forge.php b/system/database/drivers/pdo/pdo_forge.php
index aee8f71..02ceb74 100644
--- a/system/database/drivers/pdo/pdo_forge.php
+++ b/system/database/drivers/pdo/pdo_forge.php
@@ -66,18 +66,16 @@
 			// entered the field information, so we'll simply add it to the list
 			if (is_numeric($field))
 			{
-				$sql .= "\n\t$attributes";
+				$sql .= "\n\t".$attributes;
 			}
 			else
 			{
 				$attributes = array_change_key_case($attributes, CASE_UPPER);
-				$numeric    = array('SERIAL', 'INTEGER');
+				$numeric = array('SERIAL', 'INTEGER');
 
-				$sql .= "\n\t".$this->db->protect_identifiers($field);
+				$sql .= "\n\t".$this->db->escape_identifiers($field).' '.$attributes['TYPE'];
 
-				$sql .=  ' '.$attributes['TYPE'];
-
-				if (array_key_exists('CONSTRAINT', $attributes))
+				if ( ! empty($attributes['CONSTRAINT']))
 				{
 					// Exception for Postgre numeric which not too happy with constraint within those type
 					if ( ! ($this->db->pdodriver === 'pgsql' && in_array($attributes['TYPE'], $numeric)))
@@ -86,26 +84,20 @@
 					}
 				}
 
-				if (array_key_exists('UNSIGNED', $attributes) && $attributes['UNSIGNED'] === TRUE)
+				if ( ! empty($attributes['UNSIGNED']) && $attributes['UNSIGNED'] === TRUE)
 				{
 					$sql .= ' UNSIGNED';
 				}
 
-				if (array_key_exists('DEFAULT', $attributes))
+				if (isset($attributes['DEFAULT']))
 				{
-					$sql .= ' DEFAULT \''.$attributes['DEFAULT'].'\'';
+					$sql .= " DEFAULT '".$attributes['DEFAULT']."'";
 				}
 
-				if (array_key_exists('NULL', $attributes) && $attributes['NULL'] === TRUE)
-				{
-					$sql .= ' NULL';
-				}
-				else
-				{
-					$sql .= ' NOT NULL';
-				}
+				$sql .= ( ! empty($attributes['NULL']) && $attributes['NULL'] === TRUE)
+					? ' NULL' : ' NOT NULL';
 
-				if (array_key_exists('AUTO_INCREMENT', $attributes) && $attributes['AUTO_INCREMENT'] === TRUE)
+				if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE)
 				{
 					$sql .= ' AUTO_INCREMENT';
 				}
@@ -120,30 +112,22 @@
 
 		if (count($primary_keys) > 0)
 		{
-			$primary_keys = $this->db->protect_identifiers($primary_keys);
-			$sql .= ",\n\tPRIMARY KEY (" . implode(', ', $primary_keys) . ")";
+			$sql .= ",\n\tPRIMARY KEY (".implode(', ', $this->db->escape_identifiers($primary_keys)).')';
 		}
 
 		if (is_array($keys) && count($keys) > 0)
 		{
 			foreach ($keys as $key)
 			{
-				if (is_array($key))
-				{
-					$key = $this->db->protect_identifiers($key);
-				}
-				else
-				{
-					$key = array($this->db->protect_identifiers($key));
-				}
+				$key = is_array($key)
+					? $this->db->escape_identifiers($key)
+					: array($this->db->escape_identifiers($key));
 
-				$sql .= ",\n\tFOREIGN KEY (" . implode(', ', $key) . ")";
+				$sql .= ",\n\tFOREIGN KEY (".implode(', ', $key).')';
 			}
 		}
 
-		$sql .= "\n)";
-
-		return $sql;
+		return $sql."\n)";
 	}
 
 	// --------------------------------------------------------------------
@@ -165,7 +149,7 @@
 	 */
 	protected function _alter_table($alter_type, $table, $column_name, $column_definition = '', $default_value = '', $null = '', $after_field = '')
 	{
-		$sql = 'ALTER TABLE `'.$this->db->protect_identifiers($table).'` '.$alter_type.' '.$this->db->protect_identifiers($column_name);
+		$sql = 'ALTER TABLE '.$this->db->escape_identifiers($table).' '.$alter_type.' '.$this->db->escape_identifiers($column_name);
 
 		// DROP has everything it needs now.
 		if ($alter_type === 'DROP')
@@ -173,29 +157,10 @@
 			return $sql;
 		}
 
-		$sql .= " $column_definition";
-
-		if ($default_value !== '')
-		{
-			$sql .= " DEFAULT \"$default_value\"";
-		}
-
-		if ($null === NULL)
-		{
-			$sql .= ' NULL';
-		}
-		else
-		{
-			$sql .= ' NOT NULL';
-		}
-
-		if ($after_field !== '')
-		{
-			return $sql.' AFTER '.$this->db->protect_identifiers($after_field);
-		}
-
-		return $sql;
-
+		return $sql .' '.$column_definition
+			.($default_value !== '' ? " DEFAULT '".$default_value."'" : '')
+			.($null === NULL ? ' NULL' : ' NOT NULL')
+			.($after_field !== '' ? ' AFTER '.$this->db->escape_identifiers($after_field) : '');
 	}
 
 }
diff --git a/system/database/drivers/postgre/postgre_driver.php b/system/database/drivers/postgre/postgre_driver.php
index e5d861b..ad9ac90 100644
--- a/system/database/drivers/postgre/postgre_driver.php
+++ b/system/database/drivers/postgre/postgre_driver.php
@@ -467,12 +467,7 @@
 	 */
 	protected function _from_tables($tables)
 	{
-		if ( ! is_array($tables))
-		{
-			$tables = array($tables);
-		}
-
-		return implode(', ', $tables);
+		return is_array($tables) ? implode(', ', $tables) : $tables;
 	}
 
 	// --------------------------------------------------------------------
@@ -620,6 +615,10 @@
 		{
 			$prefix = (count($this->qb_where) === 0 && count($this->qb_cache_where) === 0) ? '' : $type;
 
+			$k = $this->_has_operator($k)
+				? $this->protect_identifiers(substr($k, 0, strpos(rtrim($k), ' ')), FALSE, $escape).strchr(rtrim($k), ' ')
+				: $this->protect_identifiers($k, FALSE, $escape);
+
 			if (is_null($v) && ! $this->_has_operator($k))
 			{
 				// value appears not to have been set, assign the test to IS NULL
@@ -630,7 +629,6 @@
 			{
 				if ($escape === TRUE)
 				{
-					$k = $this->protect_identifiers($k, FALSE, $escape);
 					$v = ' '.$this->escape($v);
 				}
 				elseif (is_bool($v))
@@ -643,10 +641,6 @@
 					$k .= ' = ';
 				}
 			}
-			else
-			{
-				$k = $this->protect_identifiers($k, FALSE, $escape);
-			}
 
 			$this->qb_where[] = $prefix.$k.$v;
 			if ($this->qb_caching === TRUE)
diff --git a/system/database/drivers/postgre/postgre_forge.php b/system/database/drivers/postgre/postgre_forge.php
index af1c45f..c434e95 100644
--- a/system/database/drivers/postgre/postgre_forge.php
+++ b/system/database/drivers/postgre/postgre_forge.php
@@ -58,7 +58,7 @@
 			}
 			else
 			{
-				$sql .= "\n\t".$this->db->protect_identifiers($field);
+				$sql .= "\n\t".$this->db->escape_identifiers($field);
 
 				$attributes = array_change_key_case($attributes, CASE_UPPER);
 				$is_unsigned = ( ! empty($attributes['UNSIGNED']) && $attributes['UNSIGNED'] === TRUE);
@@ -107,10 +107,19 @@
 					$sql .= '('.$attributes['CONSTRAINT'].')';
 				}
 
-				$sql .= (isset($attributes['DEFAULT']) ? " DEFAULT '".$attributes['DEFAULT']."'" : '')
-					.(( ! empty($attributes['NULL']) && $attributes['NULL'] === TRUE) ? ' NULL' : ' NOT NULL')
-					// Added new attribute to create unqite fields. Also works with MySQL
-					.(( ! empty($attributes['UNIQUE']) && $attributes['UNIQUE'] === TRUE) ? ' UNIQUE' : '');
+				if (isset($attributes['DEFAULT']))
+				{
+					$sql .= " DEFAULT '".$attributes['DEFAULT']."'";
+				}
+
+				$sql .= ( ! empty($attributes['NULL']) && $attributes['NULL'] === TRUE)
+					? ' NULL' : ' NOT NULL';
+
+				// Added new attribute to create unique fields. Also works with MySQL
+				if ( ! empty($attributes['UNIQUE']) && $attributes['UNIQUE'] === TRUE)
+				{
+					$sql .= ' UNIQUE';
+				}
 			}
 
 			// don't add a comma on the end of the last field
@@ -139,26 +148,17 @@
 	{
 		$sql = 'CREATE TABLE ';
 
-		if ($if_not_exists === TRUE)
+		// PostgreSQL doesn't support IF NOT EXISTS syntax so we check if table exists manually
+		if ($if_not_exists === TRUE && $this->db->table_exists($table))
 		{
-			// PostgreSQL doesn't support IF NOT EXISTS syntax so we check if table exists manually
-			if ($this->db->table_exists($table))
-			{
-				return TRUE;
-			}
+			return TRUE;
 		}
 
 		$sql .= $this->db->escape_identifiers($table).' ('.$this->_process_fields($fields, $primary_keys);
 
 		if (count($primary_keys) > 0)
 		{
-			// Something seems to break when passing an array to protect_identifiers()
-			foreach ($primary_keys as $index => $key)
-			{
-				$primary_keys[$index] = $this->db->protect_identifiers($key);
-			}
-
-			$sql .= ",\n\tPRIMARY KEY (".implode(', ', $primary_keys).')';
+			$sql .= ",\n\tPRIMARY KEY (".implode(', ', $this->db->escape_identifiers($primary_keys)).')';
 		}
 
 		$sql .= "\n);";
@@ -167,18 +167,14 @@
 		{
 			foreach ($keys as $key)
 			{
-				if (is_array($key))
-				{
-					$key = $this->db->protect_identifiers($key);
-				}
-				else
-				{
-					$key = array($this->db->protect_identifiers($key));
-				}
+				$key = is_array($key)
+					? $this->db->escape_identifiers($key)
+					: array($this->db->escape_identifiers($key));
 
 				foreach ($key as $field)
 				{
-					$sql .= 'CREATE INDEX '.$table.'_'.str_replace(array('"', "'"), '', $field).'_index ON '.$table.' ('.$field.'); ';
+					$sql .= "\nCREATE INDEX ".$this->db->escape_identifiers($table.'_'.str_replace(array('"', "'"), '', $field).'_index')
+						.' ON '.$this->db->escape_identifiers($table).' ('.$this->db->escape_identifiers($field).');';
 				}
 			}
 		}
@@ -205,16 +201,16 @@
 	 */
 	protected function _alter_table($alter_type, $table, $fields, $after_field = '')
  	{
- 		$sql = 'ALTER TABLE '.$this->db->protect_identifiers($table).' '.$alter_type.' ';
+ 		$sql = 'ALTER TABLE '.$this->db->escape_identifiers($table).' '.$alter_type.' ';
 
  		// DROP has everything it needs now.
  		if ($alter_type === 'DROP')
  		{
- 			return $sql.$this->db->protect_identifiers($fields);
+ 			return $sql.$this->db->escape_identifiers($fields);
  		}
 
  		return $sql.$this->_process_fields($fields)
-			.($after_field !== '' ? ' AFTER '.$this->db->protect_identifiers($after_field) : '');
+			.($after_field !== '' ? ' AFTER '.$this->db->escape_identifiers($after_field) : '');
  	}
 
 }
diff --git a/system/database/drivers/sqlite/sqlite_driver.php b/system/database/drivers/sqlite/sqlite_driver.php
index f52b1ba..3305f60 100644
--- a/system/database/drivers/sqlite/sqlite_driver.php
+++ b/system/database/drivers/sqlite/sqlite_driver.php
@@ -43,7 +43,7 @@
 	public $dbdriver = 'sqlite';
 
 	// The character used to escape with - not needed for SQLite
-	protected $_escape_char = '';
+	protected $_escape_char = '"';
 
 	// clause and character used for LIKE escape sequences
 	protected $_like_escape_str = " ESCAPE '%s' ";
@@ -127,7 +127,9 @@
 	 */
 	protected function _execute($sql)
 	{
-		return @sqlite_query($this->conn_id, $sql);
+		return $this->is_write_type($sql)
+			? @sqlite_exec($this->conn_id, $sql)
+			: @sqlite_query($this->conn_id, $sql);
 	}
 
 	// --------------------------------------------------------------------
@@ -139,13 +141,8 @@
 	 */
 	public function trans_begin($test_mode = FALSE)
 	{
-		if ( ! $this->trans_enabled)
-		{
-			return TRUE;
-		}
-
 		// When transactions are nested we only begin/commit/rollback the outermost ones
-		if ($this->_trans_depth > 0)
+		if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
 		{
 			return TRUE;
 		}
@@ -153,7 +150,7 @@
 		// Reset the transaction failure flag.
 		// If the $test_mode flag is set to TRUE transactions will be rolled back
 		// even if the queries produce a successful result.
-		$this->_trans_failure = ($test_mode === TRUE) ? TRUE : FALSE;
+		$this->_trans_failure = ($test_mode === TRUE);
 
 		$this->simple_query('BEGIN TRANSACTION');
 		return TRUE;
@@ -168,13 +165,8 @@
 	 */
 	public function trans_commit()
 	{
-		if ( ! $this->trans_enabled)
-		{
-			return TRUE;
-		}
-
 		// When transactions are nested we only begin/commit/rollback the outermost ones
-		if ($this->_trans_depth > 0)
+		if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
 		{
 			return TRUE;
 		}
@@ -192,13 +184,8 @@
 	 */
 	public function trans_rollback()
 	{
-		if ( ! $this->trans_enabled)
-		{
-			return TRUE;
-		}
-
 		// When transactions are nested we only begin/commit/rollback the outermost ones
-		if ($this->_trans_depth > 0)
+		if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
 		{
 			return TRUE;
 		}
@@ -277,12 +264,13 @@
 	 */
 	protected function _list_tables($prefix_limit = FALSE)
 	{
-		$sql = "SELECT name from sqlite_master WHERE type='table'";
+		$sql = "SELECT name FROM sqlite_master WHERE type='table'";
 
 		if ($prefix_limit !== FALSE && $this->dbprefix != '')
 		{
-			$sql .= " AND 'name' LIKE '".$this->escape_like_str($this->dbprefix)."%' ".sprintf($this->_like_escape_str, $this->_like_escape_chr);
+			return $sql." AND 'name' LIKE '".$this->escape_like_str($this->dbprefix)."%' ".sprintf($this->_like_escape_str, $this->_like_escape_chr);
 		}
+
 		return $sql;
 	}
 
@@ -314,7 +302,7 @@
 	 */
 	protected function _field_data($table)
 	{
-		return "SELECT * FROM ".$table." LIMIT 1";
+		return 'SELECT * FROM '.$this->escape_identifiers($table).' LIMIT 1';
 	}
 
 	// --------------------------------------------------------------------
@@ -337,27 +325,6 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 * From Tables
-	 *
-	 * This function implicitly groups FROM tables so there is no confusion
-	 * about operator precedence in harmony with SQL standards
-	 *
-	 * @param	array
-	 * @return	string
-	 */
-	protected function _from_tables($tables)
-	{
-		if ( ! is_array($tables))
-		{
-			$tables = array($tables);
-		}
-
-		return '('.implode(', ', $tables).')';
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
 	 * Replace statement
 	 *
 	 * Generates a platform-specific replace string from the supplied data
@@ -404,16 +371,7 @@
 	 */
 	protected function _limit($sql, $limit, $offset)
 	{
-		if ($offset == 0)
-		{
-			$offset = '';
-		}
-		else
-		{
-			$offset .= ', ';
-		}
-
-		return $sql.'LIMIT '.$offset.$limit;
+		return $sql.'LIMIT '.($offset == 0 ? '' : $offset.', ').$limit;
 	}
 
 	// --------------------------------------------------------------------
diff --git a/system/database/drivers/sqlite/sqlite_forge.php b/system/database/drivers/sqlite/sqlite_forge.php
index 35be1b7..e02e327 100644
--- a/system/database/drivers/sqlite/sqlite_forge.php
+++ b/system/database/drivers/sqlite/sqlite_forge.php
@@ -61,6 +61,14 @@
 		{
 			return ($this->db->db_debug) ? $this->db->display_error('db_unable_to_drop') : FALSE;
 		}
+		elseif ( ! empty($this->db->data_cache['db_names']))
+		{
+			$key = array_search(strtolower($this->db->database), array_map('strtolower', $this->db->data_cache['db_names']), TRUE);
+			if ($key !== FALSE)
+			{
+				unset($this->db->data_cache['db_names'][$key]);
+			}
+		}
 
 		return TRUE;
 	}
@@ -97,41 +105,31 @@
 			// entered the field information, so we'll simply add it to the list
 			if (is_numeric($field))
 			{
-				$sql .= "\n\t$attributes";
+				$sql .= "\n\t".$attributes;
 			}
 			else
 			{
 				$attributes = array_change_key_case($attributes, CASE_UPPER);
 
-				$sql .= "\n\t".$this->db->protect_identifiers($field);
+				$sql .= "\n\t".$this->db->escape_identifiers($field).' '.$attributes['TYPE'];
 
-				$sql .=  ' '.$attributes['TYPE'];
+				empty($attributes['CONSTRAINT']) OR $sql .= '('.$attributes['CONSTRAINT'].')';
 
-				if (array_key_exists('CONSTRAINT', $attributes))
-				{
-					$sql .= '('.$attributes['CONSTRAINT'].')';
-				}
-
-				if (array_key_exists('UNSIGNED', $attributes) && $attributes['UNSIGNED'] === TRUE)
+				if ( ! empty($attributes['UNSIGNED']) && $attributes['UNSIGNED'] === TRUE)
 				{
 					$sql .= ' UNSIGNED';
 				}
 
-				if (array_key_exists('DEFAULT', $attributes))
+				if (isset($attributes['DEFAULT']))
 				{
-					$sql .= ' DEFAULT \''.$attributes['DEFAULT'].'\'';
+					$sql .= " DEFAULT '".$attributes['DEFAULT']."'";
 				}
 
-				if (array_key_exists('NULL', $attributes) && $attributes['NULL'] === TRUE)
-				{
-					$sql .= ' NULL';
-				}
-				else
-				{
-					$sql .= ' NOT NULL';
-				}
 
-				if (array_key_exists('AUTO_INCREMENT', $attributes) && $attributes['AUTO_INCREMENT'] === TRUE)
+				$sql .= ( ! empty($attributes['NULL']) && $attributes['NULL'] === TRUE)
+					? ' NULL' : ' NOT NULL';
+
+				if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE)
 				{
 					$sql .= ' AUTO_INCREMENT';
 				}
@@ -146,30 +144,22 @@
 
 		if (count($primary_keys) > 0)
 		{
-			$primary_keys = $this->db->protect_identifiers($primary_keys);
-			$sql .= ",\n\tPRIMARY KEY (" . implode(', ', $primary_keys) . ")";
+			$sql .= ",\n\tPRIMARY KEY (".implode(', ', $this->db->escape_identifiers($primary_keys)).')';
 		}
 
 		if (is_array($keys) && count($keys) > 0)
 		{
 			foreach ($keys as $key)
 			{
-				if (is_array($key))
-				{
-					$key = $this->db->protect_identifiers($key);
-				}
-				else
-				{
-					$key = array($this->db->protect_identifiers($key));
-				}
+				$key = is_array($key)
+					? $this->db->escape_identifiers($key)
+					: array($this->db->escape_identifiers($key));
 
-				$sql .= ",\n\tUNIQUE (" . implode(', ', $key) . ")";
+				$sql .= ",\n\tUNIQUE (".implode(', ', $key).')';
 			}
 		}
 
-		$sql .= "\n)";
-
-		return $sql;
+		return $sql."\n)";
 	}
 
 	// --------------------------------------------------------------------
@@ -191,40 +181,21 @@
 	 */
 	protected function _alter_table($alter_type, $table, $column_name, $column_definition = '', $default_value = '', $null = '', $after_field = '')
 	{
-		$sql = 'ALTER TABLE '.$this->db->protect_identifiers($table).' '.$alter_type.' '.$this->db->protect_identifiers($column_name);
-
-		// DROP has everything it needs now.
-		if ($alter_type === 'DROP')
+		/* SQLite only supports adding new columns and it does
+		 * NOT support the AFTER statement. Each new column will
+		 * be added as the last one in the table.
+		 */
+		if ($alter_type !== 'ADD COLUMN')
 		{
-			// SQLite does not support dropping columns
-			// http://www.sqlite.org/omitted.html
-			// http://www.sqlite.org/faq.html#q11
+			// Not supported
 			return FALSE;
 		}
 
-		$sql .= " $column_definition";
-
-		if ($default_value !== '')
-		{
-			$sql .= " DEFAULT \"$default_value\"";
-		}
-
-		if ($null === NULL)
-		{
-			$sql .= ' NULL';
-		}
-		else
-		{
-			$sql .= ' NOT NULL';
-		}
-
-		if ($after_field !== '')
-		{
-			return $sql.' AFTER '.$this->db->protect_identifiers($after_field);
-		}
-
-		return $sql;
-
+		return 'ALTER TABLE '.$this->db->escape_identifiers($table).' '.$alter_type.' '.$this->db->escape_identifiers($column_name)
+			.' '.$column_definition
+			.($default_value != '' ? " DEFAULT '".$default_value."'" : '')
+			// If NOT NULL is specified, the field must have a DEFAULT value other than NULL
+			.(($null !== NULL && $default_value !== 'NULL') ? ' NOT NULL' : ' NULL');
 	}
 
 }
diff --git a/system/database/drivers/sqlite3/sqlite3_driver.php b/system/database/drivers/sqlite3/sqlite3_driver.php
index 2acefbc..bed6189 100644
--- a/system/database/drivers/sqlite3/sqlite3_driver.php
+++ b/system/database/drivers/sqlite3/sqlite3_driver.php
@@ -318,27 +318,6 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 * From Tables
-	 *
-	 * This function implicitly groups FROM tables so there is no confusion
-	 * about operator precedence in harmony with SQL standards
-	 *
-	 * @param	string
-	 * @return	string
-	 */
-	protected function _from_tables($tables)
-	{
-		if ( ! is_array($tables))
-		{
-			$tables = array($tables);
-		}
-
-		return '('.implode(', ', $tables).')';
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
 	 * Replace statement
 	 *
 	 * Generates a platform-specific replace string from the supplied data
diff --git a/system/database/drivers/sqlite3/sqlite3_forge.php b/system/database/drivers/sqlite3/sqlite3_forge.php
index 0a5dc92..6a76ba9 100644
--- a/system/database/drivers/sqlite3/sqlite3_forge.php
+++ b/system/database/drivers/sqlite3/sqlite3_forge.php
@@ -66,6 +66,14 @@
 			{
 				return $this->db->db_debug ? $this->db->display_error('db_unable_to_drop') : FALSE;
 			}
+			elseif ( ! empty($this->db->data_cache['db_names']))
+			{
+				$key = array_search(strtolower($this->db->database), array_map('strtolower', $this->db->data_cache['db_names']), TRUE);
+				if ($key !== FALSE)
+				{
+					unset($this->db->data_cache['db_names'][$key]);
+				}
+			}
 
 			return TRUE;
 		}
@@ -111,13 +119,27 @@
 			{
 				$attributes = array_change_key_case($attributes, CASE_UPPER);
 
-				$sql .= "\n\t".$this->db->protect_identifiers($field)
-					.' '.$attributes['TYPE']
-					.( ! empty($attributes['CONSTRAINT']) ? '('.$attributes['CONSTRAINT'].')' : '')
-					.(( ! empty($attributes['UNSIGNED']) && $attributes['UNSIGNED'] === TRUE) ? ' UNSIGNED' : '')
-					.(isset($attributes['DEFAULT']) ? ' DEFAULT \''.$attributes['DEFAULT'].'\'' : '')
-					.(( ! empty($attributes['NULL']) && $attributes['NULL'] === TRUE) ? ' NULL' : ' NOT NULL')
-					.(( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE) ? ' AUTO_INCREMENT' : '');
+				$sql .= "\n\t".$this->db->escape_identifiers($field).' '.$attributes['TYPE'];
+
+				empty($attributes['CONSTRAINT']) OR $sql .= '('.$attributes['CONSTRAINT'].')';
+
+				if ( ! empty($attributes['UNSIGNED']) && $attributes['UNSIGNED'] === TRUE)
+				{
+					$sql .= ' UNSIGNED';
+				}
+
+				if (isset($attributes['DEFAULT']))
+				{
+					$sql .= " DEFAULT '".$attributes['DEFAULT']."'";
+				}
+
+				$sql .= ( ! empty($attributes['NULL']) && $attributes['NULL'] === TRUE)
+					? ' NULL' : ' NOT NULL';
+
+				if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE)
+				{
+					$sql .= ' AUTO_INCREMENT';
+				}
 			}
 
 			// don't add a comma on the end of the last field
@@ -129,22 +151,16 @@
 
 		if (count($primary_keys) > 0)
 		{
-			$primary_keys = $this->db->protect_identifiers($primary_keys);
-			$sql .= ",\n\tPRIMARY KEY (".implode(', ', $primary_keys).')';
+			$sql .= ",\n\tPRIMARY KEY (".implode(', ', $this->db->escape_identifiers($primary_keys)).')';
 		}
 
 		if (is_array($keys) && count($keys) > 0)
 		{
 			foreach ($keys as $key)
 			{
-				if (is_array($key))
-				{
-					$key = $this->db->protect_identifiers($key);
-				}
-				else
-				{
-					$key = array($this->db->protect_identifiers($key));
-				}
+				$key = is_array($key)
+					? $this->db->escape_identifiers($key)
+					: array($this->db->escape_identifiers($key));
 
 				$sql .= ",\n\tUNIQUE (".implode(', ', $key).')';
 			}
@@ -182,7 +198,7 @@
 			return FALSE;
 		}
 
-		return 'ALTER TABLE '.$this->db->protect_identifiers($table).' '.$alter_type.' '.$this->db->protect_identifiers($column_name)
+		return 'ALTER TABLE '.$this->db->escape_identifiers($table).' '.$alter_type.' '.$this->db->escape_identifiers($column_name)
 			.' '.$column_definition
 			.($default_value !== '' ? ' DEFAULT '.$default_value : '')
 			// If NOT NULL is specified, the field must have a DEFAULT value other than NULL
diff --git a/system/database/drivers/sqlsrv/sqlsrv_driver.php b/system/database/drivers/sqlsrv/sqlsrv_driver.php
index 961066d..825c024 100644
--- a/system/database/drivers/sqlsrv/sqlsrv_driver.php
+++ b/system/database/drivers/sqlsrv/sqlsrv_driver.php
@@ -21,7 +21,7 @@
  * @copyright	Copyright (c) 2008 - 2012, 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
+ * @since		Version 2.0.3
  * @filesource
  */
 
@@ -43,7 +43,7 @@
 	public $dbdriver = 'sqlsrv';
 
 	// The character used for escaping
-	protected $_escape_char = '';
+	protected $_escape_char = '"';
 
 	// clause and character used for LIKE escape sequences
 	protected $_like_escape_str = " ESCAPE '%s' ";
@@ -55,7 +55,10 @@
 	 * used for the count_all() and count_all_results() functions.
 	 */
 	protected $_count_string = 'SELECT COUNT(*) AS ';
-	protected $_random_keyword = ' NEWID()'; // not currently supported
+	protected $_random_keyword = ' NEWID()';
+
+	// SQLSRV-specific properties
+	protected $_quoted_identifier = TRUE;
 
 	/**
 	 * Non-persistent database connection
@@ -83,7 +86,15 @@
 			unset($connection['UID'], $connection['PWD']);
 		}
 
-		return sqlsrv_connect($this->hostname, $connection);
+		$conn_id = sqlsrv_connect($this->hostname, $connection);
+
+		// Determine how identifiers are escaped
+		$query = $this->query('SELECT CASE WHEN (@@OPTIONS | 256) = @@OPTIONS THEN 1 ELSE 0 END AS qi');
+		$query = $query->row_array();
+		$this->_quoted_identifier = empty($query) ? FALSE : (bool) $query->qi;
+		$this->_escape_char = ($this->_quoted_identifier) ? '"' : array('[', ']');
+
+		return $conn_id;
 	}
 
 	// --------------------------------------------------------------------
@@ -146,13 +157,8 @@
 	 */
 	public function trans_begin($test_mode = FALSE)
 	{
-		if ( ! $this->trans_enabled)
-		{
-			return TRUE;
-		}
-
 		// When transactions are nested we only begin/commit/rollback the outermost ones
-		if ($this->_trans_depth > 0)
+		if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
 		{
 			return TRUE;
 		}
@@ -160,7 +166,7 @@
 		// Reset the transaction failure flag.
 		// If the $test_mode flag is set to TRUE transactions will be rolled back
 		// even if the queries produce a successful result.
-		$this->_trans_failure = ($test_mode === TRUE) ? TRUE : FALSE;
+		$this->_trans_failure = ($test_mode === TRUE);
 
 		return sqlsrv_begin_transaction($this->conn_id);
 	}
@@ -174,13 +180,8 @@
 	 */
 	public function trans_commit()
 	{
-		if ( ! $this->trans_enabled)
-		{
-			return TRUE;
-		}
-
 		// When transactions are nested we only begin/commit/rollback the outermost ones
-		if ($this->_trans_depth > 0)
+		if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
 		{
 			return TRUE;
 		}
@@ -197,13 +198,8 @@
 	 */
 	public function trans_rollback()
 	{
-		if ( ! $this->trans_enabled)
-		{
-			return TRUE;
-		}
-
 		// When transactions are nested we only begin/commit/rollback the outermost ones
-		if ($this->_trans_depth > 0)
+		if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
 		{
 			return TRUE;
 		}
@@ -372,12 +368,7 @@
 	 */
 	protected function _from_tables($tables)
 	{
-		if ( ! is_array($tables))
-		{
-			$tables = array($tables);
-		}
-
-		return implode(', ', $tables);
+		return is_array($tables) ? implode(', ', $tables) : $tables;
 	}
 
 	// --------------------------------------------------------------------
@@ -397,7 +388,7 @@
 	 */
 	protected function _update($table, $values, $where, $orderby = array(), $limit = FALSE, $like = array())
 	{
-		foreach($values as $key => $val)
+		foreach ($values as $key => $val)
 		{
 			$valstr[] = $key.' = '.$val;
 		}
@@ -471,7 +462,29 @@
 	 */
 	protected function _limit($sql, $limit, $offset)
 	{
-		return preg_replace('/(^\SELECT (DISTINCT)?)/i','\\1 TOP '.($limit + $offset).' ', $sql);
+		// As of SQL Server 2012 (11.0.*) OFFSET is supported
+		if (version_compare($this->version(), '11', '>='))
+		{
+			return $sql.' OFFSET '.(int) $offset.' ROWS FETCH NEXT '.(int) $limit.' ROWS ONLY';
+		}
+
+		$limit = $offset + $limit;
+
+		// An ORDER BY clause is required for ROW_NUMBER() to work
+		if ($offset && ! empty($this->qb_orderby))
+		{
+			$orderby = 'ORDER BY '.implode(', ', $this->qb_orderby);
+
+			// We have to strip the ORDER BY clause
+			$sql = trim(substr($sql, 0, strrpos($sql, 'ORDER BY '.$orderby)));
+
+			return 'SELECT '.(count($this->qb_select) === 0 ? '*' : implode(', ', $this->qb_select))." FROM (\n"
+				.preg_replace('/^(SELECT( DISTINCT)?)/i', '\\1 ROW_NUMBER() OVER('.$orderby.') AS '.$this->escape_identifiers('CI_rownum').', ', $sql)
+				."\n) ".$this->escape_identifiers('CI_subquery')
+				."\nWHERE ".$this->escape_identifiers('CI_rownum').' BETWEEN '.((int) $offset + 1).' AND '.$limit;
+		}
+
+		return preg_replace('/(^\SELECT (DISTINCT)?)/i','\\1 TOP '.$limit.' ', $sql);
 	}
 
 	// --------------------------------------------------------------------
diff --git a/system/database/drivers/sqlsrv/sqlsrv_forge.php b/system/database/drivers/sqlsrv/sqlsrv_forge.php
index 1529b2a..ccdb369 100644
--- a/system/database/drivers/sqlsrv/sqlsrv_forge.php
+++ b/system/database/drivers/sqlsrv/sqlsrv_forge.php
@@ -21,7 +21,7 @@
  * @copyright	Copyright (c) 2008 - 2012, 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
+ * @since		Version 2.0.3
  * @filesource
  */
 
@@ -44,7 +44,7 @@
 	 * @param	mixed	primary key(s)
 	 * @param	mixed	key(s)
 	 * @param	bool	should 'IF NOT EXISTS' be added to the SQL
-	 * @return	bool
+	 * @return	string
 	 */
 	protected function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists)
 	{
@@ -70,31 +70,25 @@
 
 				$sql .= "\n\t".$this->db->escape_identifiers($field).' '.$attributes['TYPE'];
 
-				if (array_key_exists('CONSTRAINT', $attributes))
+				if (stripos($attributes['TYPE'], 'INT') === FALSE && ! empty($attributes['CONSTRAINT']))
 				{
 					$sql .= '('.$attributes['CONSTRAINT'].')';
 				}
 
-				if (array_key_exists('UNSIGNED', $attributes) && $attributes['UNSIGNED'] === TRUE)
+				if ( ! empty($attributes['UNSIGNED']) && $attributes['UNSIGNED'] === TRUE)
 				{
 					$sql .= ' UNSIGNED';
 				}
 
-				if (array_key_exists('DEFAULT', $attributes))
+				if (isset($attributes['DEFAULT']))
 				{
-					$sql .= ' DEFAULT \''.$attributes['DEFAULT'].'\'';
+					$sql .= " DEFAULT '".$attributes['DEFAULT']."'";
 				}
 
-				if (array_key_exists('NULL', $attributes) && $attributes['NULL'] === TRUE)
-				{
-					$sql .= ' NULL';
-				}
-				else
-				{
-					$sql .= ' NOT NULL';
-				}
+				$sql .= ( ! empty($attributes['NULL']) && $attribues['NULL'] === TRUE)
+					? ' NULL' : ' NOT NULL';
 
-				if (array_key_exists('AUTO_INCREMENT', $attributes) && $attributes['AUTO_INCREMENT'] === TRUE)
+				if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE)
 				{
 					$sql .= ' AUTO_INCREMENT';
 				}
@@ -109,22 +103,16 @@
 
 		if (count($primary_keys) > 0)
 		{
-			$primary_keys = $this->db->protect_identifiers($primary_keys);
-			$sql .= ",\n\tPRIMARY KEY (".implode(', ', $primary_keys).')';
+			$sql .= ",\n\tPRIMARY KEY (".implode(', ', $this->db->escape_identifiers($primary_keys)).')';
 		}
 
 		if (is_array($keys) && count($keys) > 0)
 		{
 			foreach ($keys as $key)
 			{
-				if (is_array($key))
-				{
-					$key = $this->db->protect_identifiers($key);
-				}
-				else
-				{
-					$key = array($this->db->protect_identifiers($key));
-				}
+				$key = is_array($key)
+					? $this->db->escape_identifiers($key)
+					: array($this->escape_identifiers($key));
 
 				$sql .= ",\n\tFOREIGN KEY (".implode(', ', $key).')';
 			}
@@ -152,7 +140,7 @@
 	 */
 	protected function _alter_table($alter_type, $table, $column_name, $column_definition = '', $default_value = '', $null = '', $after_field = '')
 	{
-		$sql = 'ALTER TABLE '.$this->db->protect_identifiers($table).' '.$alter_type.' '.$this->db->protect_identifiers($column_name);
+		$sql = 'ALTER TABLE '.$this->db->escape_identifiers($table).' '.$alter_type.' '.$this->db->escape_identifiers($column_name);
 
 		// DROP has everything it needs now.
 		if ($alter_type === 'DROP')
@@ -160,21 +148,10 @@
 			return $sql;
 		}
 
-		$sql .= ' '.$column_definition;
-
-		if ($default_value !== '')
-		{
-			$sql .= " DEFAULT '".$default_value."'";
-		}
-
-		$sql .= ($null === NULL) ? ' NULL' : ' NOT NULL';
-
-		if ($after_field !== '')
-		{
-			return $sql.' AFTER '.$this->db->protect_identifiers($after_field);
-		}
-
-		return $sql;
+		return $sql.' '.$column_definition
+			.($default_value != '' ? ' DEFAULT "'.$default_value.'"' : '')
+			.($null === NULL ? ' NULL' : ' NOT NULL')
+			.($after_field != '' ? ' AFTER '.$this->db->escape_identifiers($after_field) : '');
 	}
 
 }
diff --git a/system/database/drivers/sqlsrv/sqlsrv_result.php b/system/database/drivers/sqlsrv/sqlsrv_result.php
index 0802677..f9d5a0d 100644
--- a/system/database/drivers/sqlsrv/sqlsrv_result.php
+++ b/system/database/drivers/sqlsrv/sqlsrv_result.php
@@ -21,7 +21,7 @@
  * @copyright	Copyright (c) 2008 - 2012, 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
+ * @since		Version 2.0.3
  * @filesource
  */
 
@@ -92,12 +92,12 @@
 		$retval = array();
 		foreach (sqlsrv_field_metadata($this->result_id) as $offset => $field)
 		{
-			$F 				= new stdClass();
-			$F->name 		= $field['Name'];
-			$F->type 		= $field['Type'];
+			$F 		= new stdClass();
+			$F->name 	= $field['Name'];
+			$F->type 	= $field['Type'];
 			$F->max_length	= $field['Size'];
 			$F->primary_key = 0;
-			$F->default		= '';
+			$F->default	= '';
 
 			$retval[] = $F;
 		}
diff --git a/system/database/drivers/sqlsrv/sqlsrv_utility.php b/system/database/drivers/sqlsrv/sqlsrv_utility.php
index 394964b..d518cc1 100644
--- a/system/database/drivers/sqlsrv/sqlsrv_utility.php
+++ b/system/database/drivers/sqlsrv/sqlsrv_utility.php
@@ -21,7 +21,7 @@
  * @copyright	Copyright (c) 2008 - 2012, 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
+ * @since		Version 2.0.3
  * @filesource
  */
 
@@ -41,7 +41,7 @@
 	 * SQLSRV Export
 	 *
 	 * @param	array	Preferences
-	 * @return	mixed
+	 * @return	bool
 	 */
 	protected function _backup($params = array())
 	{
diff --git a/system/helpers/date_helper.php b/system/helpers/date_helper.php
index c601dc9..077a671 100644
--- a/system/helpers/date_helper.php
+++ b/system/helpers/date_helper.php
@@ -42,29 +42,28 @@
 	/**
 	 * Get "now" time
 	 *
-	 * Returns time() or its GMT equivalent based on the config file preference
+	 * Returns time() based on the timezone parameter or on the
+	 * "time_reference" setting
 	 *
+	 * @param	string
 	 * @return	int
 	 */
-	function now()
+	function now($timezone = NULL)
 	{
-		$CI =& get_instance();
-
-		if (strtolower($CI->config->item('time_reference')) === 'gmt')
+		if (empty($timezone))
 		{
-			$now = time();
-			$system_time = mktime(gmdate("H", $now), gmdate("i", $now), gmdate("s", $now), gmdate("m", $now), gmdate("d", $now), gmdate("Y", $now));
-
-			if (strlen($system_time) < 10)
-			{
-				$system_time = time();
-				log_message('error', 'The Date class could not set a proper GMT timestamp so the local time() value was used.');
-			}
-
-			return $system_time;
+			$timezone = config_item('time_reference');
 		}
 
-		return time();
+		if ($timezone === 'local' OR $timezone === date_default_timezone_get())
+		{
+			return time();
+		}
+
+		$datetime = new DateTime('now', new DateTimeZone($timezone));
+		sscanf($datetime->format('j-n-Y G:i:s'), '%d-%d-%d %d:%d:%d', $day, $month, $year, $hour, $minute, $second);
+
+		return mktime($hour, $minute, $second, $month, $day, $year);
 	}
 }
 
@@ -94,8 +93,10 @@
 		{
 			return '';
 		}
-
-		$time = ($time === '') ? now() : $time;
+		elseif (empty($time))
+		{
+			$time = now();
+		}
 
 		$datestr = str_replace(
 			'%\\',
@@ -123,24 +124,19 @@
 	function standard_date($fmt = 'DATE_RFC822', $time = '')
 	{
 		$formats = array(
-						'DATE_ATOM'		=>	'%Y-%m-%dT%H:%i:%s%O',
-						'DATE_COOKIE'	=>	'%l, %d-%M-%y %H:%i:%s UTC',
-						'DATE_ISO8601'	=>	'%Y-%m-%dT%H:%i:%s%O',
-						'DATE_RFC822'	=>	'%D, %d %M %y %H:%i:%s %O',
-						'DATE_RFC850'	=>	'%l, %d-%M-%y %H:%i:%s UTC',
-						'DATE_RFC1036'	=>	'%D, %d %M %y %H:%i:%s %O',
-						'DATE_RFC1123'	=>	'%D, %d %M %Y %H:%i:%s %O',
-						'DATE_RFC2822'	=>	'%D, %d %M %Y %H:%i:%s %O',
-						'DATE_RSS'		=>	'%D, %d %M %Y %H:%i:%s %O',
-						'DATE_W3C'		=>	'%Y-%m-%dT%H:%i:%s%O'
-						);
+				'DATE_ATOM'		=>	'%Y-%m-%dT%H:%i:%s%O',
+				'DATE_COOKIE'	=>	'%l, %d-%M-%y %H:%i:%s UTC',
+				'DATE_ISO8601'	=>	'%Y-%m-%dT%H:%i:%s%O',
+				'DATE_RFC822'	=>	'%D, %d %M %y %H:%i:%s %O',
+				'DATE_RFC850'	=>	'%l, %d-%M-%y %H:%i:%s UTC',
+				'DATE_RFC1036'	=>	'%D, %d %M %y %H:%i:%s %O',
+				'DATE_RFC1123'	=>	'%D, %d %M %Y %H:%i:%s %O',
+				'DATE_RFC2822'	=>	'%D, %d %M %Y %H:%i:%s %O',
+				'DATE_RSS'		=>	'%D, %d %M %Y %H:%i:%s %O',
+				'DATE_W3C'		=>	'%Y-%m-%dT%H:%i:%s%O'
+				);
 
-		if ( ! isset($formats[$fmt]))
-		{
-			return FALSE;
-		}
-
-		return mdate($formats[$fmt], $time);
+		return isset($formats[$fmt]) ? mdate($formats[$fmt], $time) : FALSE;
 	}
 }
 
@@ -164,20 +160,9 @@
 		$CI =& get_instance();
 		$CI->lang->load('date');
 
-		if ( ! is_numeric($seconds))
-		{
-			$seconds = 1;
-		}
-
-		if ( ! is_numeric($time))
-		{
-			$time = time();
-		}
-
-		if ( ! is_numeric($units))
-		{
-			$units = 7;
-		}
+		is_numeric($seconds) OR $seconds = 1;
+		is_numeric($time) OR $time = time();
+		is_numeric($units) OR $units = 7;
 
 		$seconds = ($time <= $seconds) ? 1 : $time - $seconds;
 
@@ -186,7 +171,7 @@
 
 		if ($years > 0)
 		{
-			$str[] = $years.' '.$CI->lang->line((($years	> 1) ? 'date_years' : 'date_year'));
+			$str[] = $years.' '.$CI->lang->line($years > 1 ? 'date_years' : 'date_year');
 		}
 
 		$seconds -= $years * 31557600;
@@ -196,7 +181,7 @@
 		{
 			if ($months > 0)
 			{
-				$str[] = $months.' '.$CI->lang->line((($months	> 1) ? 'date_months' : 'date_month'));
+				$str[] = $months.' '.$CI->lang->line($months > 1 ? 'date_months' : 'date_month');
 			}
 
 			$seconds -= $months * 2629743;
@@ -208,7 +193,7 @@
 		{
 			if ($weeks > 0)
 			{
-				$str[] = $weeks.' '.$CI->lang->line((($weeks	> 1) ? 'date_weeks' : 'date_week'));
+				$str[] = $weeks.' '.$CI->lang->line($weeks > 1 ? 'date_weeks' : 'date_week');
 			}
 
 			$seconds -= $weeks * 604800;
@@ -220,7 +205,7 @@
 		{
 			if ($days > 0)
 			{
-				$str[] = $days.' '.$CI->lang->line((($days	> 1) ? 'date_days' : 'date_day'));
+				$str[] = $days.' '.$CI->lang->line($days > 1 ? 'date_days' : 'date_day');
 			}
 
 			$seconds -= $days * 86400;
@@ -232,7 +217,7 @@
 		{
 			if ($hours > 0)
 			{
-				$str[] = $hours.' '.$CI->lang->line((($hours	> 1) ? 'date_hours' : 'date_hour'));
+				$str[] = $hours.' '.$CI->lang->line($hours > 1 ? 'date_hours' : 'date_hour');
 			}
 
 			$seconds -= $hours * 3600;
@@ -244,7 +229,7 @@
 		{
 			if ($minutes > 0)
 			{
-				$str[] = $minutes.' '.$CI->lang->line((($minutes	> 1) ? 'date_minutes' : 'date_minute'));
+				$str[] = $minutes.' '.$CI->lang->line($minutes > 1 ? 'date_minutes' : 'date_minute');
 			}
 
 			$seconds -= $minutes * 60;
@@ -252,7 +237,7 @@
 
 		if (count($str) === 0)
 		{
-			$str[] = $seconds.' '.$CI->lang->line((($seconds	> 1) ? 'date_seconds' : 'date_second'));
+			$str[] = $seconds.' '.$CI->lang->line($seconds > 1 ? 'date_seconds' : 'date_second');
 		}
 
 		return implode(', ', $str);
@@ -279,12 +264,16 @@
 		{
 			return 0;
 		}
-
-		if ( ! is_numeric($year) OR strlen($year) !== 4)
+		elseif ( ! is_numeric($year) OR strlen($year) !== 4)
 		{
 			$year = date('Y');
 		}
 
+		if ($year >= 1970)
+		{
+			return (int) date('t', mktime(12, 0, 0, $month, 1, $year));
+		}
+
 		if ($month == 2)
 		{
 			if ($year % 400 === 0 OR ($year % 4 === 0 && $year % 100 !== 0))
@@ -315,13 +304,13 @@
 			$time = time();
 		}
 
-		return mktime(
-			gmdate('H', $time),
-			gmdate('i', $time),
-			gmdate('s', $time),
-			gmdate('m', $time),
-			gmdate('d', $time),
-			gmdate('Y', $time)
+		return gmmktime(
+			date('G', $time),
+			date('i', $time),
+			date('s', $time),
+			date('n', $time),
+			date('j', $time),
+			date('Y', $time)
 		);
 	}
 }
@@ -351,12 +340,7 @@
 
 		$time += timezones($timezone) * 3600;
 
-		if ($dst === TRUE)
-		{
-			$time += 3600;
-		}
-
-		return $time;
+		return ($dst === TRUE) ? $time + 3600 : $time;
 	}
 }
 
@@ -376,9 +360,7 @@
 		// since the formatting changed with MySQL 4.1
 		// YYYY-MM-DD HH:MM:SS
 
-		$time = str_replace('-', '', $time);
-		$time = str_replace(':', '', $time);
-		$time = str_replace(' ', '', $time);
+		$time = str_replace(array('-', ':', ' '), '', $time);
 
 		// YYYYMMDDHHMMSS
 		return mktime(
@@ -408,7 +390,7 @@
 	 */
 	function unix_to_human($time = '', $seconds = FALSE, $fmt = 'us')
 	{
-		$r  = date('Y', $time).'-'.date('m', $time).'-'.date('d', $time).' ';
+		$r = date('Y', $time).'-'.date('m', $time).'-'.date('d', $time).' ';
 
 		if ($fmt === 'us')
 		{
@@ -426,7 +408,7 @@
 
 		if ($fmt === 'us')
 		{
-			$r .= ' '.date('A', $time);
+			return $r.' '.date('A', $time);
 		}
 
 		return $r;
@@ -454,51 +436,33 @@
 
 		$datestr = preg_replace('/\040+/', ' ', trim($datestr));
 
-		if ( ! preg_match('/^[0-9]{2,4}\-[0-9]{1,2}\-[0-9]{1,2}\s[0-9]{1,2}:[0-9]{1,2}(?::[0-9]{1,2})?(?:\s[AP]M)?$/i', $datestr))
+		if ( ! preg_match('/^(\d{2}|\d{4})\-[0-9]{1,2}\-[0-9]{1,2}\s[0-9]{1,2}:[0-9]{1,2}(?::[0-9]{1,2})?(?:\s[AP]M)?$/i', $datestr))
 		{
 			return FALSE;
 		}
 
 		$split = explode(' ', $datestr);
 
-		$ex = explode('-', $split['0']);
-
-		$year  = (strlen($ex[0]) === 2) ? '20'.$ex[0] : $ex[0];
-		$month = (strlen($ex[1]) === 1) ? '0'.$ex[1]  : $ex[1];
-		$day   = (strlen($ex[2]) === 1) ? '0'.$ex[2]  : $ex[2];
+		list($year, $month, $day) = explode('-', $split[0]);
 
 		$ex = explode(':', $split['1']);
 
-		$hour = (strlen($ex[0]) === 1) ? '0'.$ex[0] : $ex[0];
-		$min  = (strlen($ex[1]) === 1) ? '0'.$ex[1] : $ex[1];
-
-		if (isset($ex[2]) && preg_match('/[0-9]{1,2}/', $ex[2]))
-		{
-			$sec = (strlen($ex[2]) === 1) ? '0'.$ex[2] : $ex[2];
-		}
-		else
-		{
-			// Unless specified, seconds get set to zero.
-			$sec = '00';
-		}
+		$hour	= (int) $ex[0];
+		$min	= (int) $ex[1];
+		$sec	= ( ! empty($ex[2]) && preg_match('/[0-9]{1,2}/', $ex[2]))
+				? (int) $ex[2] : 0;
 
 		if (isset($split[2]))
 		{
 			$ampm = strtolower($split[2]);
 
-			if (substr($ampm, 0, 1) === 'p' && $hour < 12)
+			if ($ampm[0] === 'p' && $hour < 12)
 			{
 				$hour += 12;
 			}
-
-			if (substr($ampm, 0, 1) === 'a' && $hour == 12)
+			elseif ($ampm[0] === 'a' && $hour === 12)
 			{
-				$hour =  '00';
-			}
-
-			if (strlen($hour) === 1)
-			{
-				$hour = '0'.$hour;
+				$hour = 0;
 			}
 		}
 
@@ -526,7 +490,7 @@
 		}
 
 		// Date like: YYYYMM
-		if (preg_match('/^\d{6}$/', $bad_date))
+		if (preg_match('/^\d{6}$/i', $bad_date))
 		{
 			if (in_array(substr($bad_date, 0, 2), array('19', '20')))
 			{
@@ -543,20 +507,15 @@
 		}
 
 		// Date Like: YYYYMMDD
-		if (preg_match('/^\d{8}$/', $bad_date))
+		if (preg_match('/^(\d{2})\d{2}(\d{4})$/i', $bad_date, $matches))
 		{
-			$month = substr($bad_date, 0, 2);
-			$day   = substr($bad_date, 2, 2);
-			$year  = substr($bad_date, 4, 4);
-
-			return date($format, strtotime($month.'/01/'.$year));
+			return date($format, strtotime($matches[1].'/01/'.$matches[2]));
 		}
 
 		// Date Like: MM-DD-YYYY __or__ M-D-YYYY (or anything in between)
-		if (preg_match('/^\d{1,2}-\d{1,2}-\d{4}$/', $bad_date))
+		if (preg_match('/^(\d{1,2})-(\d{1,2})-(\d{4})$/i', $bad_date, $matches))
 		{
-			list($m, $d, $y) = explode('-', $bad_date);
-			return date($format, strtotime($y.'-'.$m.'-'.$d));
+			return date($format, strtotime($matches[3].'-'.$matches[1].'-'.$matches[2]));
 		}
 
 		// Any other kind of string, when converted into UNIX time,
@@ -678,8 +637,6 @@
 			return $zones;
 		}
 
-		$tz = ($tz === 'GMT') ? 'UTC' : $tz;
-
 		return isset($zones[$tz]) ? $zones[$tz] : 0;
 	}
 }
diff --git a/system/helpers/download_helper.php b/system/helpers/download_helper.php
index 3c67705..5efbc49 100644
--- a/system/helpers/download_helper.php
+++ b/system/helpers/download_helper.php
@@ -73,14 +73,7 @@
 			}
 
 			// Load the mime types
-			if (defined('ENVIRONMENT') && is_file(APPPATH.'config/'.ENVIRONMENT.'/mimes.php'))
-			{
-				$mimes = include(APPPATH.'config/'.ENVIRONMENT.'/mimes.php');
-			}
-			elseif (is_file(APPPATH.'config/mimes.php'))
-			{
-				$mimes = include(APPPATH.'config/mimes.php');
-			}
+			$mimes =& get_mimes();
 
 			// Only change the default MIME if we can find one
 			if (isset($mimes[$extension]))
diff --git a/system/helpers/file_helper.php b/system/helpers/file_helper.php
index 068706c..be616f6 100644
--- a/system/helpers/file_helper.php
+++ b/system/helpers/file_helper.php
@@ -44,38 +44,15 @@
 	 *
 	 * Opens the file specfied in the path and returns it as a string.
 	 *
+	 * This function is DEPRECATED and should be removed in
+	 * CodeIgniter 3.1+. Use file_get_contents() instead.
+	 *
 	 * @param	string	path to file
 	 * @return	string
 	 */
 	function read_file($file)
 	{
-		if ( ! file_exists($file))
-		{
-			return FALSE;
-		}
-
-		if (function_exists('file_get_contents'))
-		{
-			return file_get_contents($file);
-		}
-
-		if ( ! $fp = @fopen($file, FOPEN_READ))
-		{
-			return FALSE;
-		}
-
-		flock($fp, LOCK_SH);
-
-		$data = '';
-		if (filesize($file) > 0)
-		{
-			$data =& fread($fp, filesize($file));
-		}
-
-		flock($fp, LOCK_UN);
-		fclose($fp);
-
-		return $data;
+		return @file_get_contents($file);
 	}
 }
 
@@ -353,32 +330,19 @@
 
 		if ( ! is_array($mimes))
 		{
-			if (defined('ENVIRONMENT') && is_file(APPPATH.'config/'.ENVIRONMENT.'/mimes.php'))
-			{
-				$mimes = include(APPPATH.'config/'.ENVIRONMENT.'/mimes.php');
-			}
-			elseif (is_file(APPPATH.'config/mimes.php'))
-			{
-				$mimes = include(APPPATH.'config/mimes.php');
-			}
+			$mimes =& get_mimes();
 
-			if ( ! is_array($mimes))
+			if (empty($mimes))
 			{
 				return FALSE;
 			}
 		}
 
-		if (array_key_exists($extension, $mimes))
+		if (isset($mimes[$extension]))
 		{
-			if (is_array($mimes[$extension]))
-			{
-				// Multiple mime types, just give the first one
-				return current($mimes[$extension]);
-			}
-			else
-			{
-				return $mimes[$extension];
-			}
+			return is_array($mimes[$extension])
+				? current($mimes[$extension]) // Multiple mime types, just give the first one
+				: $mimes[$extension];
 		}
 
 		return FALSE;
diff --git a/system/helpers/form_helper.php b/system/helpers/form_helper.php
index 4109721..9846343 100644
--- a/system/helpers/form_helper.php
+++ b/system/helpers/form_helper.php
@@ -325,7 +325,10 @@
 			$selected = array($_POST[$name]);
 		}
 
-		if ($extra !== '') $extra = ' '.$extra;
+		if ($extra != '')
+		{
+			$extra = ' '.$extra;
+		}
 
 		$multiple = (count($selected) > 1 && strpos($extra, 'multiple') === FALSE) ? ' multiple="multiple"' : '';
 
@@ -378,7 +381,7 @@
 		{
 			$checked = $data['checked'];
 
-			if ($checked === FALSE)
+			if ($checked == FALSE)
 			{
 				unset($data['checked']);
 			}
@@ -388,7 +391,7 @@
 			}
 		}
 
-		if ($checked === TRUE)
+		if ($checked == TRUE)
 		{
 			$defaults['checked'] = 'checked';
 		}
@@ -702,7 +705,7 @@
 					return '';
 				}
 			}
-			elseif (($field === '' OR $value === '') OR ($field !== $value))
+			elseif (($field == '' OR $value == '') OR $field !== $value)
 			{
 				return '';
 			}
@@ -753,7 +756,7 @@
 					return '';
 				}
 			}
-			elseif (($field === '' OR $value === '') OR ($field !== $value))
+			elseif (($field == '' OR $value == '') OR $field !== $value)
 			{
 				return '';
 			}
@@ -806,7 +809,7 @@
 			}
 			else
 			{
-				if (($field === '' OR $value === '') OR ($field !== $value))
+				if (($field == '' OR $value == '') OR $field !== $value)
 				{
 					return '';
 				}
diff --git a/system/helpers/path_helper.php b/system/helpers/path_helper.php
index 1341054..fec4a1a 100644
--- a/system/helpers/path_helper.php
+++ b/system/helpers/path_helper.php
@@ -55,7 +55,7 @@
 		}
 
 		// Resolve the path
-		if (function_exists('realpath') && @realpath($path) !== FALSE)
+		if (@realpath($path) !== FALSE)
 		{
 			$path = realpath($path);
 		}
diff --git a/system/helpers/security_helper.php b/system/helpers/security_helper.php
index 6187a4a..3e6e914 100644
--- a/system/helpers/security_helper.php
+++ b/system/helpers/security_helper.php
@@ -77,6 +77,9 @@
 	/**
 	 * Hash encode a string
 	 *
+	 * This function is DEPRECATED and should be removed in
+	 * CodeIgniter 3.1+. Use hash() instead.
+	 *
 	 * @param	string
 	 * @param	string
 	 * @return	string
diff --git a/system/language/english/calendar_lang.php b/system/language/english/calendar_lang.php
index 2d477e6..48939d4 100644
--- a/system/language/english/calendar_lang.php
+++ b/system/language/english/calendar_lang.php
@@ -5,9 +5,9 @@
  * 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:
diff --git a/system/language/english/date_lang.php b/system/language/english/date_lang.php
index 5335637..38532b7 100644
--- a/system/language/english/date_lang.php
+++ b/system/language/english/date_lang.php
@@ -5,9 +5,9 @@
  * 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:
diff --git a/system/language/english/db_lang.php b/system/language/english/db_lang.php
index a135d1a..479cbb1 100644
--- a/system/language/english/db_lang.php
+++ b/system/language/english/db_lang.php
@@ -5,9 +5,9 @@
  * 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:
diff --git a/system/language/english/email_lang.php b/system/language/english/email_lang.php
index 23296a2..95a16d1 100644
--- a/system/language/english/email_lang.php
+++ b/system/language/english/email_lang.php
@@ -5,9 +5,9 @@
  * 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:
diff --git a/system/language/english/form_validation_lang.php b/system/language/english/form_validation_lang.php
index 6cf0b46..eb4624e 100644
--- a/system/language/english/form_validation_lang.php
+++ b/system/language/english/form_validation_lang.php
@@ -5,9 +5,9 @@
  * 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:
diff --git a/system/language/english/ftp_lang.php b/system/language/english/ftp_lang.php
index 4e39e43..d00126b 100644
--- a/system/language/english/ftp_lang.php
+++ b/system/language/english/ftp_lang.php
@@ -5,9 +5,9 @@
  * 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:
diff --git a/system/language/english/imglib_lang.php b/system/language/english/imglib_lang.php
index 67ca942..67a36e1 100644
--- a/system/language/english/imglib_lang.php
+++ b/system/language/english/imglib_lang.php
@@ -5,9 +5,9 @@
  * 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:
diff --git a/system/language/english/migration_lang.php b/system/language/english/migration_lang.php
index 2085cee..9e3e188 100644
--- a/system/language/english/migration_lang.php
+++ b/system/language/english/migration_lang.php
@@ -5,9 +5,9 @@
  * 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:
diff --git a/system/language/english/number_lang.php b/system/language/english/number_lang.php
index 0c19ec6..429c647 100644
--- a/system/language/english/number_lang.php
+++ b/system/language/english/number_lang.php
@@ -5,9 +5,9 @@
  * 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:
@@ -25,11 +25,11 @@
  * @filesource
  */
 
-$lang['terabyte_abbr'] = "TB";
-$lang['gigabyte_abbr'] = "GB";
-$lang['megabyte_abbr'] = "MB";
-$lang['kilobyte_abbr'] = "KB";
-$lang['bytes'] = "Bytes";
+$lang['terabyte_abbr'] = 'TB';
+$lang['gigabyte_abbr'] = 'GB';
+$lang['megabyte_abbr'] = 'MB';
+$lang['kilobyte_abbr'] = 'KB';
+$lang['bytes'] = 'Bytes';
 
 /* End of file number_lang.php */
 /* Location: ./system/language/english/number_lang.php */
\ No newline at end of file
diff --git a/system/language/english/profiler_lang.php b/system/language/english/profiler_lang.php
index 11d7912..112527f 100644
--- a/system/language/english/profiler_lang.php
+++ b/system/language/english/profiler_lang.php
@@ -5,9 +5,9 @@
  * 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:
diff --git a/system/language/english/unit_test_lang.php b/system/language/english/unit_test_lang.php
index 3a8e144..36e9aca 100644
--- a/system/language/english/unit_test_lang.php
+++ b/system/language/english/unit_test_lang.php
@@ -5,9 +5,9 @@
  * 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:
diff --git a/system/language/english/upload_lang.php b/system/language/english/upload_lang.php
index 4fa8394..c3cb9c3 100644
--- a/system/language/english/upload_lang.php
+++ b/system/language/english/upload_lang.php
@@ -5,9 +5,9 @@
  * 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:
diff --git a/system/libraries/Cache/Cache.php b/system/libraries/Cache/Cache.php
index 53f9f81..4395cf4 100644
--- a/system/libraries/Cache/Cache.php
+++ b/system/libraries/Cache/Cache.php
@@ -41,11 +41,12 @@
 	 *
 	 * @var array
 	 */
-	protected $valid_drivers = array(
+	protected $valid_drivers 	= array(
 		'cache_apc',
+		'cache_dummy',
 		'cache_file',
 		'cache_memcached',
-		'cache_dummy',
+		'cache_redis',
 		'cache_wincache'
 	);
 
diff --git a/system/libraries/Cache/drivers/Cache_file.php b/system/libraries/Cache/drivers/Cache_file.php
index ce2c2b1..0823196 100644
--- a/system/libraries/Cache/drivers/Cache_file.php
+++ b/system/libraries/Cache/drivers/Cache_file.php
@@ -26,7 +26,7 @@
  */
 
 /**
- * CodeIgniter Memcached Caching Class
+ * CodeIgniter File Caching Class
  *
  * @package		CodeIgniter
  * @subpackage	Libraries
@@ -71,7 +71,7 @@
 			return FALSE;
 		}
 
-		$data = unserialize(read_file($this->_cache_path.$id));
+		$data = unserialize(file_get_contents($this->_cache_path.$id));
 
 		if (time() >  $data['time'] + $data['ttl'])
 		{
@@ -165,19 +165,19 @@
 			return FALSE;
 		}
 
-		$data = unserialize(read_file($this->_cache_path.$id));
+		$data = unserialize(file_get_contents($this->_cache_path.$id));
 
 		if (is_array($data))
 		{
 			$mtime = filemtime($this->_cache_path.$id);
 
-			if ( ! isset($data['data']['ttl']))
+			if ( ! isset($data['ttl']))
 			{
 				return FALSE;
 			}
 
 			return array(
-				'expire' => $mtime + $data['data']['ttl'],
+				'expire' => $mtime + $data['ttl'],
 				'mtime'	 => $mtime
 			);
 		}
diff --git a/system/libraries/Cache/drivers/Cache_redis.php b/system/libraries/Cache/drivers/Cache_redis.php
new file mode 100644
index 0000000..e4a26b5
--- /dev/null
+++ b/system/libraries/Cache/drivers/Cache_redis.php
@@ -0,0 +1,236 @@
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * 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) 2006 - 2012 EllisLab, Inc.
+ * @license		http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
+ * @link		http://codeigniter.com
+ * @since		Version 3.0
+ * @filesource
+ */
+
+/**
+ * CodeIgniter Redis Caching Class
+ *
+ * @package	   CodeIgniter
+ * @subpackage Libraries
+ * @category   Core
+ * @author	   Anton Lindqvist <anton@qvister.se>
+ * @link
+ */
+class CI_Cache_redis extends CI_Driver
+{
+	/**
+	 * Default config
+	 *
+	 * @static
+	 * @var	array
+	 */
+	protected static $_default_config = array(
+		'host' => '127.0.0.1',
+		'password' => NULL,
+		'port' => 6379,
+		'timeout' => 0
+	);
+
+	/**
+	 * Redis connection
+	 *
+	 * @var	Redis
+	 */
+	protected $_redis;
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * Get cache
+	 *
+	 * @param	string	Cache key identifier
+	 * @return	mixed
+	 */
+	public function get($key)
+	{
+		return $this->_redis->get($key);
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * Save cache
+	 *
+	 * @param	string	Cache key identifier
+	 * @param	mixed	Data to save
+	 * @param	int	Time to live
+	 * @return	bool
+	 */
+	public function save($key, $value, $ttl = NULL)
+	{
+		return ($ttl)
+			? $this->_redis->setex($key, $ttl, $value)
+			: $this->_redis->set($key, $value);
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * Delete from cache
+	 *
+	 * @param	string	Cache key
+	 * @return	bool
+	 */
+	public function delete($key)
+	{
+		return ($this->_redis->delete($key) === 1);
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * Clean cache
+	 *
+	 * @return	bool
+	 * @see		Redis::flushDB()
+	 */
+	public function clean()
+	{
+		return $this->_redis->flushDB();
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * Get cache driver info
+	 *
+	 * @param	string	Not supported in Redis.
+	 *			Only included in order to offer a
+	 *			consistent cache API.
+	 * @return	array
+	 * @see		Redis::info()
+	 */
+	public function cache_info($type = NULL)
+	{
+		return $this->_redis->info();
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * Get cache metadata
+	 *
+	 * @param	string	Cache key
+	 * @return	array
+	 */
+	public function get_metadata($key)
+	{
+		$value = $this->get($key);
+
+		if ($value)
+		{
+			return array(
+				'expire' => time() + $this->_redis->ttl($key),
+				'data' => $value
+			);
+		}
+
+		return FALSE;
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * Check if Redis driver is supported
+	 *
+	 * @return	bool
+	 */
+	public function is_supported()
+	{
+		if (extension_loaded('redis'))
+		{
+			$this->_setup_redis();
+			return TRUE;
+		}
+		else
+		{
+			log_message('error', 'The Redis extension must be loaded to use Redis cache.');
+			return FALSE;
+		}
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * Setup Redis config and connection
+	 *
+	 * Loads Redis config file if present. Will halt execution
+	 * if a Redis connection can't be established.
+	 *
+	 * @return	bool
+	 * @see		Redis::connect()
+	 */
+	protected function _setup_redis()
+	{
+		$config = array();
+		$CI =& get_instance();
+
+		if ($CI->config->load('redis', TRUE, TRUE))
+		{
+			$config += $CI->config->item('redis');
+		}
+
+		$config = array_merge(self::$_default_config, $config);
+
+		$this->_redis = new Redis();
+
+		try
+		{
+			$this->_redis->connect($config['host'], $config['port'], $config['timeout']);
+		}
+		catch (RedisException $e)
+		{
+			show_error('Redis connection refused. ' . $e->getMessage());
+		}
+
+		if (isset($config['password']))
+		{
+			$this->_redis->auth($config['password']);
+		}
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+
+	 * Class destructor
+	 *
+	 * Closes the connection to Redis if present.
+	 *
+	 * @return	void
+	 */
+	public function __destruct()
+	{
+		if ($this->_redis)
+		{
+			$this->_redis->close();
+		}
+	}
+
+}
+
+/* End of file Cache_redis.php */
+/* Location: ./system/libraries/Cache/drivers/Cache_redis.php */
\ No newline at end of file
diff --git a/system/libraries/Email.php b/system/libraries/Email.php
index 4586679..dd5477e 100644
--- a/system/libraries/Email.php
+++ b/system/libraries/Email.php
@@ -166,8 +166,8 @@
 		$this->_headers		= array();
 		$this->_debug_msg	= array();
 
-		$this->_set_header('User-Agent', $this->useragent);
-		$this->_set_header('Date', $this->_set_date());
+		$this->set_header('User-Agent', $this->useragent);
+		$this->set_header('Date', $this->_set_date());
 
 		if ($clear_attachments !== FALSE)
 		{
@@ -215,8 +215,8 @@
 			}
 		}
 
-		$this->_set_header('From', $name.' <'.$from.'>');
-		$this->_set_header('Return-Path', '<'.$from.'>');
+		$this->set_header('From', $name.' <'.$from.'>');
+		$this->set_header('Return-Path', '<'.$from.'>');
 
 		return $this;
 	}
@@ -247,12 +247,12 @@
 			$name = $replyto;
 		}
 
-		if (strncmp($name, '"', 1) !== 0)
+		if (strpos($name, '"') !== 0)
 		{
 			$name = '"'.$name.'"';
 		}
 
-		$this->_set_header('Reply-To', $name.' <'.$replyto.'>');
+		$this->set_header('Reply-To', $name.' <'.$replyto.'>');
 		$this->_replyto_flag = TRUE;
 
 		return $this;
@@ -278,7 +278,7 @@
 
 		if ($this->_get_protocol() !== 'mail')
 		{
-			$this->_set_header('To', implode(', ', $to));
+			$this->set_header('To', implode(', ', $to));
 		}
 
 		switch ($this->_get_protocol())
@@ -312,7 +312,7 @@
 			$this->validate_email($cc);
 		}
 
-		$this->_set_header('Cc', implode(', ', $cc));
+		$this->set_header('Cc', implode(', ', $cc));
 
 		if ($this->_get_protocol() === 'smtp')
 		{
@@ -352,7 +352,7 @@
 		}
 		else
 		{
-			$this->_set_header('Bcc', implode(', ', $bcc));
+			$this->set_header('Bcc', implode(', ', $bcc));
 		}
 
 		return $this;
@@ -369,7 +369,7 @@
 	public function subject($subject)
 	{
 		$subject = $this->_prep_q_encoding($subject);
-		$this->_set_header('Subject', $subject);
+		$this->set_header('Subject', $subject);
 		return $this;
 	}
 
@@ -424,7 +424,7 @@
 	 * @param	string
 	 * @return	void
 	 */
-	protected function _set_header($header, $value)
+	public function set_header($header, $value)
 	{
 		$this->_headers[$header] = $value;
 	}
@@ -606,7 +606,7 @@
 
 		foreach ($this->_base_charsets as $charset)
 		{
-			if (strncmp($charset, $this->charset, strlen($charset)) === 0)
+			if (strpos($charset, $this->charset) === 0)
 			{
 				$this->_encoding = '7bit';
 			}
@@ -651,7 +651,7 @@
 	protected function _set_date()
 	{
 		$timezone = date('Z');
-		$operator = (strncmp($timezone, '-', 1) === 0) ? '-' : '+';
+		$operator = ($timezone[0] === '-') ? '-' : '+';
 		$timezone = abs($timezone);
 		$timezone = floor($timezone/3600) * 100 + ($timezone % 3600) / 60;
 
@@ -867,11 +867,11 @@
 	 */
 	protected function _build_headers()
 	{
-		$this->_set_header('X-Sender', $this->clean_email($this->_headers['From']));
-		$this->_set_header('X-Mailer', $this->useragent);
-		$this->_set_header('X-Priority', $this->_priorities[$this->priority - 1]);
-		$this->_set_header('Message-ID', $this->_get_message_id());
-		$this->_set_header('Mime-Version', '1.0');
+		$this->set_header('X-Sender', $this->clean_email($this->_headers['From']));
+		$this->set_header('X-Mailer', $this->useragent);
+		$this->set_header('X-Priority', $this->_priorities[$this->priority - 1]);
+		$this->set_header('Message-ID', $this->_get_message_id());
+		$this->set_header('Mime-Version', '1.0');
 	}
 
 	// --------------------------------------------------------------------
@@ -1305,7 +1305,7 @@
 
 			if ($this->protocol !== 'smtp')
 			{
-				$this->_set_header('Bcc', implode(', ', $bcc));
+				$this->set_header('Bcc', implode(', ', $bcc));
 			}
 			else
 			{
@@ -1481,7 +1481,7 @@
 
 		$this->_set_error_message($reply);
 
-		if (strncmp($reply, '250', 3) !== 0)
+		if (strpos($reply, '250') !== 0)
 		{
 			$this->_set_error_message('lang:email_smtp_error', $reply);
 			return FALSE;
@@ -1599,7 +1599,7 @@
 
 		$this->_debug_msg[] = '<pre>'.$cmd.': '.$reply.'</pre>';
 
-		if (substr($reply, 0, 3) !== $resp)
+		if ( (int) substr($reply, 0, 3) !== $resp)
 		{
 			$this->_set_error_message('lang:email_smtp_error', $reply);
 			return FALSE;
@@ -1637,7 +1637,7 @@
 
 		$reply = $this->_get_smtp_data();
 
-		if (strncmp($reply, '334', 3) !== 0)
+		if (strpos($reply, '334') !== 0)
 		{
 			$this->_set_error_message('lang:email_failed_smtp_login', $reply);
 			return FALSE;
@@ -1647,7 +1647,7 @@
 
 		$reply = $this->_get_smtp_data();
 
-		if (strncmp($reply, '334', 3) !== 0)
+		if (strpos($reply, '334') !== 0)
 		{
 			$this->_set_error_message('lang:email_smtp_auth_un', $reply);
 			return FALSE;
@@ -1657,7 +1657,7 @@
 
 		$reply = $this->_get_smtp_data();
 
-		if (strncmp($reply, '235', 3) !== 0)
+		if (strpos($reply, '235') !== 0)
 		{
 			$this->_set_error_message('lang:email_smtp_auth_pw', $reply);
 			return FALSE;
@@ -1816,98 +1816,23 @@
 	 */
 	protected function _mime_types($ext = '')
 	{
-		$mimes = array(
-						'hqx'	=>	'application/mac-binhex40',
-						'cpt'	=>	'application/mac-compactpro',
-						'doc'	=>	'application/msword',
-						'bin'	=>	'application/macbinary',
-						'dms'	=>	'application/octet-stream',
-						'lha'	=>	'application/octet-stream',
-						'lzh'	=>	'application/octet-stream',
-						'exe'	=>	'application/octet-stream',
-						'class'	=>	'application/octet-stream',
-						'psd'	=>	'application/octet-stream',
-						'so'	=>	'application/octet-stream',
-						'sea'	=>	'application/octet-stream',
-						'dll'	=>	'application/octet-stream',
-						'oda'	=>	'application/oda',
-						'pdf'	=>	'application/pdf',
-						'ai'	=>	'application/postscript',
-						'eps'	=>	'application/postscript',
-						'ps'	=>	'application/postscript',
-						'smi'	=>	'application/smil',
-						'smil'	=>	'application/smil',
-						'mif'	=>	'application/vnd.mif',
-						'xls'	=>	'application/vnd.ms-excel',
-						'ppt'	=>	'application/vnd.ms-powerpoint',
-						'wbxml'	=>	'application/vnd.wap.wbxml',
-						'wmlc'	=>	'application/vnd.wap.wmlc',
-						'dcr'	=>	'application/x-director',
-						'dir'	=>	'application/x-director',
-						'dxr'	=>	'application/x-director',
-						'dvi'	=>	'application/x-dvi',
-						'gtar'	=>	'application/x-gtar',
-						'php'	=>	'application/x-httpd-php',
-						'php4'	=>	'application/x-httpd-php',
-						'php3'	=>	'application/x-httpd-php',
-						'phtml'	=>	'application/x-httpd-php',
-						'phps'	=>	'application/x-httpd-php-source',
-						'js'	=>	'application/x-javascript',
-						'swf'	=>	'application/x-shockwave-flash',
-						'sit'	=>	'application/x-stuffit',
-						'tar'	=>	'application/x-tar',
-						'tgz'	=>	'application/x-tar',
-						'xhtml'	=>	'application/xhtml+xml',
-						'xht'	=>	'application/xhtml+xml',
-						'zip'	=>	'application/zip',
-						'mid'	=>	'audio/midi',
-						'midi'	=>	'audio/midi',
-						'mpga'	=>	'audio/mpeg',
-						'mp2'	=>	'audio/mpeg',
-						'mp3'	=>	'audio/mpeg',
-						'aif'	=>	'audio/x-aiff',
-						'aiff'	=>	'audio/x-aiff',
-						'aifc'	=>	'audio/x-aiff',
-						'ram'	=>	'audio/x-pn-realaudio',
-						'rm'	=>	'audio/x-pn-realaudio',
-						'rpm'	=>	'audio/x-pn-realaudio-plugin',
-						'ra'	=>	'audio/x-realaudio',
-						'rv'	=>	'video/vnd.rn-realvideo',
-						'wav'	=>	'audio/x-wav',
-						'bmp'	=>	'image/bmp',
-						'gif'	=>	'image/gif',
-						'jpeg'	=>	'image/jpeg',
-						'jpg'	=>	'image/jpeg',
-						'jpe'	=>	'image/jpeg',
-						'png'	=>	'image/png',
-						'tiff'	=>	'image/tiff',
-						'tif'	=>	'image/tiff',
-						'css'	=>	'text/css',
-						'ics'	=>	'text/calendar',
-						'html'	=>	'text/html',
-						'htm'	=>	'text/html',
-						'shtml'	=>	'text/html',
-						'txt'	=>	'text/plain',
-						'text'	=>	'text/plain',
-						'log'	=>	'text/plain',
-						'rtx'	=>	'text/richtext',
-						'rtf'	=>	'text/rtf',
-						'xml'	=>	'text/xml',
-						'xsl'	=>	'text/xml',
-						'mpeg'	=>	'video/mpeg',
-						'mpg'	=>	'video/mpeg',
-						'mpe'	=>	'video/mpeg',
-						'qt'	=>	'video/quicktime',
-						'mov'	=>	'video/quicktime',
-						'avi'	=>	'video/x-msvideo',
-						'movie'	=>	'video/x-sgi-movie',
-						'doc'	=>	'application/msword',
-						'word'	=>	'application/msword',
-						'xl'	=>	'application/excel',
-						'eml'	=>	'message/rfc822'
-					);
+		static $mimes;
 
-		return isset($mimes[strtolower($ext)]) ? $mimes[strtolower($ext)] : 'application/x-unknown-content-type';
+		$ext = strtolower($ext);
+
+		if ( ! is_array($mimes))
+		{
+			$mimes =& get_mimes();
+		}
+
+		if (isset($mimes[$ext]))
+		{
+			return is_array($mimes[$ext])
+				? current($mimes[$ext])
+				: $mimes[$ext];
+		}
+
+		return 'application/x-unknown-content-type';
 	}
 
 }
diff --git a/system/libraries/Encrypt.php b/system/libraries/Encrypt.php
index 959e2ee..8ffd93a 100644
--- a/system/libraries/Encrypt.php
+++ b/system/libraries/Encrypt.php
@@ -104,8 +104,7 @@
 				return $this->encryption_key;
 			}
 
-			$CI =& get_instance();
-			$key = $CI->config->item('encryption_key');
+			$key = config_item('encryption_key');
 
 			if ($key === FALSE)
 			{
@@ -214,6 +213,7 @@
 		$dec = base64_decode($string);
 		if (($dec = $this->mcrypt_decode($dec, $key)) === FALSE)
 		{
+			$this->set_mode($current_mode);
 			return FALSE;
 		}
 
diff --git a/system/libraries/Form_validation.php b/system/libraries/Form_validation.php
index 225325d..6cbe032 100644
--- a/system/libraries/Form_validation.php
+++ b/system/libraries/Form_validation.php
@@ -187,6 +187,12 @@
 			return $this;
 		}
 
+		// Convert an array of rules to a string
+		if (is_array($rules))
+		{
+			$rules = implode('|', $rules);
+		}
+
 		// No fields? Nothing to do...
 		if ( ! is_string($field) OR ! is_string($rules) OR $field === '')
 		{
@@ -1089,11 +1095,12 @@
 	 * Validate IP Address
 	 *
 	 * @param	string
+	 * @param	string	'ipv4' or 'ipv6' to validate a specific IP format
 	 * @return	bool
 	 */
-	public function valid_ip($ip)
+	public function valid_ip($ip, $which = '')
 	{
-		return $this->CI->input->valid_ip($ip);
+		return $this->CI->input->valid_ip($ip, $which);
 	}
 
 	// --------------------------------------------------------------------
diff --git a/system/libraries/Javascript.php b/system/libraries/Javascript.php
index 98fec61..5c8b092 100644
--- a/system/libraries/Javascript.php
+++ b/system/libraries/Javascript.php
@@ -620,7 +620,7 @@
 			$this->_javascript_location = $this->CI->config->item('javascript_location');
 		}
 
-		if ($relative === TRUE OR strncmp($external_file, 'http://', 7) === 0 OR strncmp($external_file, 'https://', 8) === 0)
+		if ($relative === TRUE OR strpos($external_file, 'http://') === 0 OR strpos($external_file, 'https://') === 0)
 		{
 			$str = $this->_open_script($external_file);
 		}
diff --git a/system/libraries/Pagination.php b/system/libraries/Pagination.php
index a91159c..cdec736 100644
--- a/system/libraries/Pagination.php
+++ b/system/libraries/Pagination.php
@@ -36,38 +36,39 @@
  */
 class CI_Pagination {
 
-	protected $base_url				= ''; // The page we are linking to
-	protected $prefix				= ''; // A custom prefix added to the path.
-	protected $suffix				= ''; // A custom suffix added to the path.
-	protected $total_rows			= 0; // Total number of items (database results)
-	protected $per_page				= 10; // Max number of items you want shown per page
-	protected $num_links			= 2; // Number of "digit" links to show before/after the currently viewed page
-	protected $cur_page				= 0; // The current page being viewed
-	protected $use_page_numbers		= FALSE; // Use page number for segment instead of offset
-	protected $first_link			= '&lsaquo; First';
-	protected $next_link			= '&gt;';
-	protected $prev_link			= '&lt;';
-	protected $last_link			= 'Last &rsaquo;';
-	protected $uri_segment			= 3;
-	protected $full_tag_open		= '';
-	protected $full_tag_close		= '';
-	protected $first_tag_open		= '';
-	protected $first_tag_close		= '&nbsp;';
-	protected $last_tag_open		= '&nbsp;';
-	protected $last_tag_close		= '';
-	protected $first_url			= ''; // Alternative URL for the First Page.
-	protected $cur_tag_open			= '&nbsp;<strong>';
-	protected $cur_tag_close		= '</strong>';
-	protected $next_tag_open		= '&nbsp;';
-	protected $next_tag_close		= '&nbsp;';
-	protected $prev_tag_open		= '&nbsp;';
-	protected $prev_tag_close		= '';
-	protected $num_tag_open			= '&nbsp;';
-	protected $num_tag_close		= '';
-	protected $page_query_string	= FALSE;
-	protected $query_string_segment = 'per_page';
-	protected $display_pages		= TRUE;
-	protected $anchor_class			= '';
+	public $base_url				= ''; // The page we are linking to
+	public $prefix				= ''; // A custom prefix added to the path.
+	public $suffix				= ''; // A custom suffix added to the path.
+	public $total_rows			= 0; // Total number of items (database results)
+	public $per_page				= 10; // Max number of items you want shown per page
+	public $num_links			= 2; // Number of "digit" links to show before/after the currently viewed page
+	public $cur_page				= 0; // The current page being viewed
+	public $use_page_numbers		= FALSE; // Use page number for segment instead of offset
+	public $first_link			= '&lsaquo; First';
+	public $next_link			= '&gt;';
+	public $prev_link			= '&lt;';
+	public $last_link			= 'Last &rsaquo;';
+	public $uri_segment			= 3;
+	public $full_tag_open		= '';
+	public $full_tag_close		= '';
+	public $first_tag_open		= '';
+	public $first_tag_close		= '&nbsp;';
+	public $last_tag_open		= '&nbsp;';
+	public $last_tag_close		= '';
+	public $first_url			= ''; // Alternative URL for the First Page.
+	public $cur_tag_open			= '&nbsp;<strong>';
+	public $cur_tag_close		= '</strong>';
+	public $next_tag_open		= '&nbsp;';
+	public $next_tag_close		= '&nbsp;';
+	public $prev_tag_open		= '&nbsp;';
+	public $prev_tag_close		= '';
+	public $num_tag_open			= '&nbsp;';
+	public $num_tag_close		= '';
+	public $page_query_string	= FALSE;
+	public $query_string_segment = 'per_page';
+	public $display_pages		= TRUE;
+	public $anchor_class			= '';
+	public $attr_rel			= TRUE;
 
 	/**
 	 * Constructor
@@ -97,7 +98,7 @@
 			{
 				if ($key === 'anchor_class')
 				{
-					$this->anchor_class = ($val !== '') ? 'class="'.$val.'" ' : '';
+					$this->anchor_class = ($val) ? 'class="'.$val.'" ' : '';
 				}
 				elseif (isset($this->$key))
 				{
@@ -145,7 +146,7 @@
 
 		if ($CI->config->item('enable_query_strings') === TRUE OR $this->page_query_string === TRUE)
 		{
-			if ($CI->input->get($this->query_string_segment) !== $base_page)
+			if ($CI->input->get($this->query_string_segment) != $base_page)
 			{
 				$this->cur_page = (int) $CI->input->get($this->query_string_segment);
 			}
@@ -212,7 +213,8 @@
 		if ($this->first_link !== FALSE && $this->cur_page > ($this->num_links + 1))
 		{
 			$first_url = ($this->first_url === '') ? $this->base_url : $this->first_url;
-			$output .= $this->first_tag_open.'<a '.$this->anchor_class.'href="'.$first_url.'">'.$this->first_link.'</a>'.$this->first_tag_close;
+			$output .= $this->first_tag_open.'<a '.$this->anchor_class.'href="'.$first_url.'"'.$this->_attr_rel('start').'>'
+				.$this->first_link.'</a>'.$this->first_tag_close;
 		}
 
 		// Render the "previous" link
@@ -222,12 +224,14 @@
 
 			if ($i === $base_page && $this->first_url !== '')
 			{
-				$output .= $this->prev_tag_open.'<a '.$this->anchor_class.'href="'.$this->first_url.'">'.$this->prev_link.'</a>'.$this->prev_tag_close;
+				$output .= $this->prev_tag_open.'<a '.$this->anchor_class.'href="'.$this->first_url.'"'.$this->_attr_rel('prev').'>'
+					.$this->prev_link.'</a>'.$this->prev_tag_close;
 			}
 			else
 			{
 				$i = ($i === $base_page) ? '' : $this->prefix.$i.$this->suffix;
-				$output .= $this->prev_tag_open.'<a '.$this->anchor_class.'href="'.$this->base_url.$i.'">'.$this->prev_link.'</a>'.$this->prev_tag_close;
+				$output .= $this->prev_tag_open.'<a '.$this->anchor_class.'href="'.$this->base_url.$i.'"'.$this->_attr_rel('prev').'>'
+					.$this->prev_link.'</a>'.$this->prev_tag_close;
 			}
 
 		}
@@ -252,13 +256,15 @@
 
 						if ($n === '' && $this->first_url !== '')
 						{
-							$output .= $this->num_tag_open.'<a '.$this->anchor_class.'href="'.$this->first_url.'">'.$loop.'</a>'.$this->num_tag_close;
+							$output .= $this->num_tag_open.'<a '.$this->anchor_class.'href="'.$this->first_url.'"'.$this->_attr_rel('start').'>'
+								.$loop.'</a>'.$this->num_tag_close;
 						}
 						else
 						{
 							$n = ($n === '') ? '' : $this->prefix.$n.$this->suffix;
 
-							$output .= $this->num_tag_open.'<a '.$this->anchor_class.'href="'.$this->base_url.$n.'">'.$loop.'</a>'.$this->num_tag_close;
+							$output .= $this->num_tag_open.'<a '.$this->anchor_class.'href="'.$this->base_url.$n.'"'.$this->_attr_rel().'>'
+								.$loop.'</a>'.$this->num_tag_close;
 						}
 					}
 				}
@@ -270,7 +276,8 @@
 		{
 			$i = ($this->use_page_numbers) ? $this->cur_page + 1 : $this->cur_page * $this->per_page;
 
-			$output .= $this->next_tag_open.'<a '.$this->anchor_class.'href="'.$this->base_url.$this->prefix.$i.$this->suffix.'">'.$this->next_link.'</a>'.$this->next_tag_close;
+			$output .= $this->next_tag_open.'<a '.$this->anchor_class.'href="'.$this->base_url.$this->prefix.$i.$this->suffix.'"'.$this->_attr_rel('next').'>'
+				.$this->next_link.'</a>'.$this->next_tag_close;
 		}
 
 		// Render the "Last" link
@@ -278,7 +285,8 @@
 		{
 			$i = ($this->use_page_numbers) ? $num_pages : ($num_pages * $this->per_page) - $this->per_page;
 
-			$output .= $this->last_tag_open.'<a '.$this->anchor_class.'href="'.$this->base_url.$this->prefix.$i.$this->suffix.'">'.$this->last_link.'</a>'.$this->last_tag_close;
+			$output .= $this->last_tag_open.'<a '.$this->anchor_class.'href="'.$this->base_url.$this->prefix.$i.$this->suffix.'"'.$this->_attr_rel().'>'
+				.$this->last_link.'</a>'.$this->last_tag_close;
 		}
 
 		// Kill double slashes. Note: Sometimes we can end up with a double slash
@@ -289,6 +297,28 @@
 		return $this->full_tag_open.$output.$this->full_tag_close;
 	}
 
+	// --------------------------------------------------------------------
+
+	/**
+	 * Add "rel" attribute
+	 *
+	 * @param	string
+	 * @return	string
+	 */
+	protected function _attr_rel($value = '')
+	{
+		if (empty($this->attr_rel) OR ($this->attr_rel === TRUE && empty($value)))
+		{
+			return '';
+		}
+		elseif ( ! is_bool($this->attr_rel))
+		{
+			$value = $this->attr_rel;
+		}
+
+		return ' rel="'.$value.'"';
+	}
+
 }
 
 /* End of file Pagination.php */
diff --git a/system/libraries/Profiler.php b/system/libraries/Profiler.php
index aaac0c5..d96088c 100644
--- a/system/libraries/Profiler.php
+++ b/system/libraries/Profiler.php
@@ -402,7 +402,7 @@
 			."\n"
 			.'<legend style="color:#5a0099;">&nbsp;&nbsp;'.$this->CI->lang->line('profiler_memory_usage')."&nbsp;&nbsp;</legend>\n"
 			.'<div style="color:#5a0099;font-weight:normal;padding:4px 0 4px 0;">'
-			.((function_exists('memory_get_usage') && ($usage = memory_get_usage()) !== '') ? number_format($usage).' bytes' : $this->CI->lang->line('profiler_no_memory'))
+			.(($usage = memory_get_usage()) != '' ? number_format($usage).' bytes' : $this->CI->lang->line('profiler_no_memory'))
 			.'</div></fieldset>';
 	}
 
diff --git a/system/libraries/Session.php b/system/libraries/Session.php
index 7beedd9..72a942b 100644
--- a/system/libraries/Session.php
+++ b/system/libraries/Session.php
@@ -149,11 +149,11 @@
 	public $flashdata_key			= 'flash';
 
 	/**
-	 * Function to use to get the current time
+	 * Timezone to use for the current time
 	 *
 	 * @var string
 	 */
-	public $time_reference			= 'time';
+	public $time_reference			= 'local';
 
 	/**
 	 * Probablity level of garbage collection of old sessions
@@ -203,7 +203,7 @@
 		// manually via the $params array above or via the config file
 		foreach (array('sess_encrypt_cookie', 'sess_use_database', 'sess_table_name', 'sess_expiration', 'sess_expire_on_close', 'sess_match_ip', 'sess_match_useragent', 'sess_cookie_name', 'cookie_path', 'cookie_domain', 'cookie_secure', 'cookie_httponly', 'sess_time_to_update', 'time_reference', 'cookie_prefix', 'encryption_key') as $key)
 		{
-			$this->$key = (isset($params[$key])) ? $params[$key] : $this->CI->config->item($key);
+			$this->$key = isset($params[$key]) ? $params[$key] : $this->CI->config->item($key);
 		}
 
 		if ($this->encryption_key === '')
@@ -786,9 +786,15 @@
 	 */
 	protected function _get_time()
 	{
-		return (strtolower($this->time_reference) === 'gmt')
-			? mktime(gmdate('H'), gmdate('i'), gmdate('s'), gmdate('m'), gmdate('d'), gmdate('Y'))
-			: time();
+		if ($this->time_reference === 'local' OR $this->time_reference === date_default_timezone_get())
+		{
+			return time();
+		}
+
+		$datetime = new DateTime('now', new DateTimeZone($this->time_reference));
+		sscanf($datetime->format('j-n-Y G:i:s'), '%d-%d-%d %d:%d:%d', $day, $month, $year, $hour, $minute, $second);
+
+		return mktime($hour, $minute, $second, $month, $day, $year);
 	}
 
 	// --------------------------------------------------------------------
diff --git a/system/libraries/Unit_test.php b/system/libraries/Unit_test.php
index a87cf7e..70ad8dc 100644
--- a/system/libraries/Unit_test.php
+++ b/system/libraries/Unit_test.php
@@ -124,7 +124,7 @@
 
 		$this->results[] = $report;
 
-		return($this->report($this->result($report)));
+		return $this->report($this->result($report));
 	}
 
 	// --------------------------------------------------------------------
@@ -289,15 +289,11 @@
 	 */
 	protected function _backtrace()
 	{
-		if (function_exists('debug_backtrace'))
-		{
-			$back = debug_backtrace();
-			return array(
-					'file' => (isset($back[1]['file']) ? $back[1]['file'] : ''),
-					'line' => (isset($back[1]['line']) ? $back[1]['line'] : '')
-				);
-		}
-		return array('file' => 'Unknown', 'line' => 'Unknown');
+		$back = debug_backtrace();
+		return array(
+				'file' => (isset($back[1]['file']) ? $back[1]['file'] : ''),
+				'line' => (isset($back[1]['line']) ? $back[1]['line'] : '')
+			);
 	}
 
 	// --------------------------------------------------------------------
diff --git a/system/libraries/Upload.php b/system/libraries/Upload.php
index e31029e..c96daaf 100644
--- a/system/libraries/Upload.php
+++ b/system/libraries/Upload.php
@@ -78,6 +78,8 @@
 			$this->initialize($props);
 		}
 
+		$this->mimes =& get_mimes();
+
 		log_message('debug', 'Upload Class Initialized');
 	}
 
@@ -113,7 +115,6 @@
 					'image_type'			=> '',
 					'image_size_str'		=> '',
 					'error_msg'			=> array(),
-					'mimes'				=> array(),
 					'remove_spaces'			=> TRUE,
 					'xss_clean'			=> FALSE,
 					'temp_prefix'			=> 'temp_file_',
@@ -346,11 +347,12 @@
 	 * Returns an associative array containing all of the information
 	 * related to the upload, allowing the developer easy access in one array.
 	 *
-	 * @return	array
+	 * @param	string
+	 * @return	mixed
 	 */
-	public function data()
+	public function data($index = NULL)
 	{
-		return array(
+		$data = array(
 				'file_name'		=> $this->file_name,
 				'file_type'		=> $this->file_type,
 				'file_path'		=> $this->upload_path,
@@ -366,6 +368,13 @@
 				'image_type'		=> $this->image_type,
 				'image_size_str'	=> $this->image_size_str,
 			);
+
+		if ( ! empty($index))
+		{
+			return isset($data[$index]) ? $data[$index] : NULL;
+		}
+
+		return $data;
 	}
 
 	// --------------------------------------------------------------------
@@ -693,7 +702,7 @@
 			return FALSE;
 		}
 
-		if (function_exists('realpath') && @realpath($this->upload_path) !== FALSE)
+		if (@realpath($this->upload_path) !== FALSE)
 		{
 			$this->upload_path = str_replace('\\', '/', realpath($this->upload_path));
 		}
@@ -814,17 +823,17 @@
 			return FALSE;
 		}
 
-		if (function_exists('memory_get_usage') && memory_get_usage() && ini_get('memory_limit'))
+		if (memory_get_usage() && ($memory_limit = ini_get('memory_limit')))
 		{
-			$current = ini_get('memory_limit') * 1024 * 1024;
+			$memory_limit *= 1024 * 1024;
 
 			// There was a bug/behavioural change in PHP 5.2, where numbers over one million get output
 			// into scientific notation. number_format() ensures this number is an integer
 			// http://bugs.php.net/bug.php?id=43053
 
-			$new_memory = number_format(ceil(filesize($file) + $current), 0, '.', '');
+			$memory_limit = number_format(ceil(filesize($file) + $memory_limit), 0, '.', '');
 
-			ini_set('memory_limit', $new_memory); // When an integer is used, the value is measured in bytes. - PHP.net
+			ini_set('memory_limit', $memory_limit); // When an integer is used, the value is measured in bytes. - PHP.net
 		}
 
 		// If the file being uploaded is an image, then we should have no problem with XSS attacks (in theory), but
@@ -848,14 +857,8 @@
 			// <a, <body, <head, <html, <img, <plaintext, <pre, <script, <table, <title
 			// title is basically just in SVG, but we filter it anyhow
 
-			if ( ! preg_match('/<(a|body|head|html|img|plaintext|pre|script|table|title)[\s>]/i', $opening_bytes))
-			{
-				return TRUE; // its an image, no "triggers" detected in the first 256 bytes, we're good
-			}
-			else
-			{
-				return FALSE;
-			}
+			// if its an image or no "triggers" detected in the first 256 bytes - we're good
+			return ! preg_match('/<(a|body|head|html|img|plaintext|pre|script|table|title)[\s>]/i', $opening_bytes);
 		}
 
 		if (($data = @file_get_contents($file)) === FALSE)
@@ -924,24 +927,6 @@
 	 */
 	public function mimes_types($mime)
 	{
-		global $mimes;
-
-		if (count($this->mimes) === 0)
-		{
-			if (defined('ENVIRONMENT') && is_file(APPPATH.'config/'.ENVIRONMENT.'/mimes.php'))
-			{
-				$this->mimes = include(APPPATH.'config/'.ENVIRONMENT.'/mimes.php');
-			}
-			elseif (is_file(APPPATH.'config/mimes.php'))
-			{
-				$this->mimes = include(APPPATH.'config/mimes.php');
-			}
-			else
-			{
-				return FALSE;
-			}
-		}
-
 		return isset($this->mimes[$mime]) ? $this->mimes[$mime] : FALSE;
 	}
 
diff --git a/system/libraries/Xmlrpc.php b/system/libraries/Xmlrpc.php
index 6f35423..eac4ac1 100644
--- a/system/libraries/Xmlrpc.php
+++ b/system/libraries/Xmlrpc.php
@@ -778,7 +778,7 @@
 		}
 
 		// Check for HTTP 200 Response
-		if (strncmp($data, 'HTTP', 4) === 0 && ! preg_match('/^HTTP\/[0-9\.]+ 200 /', $data))
+		if (strpos($data, 'HTTP') === 0 && ! preg_match('/^HTTP\/[0-9\.]+ 200 /', $data))
 		{
 			$errstr = substr($data, 0, strpos($data, "\n")-1);
 			return new XML_RPC_Response(0, $this->xmlrpcerr['http_error'], $this->xmlrpcstr['http_error'].' ('.$errstr.')');
diff --git a/system/libraries/Xmlrpcs.php b/system/libraries/Xmlrpcs.php
index be930b0..e81f2ca 100644
--- a/system/libraries/Xmlrpcs.php
+++ b/system/libraries/Xmlrpcs.php
@@ -303,7 +303,7 @@
 		$methName = $m->method_name;
 
 		// Check to see if it is a system call
-		$system_call = (strncmp($methName, 'system', 5) === 0);
+		$system_call = (strpos($methName, 'system') === 0);
 
 		if ($this->xss_clean === FALSE)
 		{
diff --git a/tests/README.md b/tests/README.md
index c8fc608..d600951 100644
--- a/tests/README.md
+++ b/tests/README.md
@@ -21,8 +21,8 @@
 
 vfsStream
 
-	pear channel-discover pear.php-tools.net
-	pear install pat/vfsStream-alpha
+	pear channel-discover pear.bovigo.org
+	pear install bovigo/vfsStream-beta
 
 #### Installation of PEAR and PHPUnit on Ubuntu
 
@@ -37,11 +37,11 @@
 	pear channel-discover pear.phpunit.de
 	pear channel-discover pear.symfony-project.com
 	pear channel-discover components.ez.no
-	pear channel-discover pear.php-tools.net 
+	pear channel-discover pear.bovigo.org
 
 	# Finally install PHPUnit and vfsStream (including dependencies)
 	pear install --alldeps phpunit/PHPUnit
-	pear install --alldeps pat/vfsStream-alpha
+	pear install --alldeps bovigo/vfsStream-beta
 
 	# Finally, run 'phpunit' from within the ./tests directory
 	# and you should be on your way!
diff --git a/tests/codeigniter/Setup_test.php b/tests/codeigniter/Setup_test.php
index b48e32b..5317c56 100644
--- a/tests/codeigniter/Setup_test.php
+++ b/tests/codeigniter/Setup_test.php
@@ -1,13 +1,13 @@
 <?php
 
 class Setup_test extends PHPUnit_Framework_TestCase {
-	
-	function test_bootstrap_constants()
+
+	public function test_bootstrap_constants()
 	{
 		$this->assertTrue(defined('PROJECT_BASE'));
 		$this->assertTrue(defined('BASEPATH'));
 		$this->assertTrue(defined('APPPATH'));
 		$this->assertTrue(defined('VIEWPATH'));
 	}
-	
+
 }
\ No newline at end of file
diff --git a/tests/codeigniter/core/Benchmark_test.php b/tests/codeigniter/core/Benchmark_test.php
index 109b388..a239ba5 100644
--- a/tests/codeigniter/core/Benchmark_test.php
+++ b/tests/codeigniter/core/Benchmark_test.php
@@ -1,14 +1,14 @@
 <?php
 
 class Benchmark_test extends CI_TestCase {
-	
+
 	public function set_up()
 	{
 		$this->benchmark = new Mock_Core_Benchmark();
 	}
-	
+
 	// --------------------------------------------------------------------
-	
+
 	public function test_mark()
 	{
 		$this->assertEmpty($this->benchmark->marker);
@@ -18,7 +18,7 @@
 		$this->assertEquals(1, count($this->benchmark->marker));
 		$this->assertArrayHasKey('code_start', $this->benchmark->marker);
 	}
-	
+
 	// --------------------------------------------------------------------
 
 	public function test_elapsed_time()
@@ -29,7 +29,7 @@
 		$this->benchmark->mark('code_start');
 		sleep(1);
 		$this->benchmark->mark('code_end');
-		
+
 		$this->assertEquals('1.0', $this->benchmark->elapsed_time('code_start', 'code_end', 1));
 	}
 
@@ -39,4 +39,5 @@
 	{
 		$this->assertEquals('{memory_usage}', $this->benchmark->memory_usage());
 	}
+
 }
\ No newline at end of file
diff --git a/tests/codeigniter/core/Common_test.php b/tests/codeigniter/core/Common_test.php
index dded2e8..f9bf6c2 100644
--- a/tests/codeigniter/core/Common_test.php
+++ b/tests/codeigniter/core/Common_test.php
@@ -1,13 +1,13 @@
 <?php
 
 class Common_test extends CI_TestCase {
-	
+
 	// ------------------------------------------------------------------------
-	
+
 	public function test_is_php()
 	{
 		$this->assertEquals(TRUE, is_php('1.2.0'));
 		$this->assertEquals(FALSE, is_php('9999.9.9'));
 	}
-	
+
 }
\ No newline at end of file
diff --git a/tests/codeigniter/core/Config_test.php b/tests/codeigniter/core/Config_test.php
index 30f0cc6..30cb90a 100644
--- a/tests/codeigniter/core/Config_test.php
+++ b/tests/codeigniter/core/Config_test.php
@@ -5,7 +5,7 @@
 	public function set_up()
 	{
 		$cls =& $this->ci_core_class('cfg');
-				
+
 		// set predictable config values
 		$this->ci_set_config(array(
 			'index_page'		=> 'index.php',
@@ -13,9 +13,9 @@
 			'subclass_prefix'	=> 'MY_'
 		));
 
-		$this->config = new $cls;	
+		$this->config = new $cls;
 	}
-	
+
 	// --------------------------------------------------------------------
 
 	public function test_item()
@@ -24,30 +24,30 @@
 
 		// Bad Config value
 		$this->assertFalse($this->config->item('no_good_item'));
-		
+
 		// Index
 		$this->assertFalse($this->config->item('no_good_item', 'bad_index'));
 		$this->assertFalse($this->config->item('no_good_item', 'default'));
 	}
-	
+
 	// --------------------------------------------------------------------
-	
+
 	public function test_set_item()
 	{
 		$this->assertFalse($this->config->item('not_yet_set'));
-		
+
 		$this->config->set_item('not_yet_set', 'is set');
-		
+
 		$this->assertEquals('is set', $this->config->item('not_yet_set'));
 	}
 
 	// --------------------------------------------------------------------
-	
+
 	public function test_slash_item()
 	{
 		// Bad Config value
 		$this->assertFalse($this->config->slash_item('no_good_item'));
-		
+
 		$this->assertEquals('http://example.com/', $this->config->slash_item('base_url'));
 
 		$this->assertEquals('MY_/', $this->config->slash_item('subclass_prefix'));
@@ -58,33 +58,33 @@
 	public function test_site_url()
 	{
 		$this->assertEquals('http://example.com/index.php', $this->config->site_url());
-		
+
 		$base_url = $this->config->item('base_url');
-		
+
 		$this->config->set_item('base_url', '');
-		
+
 		$q_string = $this->config->item('enable_query_strings');
-		
+
 		$this->config->set_item('enable_query_strings', FALSE);
 
 		$this->assertEquals('index.php/test', $this->config->site_url('test'));
 		$this->assertEquals('index.php/test/1', $this->config->site_url(array('test', '1')));
-		
+
 		$this->config->set_item('enable_query_strings', TRUE);
 
 		$this->assertEquals('index.php?test', $this->config->site_url('test'));
 		$this->assertEquals('index.php?0=test&1=1', $this->config->site_url(array('test', '1')));
-		
+
 		$this->config->set_item('base_url', $base_url);
 
 		$this->assertEquals('http://example.com/index.php?test', $this->config->site_url('test'));
-		
+
 		// back to home base
-		$this->config->set_item('enable_query_strings', $q_string);				
+		$this->config->set_item('enable_query_strings', $q_string);
 	}
 
 	// --------------------------------------------------------------------
-	
+
 	public function test_system_url()
 	{
 		$this->assertEquals('http://example.com/system/', $this->config->system_url());
diff --git a/tests/codeigniter/core/Input_test.php b/tests/codeigniter/core/Input_test.php
index cfc80c9..fe87388 100644
--- a/tests/codeigniter/core/Input_test.php
+++ b/tests/codeigniter/core/Input_test.php
@@ -1,7 +1,7 @@
 <?php
 
 class Input_test extends CI_TestCase {
-	
+
 	public function set_up()
 	{
 		// Set server variable to GET as default, since this will leave unset in STDIN env
@@ -17,9 +17,9 @@
 
 		$this->input = new Mock_Core_Input($security, $utf8);
 	}
-	
+
 	// --------------------------------------------------------------------
-	
+
 	public function test_get_not_exists()
 	{
 		$this->assertEmpty($this->input->get());
@@ -38,7 +38,7 @@
 	}
 
 	// --------------------------------------------------------------------
-	
+
 	public function test_get_exist()
 	{
 		$_SERVER['REQUEST_METHOD'] = 'GET';
@@ -49,7 +49,7 @@
 	}
 
 	// --------------------------------------------------------------------
-	
+
 	public function test_get_exist_with_xss_clean()
 	{
 		$_SERVER['REQUEST_METHOD'] = 'GET';
@@ -61,7 +61,7 @@
 	}
 
 	// --------------------------------------------------------------------
-	
+
 	public function test_post_not_exists()
 	{
 		$this->assertEmpty($this->input->post());
@@ -78,7 +78,7 @@
 	}
 
 	// --------------------------------------------------------------------
-	
+
 	public function test_post_exist()
 	{
 		$_SERVER['REQUEST_METHOD'] = 'POST';
@@ -89,7 +89,7 @@
 	}
 
 	// --------------------------------------------------------------------
-	
+
 	public function test_post_exist_with_xss_clean()
 	{
 		$_SERVER['REQUEST_METHOD'] = 'POST';
@@ -101,7 +101,7 @@
 	}
 
 	// --------------------------------------------------------------------
-	
+
 	public function test_get_post()
 	{
 		$_SERVER['REQUEST_METHOD'] = 'POST';
@@ -111,7 +111,7 @@
 	}
 
 	// --------------------------------------------------------------------
-	
+
 	public function test_cookie()
 	{
 		$_COOKIE['foo'] = 'bar';
@@ -120,14 +120,14 @@
 	}
 
 	// --------------------------------------------------------------------
-	
+
 	public function test_server()
 	{
 		$this->assertEquals('GET', $this->input->server('REQUEST_METHOD'));
 	}
 
 	// --------------------------------------------------------------------
-	
+
 	public function test_fetch_from_array()
 	{
 		$data = array(
@@ -143,4 +143,19 @@
 		$this->assertEquals("Hello, i try to <script>alert('Hack');</script> your site", $harm);
 		$this->assertEquals("Hello, i try to [removed]alert&#40;'Hack'&#41;;[removed] your site", $harmless);
 	}
+
+	// --------------------------------------------------------------------
+
+	public function test_valid_ip()
+	{
+		$ip_v4 = '192.18.0.1';
+		$this->assertTrue($this->input->valid_ip($ip_v4));
+
+		$ip_v6 = array('2001:0db8:0000:85a3:0000:0000:ac1f:8001', '2001:db8:0:85a3:0:0:ac1f:8001', '2001:db8:0:85a3::ac1f:8001');
+		foreach ($ip_v6 as $ip)
+		{
+			$this->assertTrue($this->input->valid_ip($ip));
+		}
+	}
+
 }
\ No newline at end of file
diff --git a/tests/codeigniter/core/Lang_test.php b/tests/codeigniter/core/Lang_test.php
index a414f0a..a410dab 100644
--- a/tests/codeigniter/core/Lang_test.php
+++ b/tests/codeigniter/core/Lang_test.php
@@ -1,9 +1,9 @@
 <?php
 
 class Lang_test extends CI_TestCase {
-	
+
 	protected $lang;
-	
+
 	public function set_up()
 	{
 		$loader_cls = $this->ci_core_class('load');
@@ -12,20 +12,21 @@
 		$cls = $this->ci_core_class('lang');
 		$this->lang = new $cls;
 	}
-	
-	// --------------------------------------------------------------------
-	
-	public function test_load()
-	{
-		$this->assertTrue($this->lang->load('profiler', 'english'));
-	}
-	
+
 	// --------------------------------------------------------------------
 
-	public function test_line()
+	public function test_load()
 	{
 		$this->assertTrue($this->lang->load('profiler', 'english'));
 		$this->assertEquals('URI STRING', $this->lang->line('profiler_uri_string'));
 	}
-	
+
+	// --------------------------------------------------------------------
+
+	public function test_load_with_unspecified_language()
+	{
+		$this->assertTrue($this->lang->load('profiler'));
+		$this->assertEquals('URI STRING', $this->lang->line('profiler_uri_string'));
+	}
+
 }
\ No newline at end of file
diff --git a/tests/codeigniter/core/Loader_test.php b/tests/codeigniter/core/Loader_test.php
index 4300865..fdea962 100644
--- a/tests/codeigniter/core/Loader_test.php
+++ b/tests/codeigniter/core/Loader_test.php
@@ -1,35 +1,35 @@
 <?php
 
 class Loader_test extends CI_TestCase {
-	
+
 	private $ci_obj;
-	
+
 	public function set_up()
 	{
 		// Instantiate a new loader
 		$this->load = new Mock_Core_Loader();
-		
+
 		// mock up a ci instance
-		$this->ci_obj = new StdClass;
-		
+		$this->ci_obj = new stdClass;
+
 		// Fix get_instance()
 		$this->ci_instance($this->ci_obj);
 	}
 
 	// --------------------------------------------------------------------
-	
+
 	public function test_library()
 	{
 		$this->_setup_config_mock();
-		
+
 		// Test loading as an array.
 		$this->assertNull($this->load->library(array('table')));
 		$this->assertTrue(class_exists('CI_Table'), 'Table class exists');
 		$this->assertAttributeInstanceOf('CI_Table', 'table', $this->ci_obj);
-		
+
 		// Test no lib given
 		$this->assertEquals(FALSE, $this->load->library());
-		
+
 		// Test a string given to params
 		$this->assertEquals(NULL, $this->load->library('table', ' '));
 	}
@@ -39,20 +39,18 @@
 	public function test_load_library_in_application_dir()
 	{
 		$this->_setup_config_mock();
-		
+
 		$content = '<?php class Super_test_library {} ';
-		
-		$model = vfsStream::newFile('Super_test_library.php')->withContent($content)
-														->at($this->load->libs_dir);
-		
+
+		$model = vfsStream::newFile('Super_test_library.php')->withContent($content)->at($this->load->libs_dir);
 		$this->assertNull($this->load->library('super_test_library'));
-		
+
 		// Was the model class instantiated.
-		$this->assertTrue(class_exists('Super_test_library'));		
+		$this->assertTrue(class_exists('Super_test_library'));
 	}
-	
+
 	// --------------------------------------------------------------------
-	
+
 	private function _setup_config_mock()
 	{
 		// Mock up a config object until we
@@ -61,7 +59,7 @@
 		$config->expects($this->any())
 			   ->method('load')
 			   ->will($this->returnValue(TRUE));
-		
+
 		// Add the mock to our stdClass
 		$this->ci_instance_var('config', $config);
 	}
@@ -73,64 +71,62 @@
 		$this->setExpectedException(
 			'RuntimeException',
 			'CI Error: Unable to locate the model you have specified: ci_test_nonexistent_model.php'
-			);
-			
+		);
+
 		$this->load->model('ci_test_nonexistent_model.php');
 	}
 
 	// --------------------------------------------------------------------
-	
+
 	/**
 	 * @coverts CI_Loader::model
 	 */
 	public function test_models()
 	{
 		$this->ci_set_core_class('model', 'CI_Model');
-		
+
 		$content = '<?php class Unit_test_model extends CI_Model {} ';
-		
-		$model = vfsStream::newFile('unit_test_model.php')->withContent($content)
-														->at($this->load->models_dir);
-		
+
+		$model = vfsStream::newFile('unit_test_model.php')->withContent($content)->at($this->load->models_dir);
+
 		$this->assertNull($this->load->model('unit_test_model'));
-		
+
 		// Was the model class instantiated.
 		$this->assertTrue(class_exists('Unit_test_model'));
-		
+
 		// Test no model given
-		$this->assertNull($this->load->model(''));	
+		$this->assertNull($this->load->model(''));
 	}
 
 	// --------------------------------------------------------------------
-	
+
 	// public function testDatabase()
 	// {
 	// 	$this->assertEquals(NULL, $this->load->database());
-	// 	$this->assertEquals(NULL, $this->load->dbutil());		
+	// 	$this->assertEquals(NULL, $this->load->dbutil());
 	// }
 
 	// --------------------------------------------------------------------
-	
+
 	/**
 	 * @coverts CI_Loader::view
 	 */
 	public function test_load_view()
 	{
 		$this->ci_set_core_class('output', 'CI_Output');
-		
+
 		$content = 'This is my test page.  <?php echo $hello; ?>';
-		$view = vfsStream::newFile('unit_test_view.php')->withContent($content)
-														->at($this->load->views_dir);
-		
+		$view = vfsStream::newFile('unit_test_view.php')->withContent($content)->at($this->load->views_dir);
+
 		// Use the optional return parameter in this test, so the view is not
 		// run through the output class.
 		$this->assertEquals('This is my test page.  World!',
 		$this->load->view('unit_test_view', array('hello' => "World!"), TRUE));
-		
+
 	}
 
 	// --------------------------------------------------------------------
-	
+
 	/**
 	 * @coverts CI_Loader::view
 	 */
@@ -139,8 +135,8 @@
 		$this->setExpectedException(
 			'RuntimeException',
 			'CI Error: Unable to load the requested file: ci_test_nonexistent_view.php'
-			);
-			
+		);
+
 		$this->load->view('ci_test_nonexistent_view', array('foo' => 'bar'));
 	}
 
@@ -149,87 +145,77 @@
 	public function test_file()
 	{
 		$content = 'Here is a test file, which we will load now.';
-		$file = vfsStream::newFile('ci_test_mock_file.php')->withContent($content)
-														   ->at($this->load->views_dir);
-		
+		$file = vfsStream::newFile('ci_test_mock_file.php')->withContent($content)->at($this->load->views_dir);
+
 		// Just like load->view(), take the output class out of the mix here.
-		$load = $this->load->file(vfsStream::url('application').'/views/ci_test_mock_file.php', 
-								TRUE);
-		
+		$load = $this->load->file(vfsStream::url('application').'/views/ci_test_mock_file.php', TRUE);
+
 		$this->assertEquals($content, $load);
-		
+
 		$this->setExpectedException(
 			'RuntimeException',
 			'CI Error: Unable to load the requested file: ci_test_file_not_exists'
-			);
-		
+		);
+
 		$this->load->file('ci_test_file_not_exists', TRUE);
-		
 	}
 
 	// --------------------------------------------------------------------
-	
+
 	public function test_vars()
 	{
-		$vars = array(
-			'foo'	=> 'bar'
-		);
-		
-		$this->assertNull($this->load->vars($vars));
+		$this->assertNull($this->load->vars(array('foo' => 'bar')));
 		$this->assertNull($this->load->vars('foo', 'bar'));
 	}
 
 	// --------------------------------------------------------------------
-	
+
 	public function test_helper()
 	{
 		$this->assertEquals(NULL, $this->load->helper('array'));
-		
+
 		$this->setExpectedException(
 			'RuntimeException',
 			'CI Error: Unable to load the requested file: helpers/bad_helper.php'
-			);
-		
+		);
+
 		$this->load->helper('bad');
 	}
-	
+
 	// --------------------------------------------------------------------
 
 	public function test_loading_multiple_helpers()
 	{
 		$this->assertEquals(NULL, $this->load->helpers(array('file', 'array', 'string')));
 	}
-	
+
 	// --------------------------------------------------------------------
-	
+
 	// public function testLanguage()
 	// {
 	// 	$this->assertEquals(NULL, $this->load->language('test'));
-	// }	
+	// }
 
 	// --------------------------------------------------------------------
 
 	public function test_load_config()
 	{
 		$this->_setup_config_mock();
-		
 		$this->assertNull($this->load->config('config', FALSE));
 	}
-	
+
 	// --------------------------------------------------------------------
 
 	public function test_load_bad_config()
 	{
 		$this->_setup_config_mock();
-		
+
 		$this->setExpectedException(
 			'RuntimeException',
 			'CI Error: The configuration file foobar.php does not exist.'
-			);
-		
+		);
+
 		$this->load->config('foobar', FALSE);
 	}
 
-	// --------------------------------------------------------------------
-	
-}
+}
\ No newline at end of file
diff --git a/tests/codeigniter/core/Security_test.php b/tests/codeigniter/core/Security_test.php
index b2f8c69..3f6e3b0 100644
--- a/tests/codeigniter/core/Security_test.php
+++ b/tests/codeigniter/core/Security_test.php
@@ -1,7 +1,7 @@
 <?php
 
 class Security_test extends CI_TestCase {
-	
+
 	public function set_up()
 	{
 		// Set cookie for security test
@@ -14,9 +14,9 @@
 
 		$this->security = new Mock_Core_Security();
 	}
-	
+
 	// --------------------------------------------------------------------
-	
+
 	public function test_csrf_verify()
 	{
 		$_SERVER['REQUEST_METHOD'] = 'GET';
@@ -25,7 +25,7 @@
 	}
 
 	// --------------------------------------------------------------------
-	
+
 	public function test_csrf_verify_invalid()
 	{
 		// Without issuing $_POST[csrf_token_name], this request will triggering CSRF error
@@ -37,7 +37,7 @@
 	}
 
 	// --------------------------------------------------------------------
-	
+
 	public function test_csrf_verify_valid()
 	{
 		$_SERVER['REQUEST_METHOD'] = 'POST';
@@ -47,21 +47,21 @@
 	}
 
 	// --------------------------------------------------------------------
-	
+
 	public function test_get_csrf_hash()
 	{
 		$this->assertEquals($this->security->csrf_hash, $this->security->get_csrf_hash());
 	}
 
 	// --------------------------------------------------------------------
-	
+
 	public function test_get_csrf_token_name()
 	{
 		$this->assertEquals('ci_csrf_token', $this->security->get_csrf_token_name());
 	}
 
 	// --------------------------------------------------------------------
-	
+
 	public function test_xss_clean()
 	{
 		$harm_string = "Hello, i try to <script>alert('Hack');</script> your site";
@@ -72,7 +72,7 @@
 	}
 
 	// --------------------------------------------------------------------
-	
+
 	public function test_xss_hash()
 	{
 		$this->assertEmpty($this->security->xss_hash);
@@ -84,7 +84,7 @@
 	}
 
 	// --------------------------------------------------------------------
-	
+
 	public function test_entity_decode()
 	{
 		$encoded = '&lt;div&gt;Hello &lt;b&gt;Booya&lt;/b&gt;&lt;/div&gt;';
@@ -94,7 +94,7 @@
 	}
 
 	// --------------------------------------------------------------------
-	
+
 	public function test_sanitize_filename()
 	{
 		$filename = './<!--foo-->';
@@ -102,4 +102,5 @@
 
 		$this->assertEquals('foo', $safe_filename);
 	}
+
 }
\ No newline at end of file
diff --git a/tests/codeigniter/core/URI_test.php b/tests/codeigniter/core/URI_test.php
index e340ddf..60ed1a4 100644
--- a/tests/codeigniter/core/URI_test.php
+++ b/tests/codeigniter/core/URI_test.php
@@ -1,7 +1,7 @@
 <?php
 
 class URI_test extends CI_TestCase {
-	
+
 	public function set_up()
 	{
 		$this->uri = new Mock_Core_URI();
@@ -9,23 +9,21 @@
 
 	// --------------------------------------------------------------------
 
+	/* As of the following commit, _set_uri_string() is a protected method:
+
+		https://github.com/EllisLab/CodeIgniter/commit/d461934184d95b0cfb2feec93f27b621ef72a5c2
+
 	public function test_set_uri_string()
 	{
 		// Slashes get killed
 		$this->uri->_set_uri_string('/');
-		
-		$a = '';
-		$b =& $this->uri->uri_string;
-		
-		$this->assertEquals($a, $b);
-		
+		$this->assertEquals('', $this->uri->uri_string);
+
 		$this->uri->_set_uri_string('nice/uri');
-		
-		$a = 'nice/uri';
-		
-		$this->assertEquals($a, $b);
+		$this->assertEquals('nice/uri', $this->uri->uri_string);
 	}
-	
+	*/
+
 	// --------------------------------------------------------------------
 
 	public function test_fetch_uri_string()
@@ -34,75 +32,61 @@
 
 		// uri_protocol: AUTO
 		$this->uri->config->set_item('uri_protocol', 'AUTO');
-		
+
 		// Test a variety of request uris
 		$requests = array(
 			'/index.php/controller/method' => 'controller/method',
 			'/index.php?/controller/method' => 'controller/method',
 			'/index.php?/controller/method/?var=foo' => 'controller/method'
 		);
-		
+
 		foreach($requests as $request => $expected)
 		{
 			$_SERVER['SCRIPT_NAME'] = '/index.php';
 			$_SERVER['REQUEST_URI'] = $request;
-			
+
 			$this->uri->_fetch_uri_string();
 			$this->assertEquals($expected, $this->uri->uri_string );
 		}
-		
+
 		// Test a subfolder
 		$_SERVER['SCRIPT_NAME'] = '/subfolder/index.php';
 		$_SERVER['REQUEST_URI'] = '/subfolder/index.php/controller/method';
-		
+
 		$this->uri->_fetch_uri_string();
-		
-		$a = 'controller/method';
-		$b = $this->uri->uri_string;
-		
-		$this->assertEquals($a, $b);
-		
+		$this->assertEquals('controller/method', $this->uri->uri_string);
+
 		// death to request uri
 		unset($_SERVER['REQUEST_URI']);
-		
-		// life to path info
-		$_SERVER['PATH_INFO'] = '/controller/method/';
-		
-		$this->uri->_fetch_uri_string();
-		
-		$a = '/controller/method/';
-		$b =& $this->uri->uri_string;
 
-		$this->assertEquals($a, $b);
-		
+		// life to path info
+		$_SERVER['PATH_INFO'] = $a = '/controller/method/';
+
+		$this->uri->_fetch_uri_string();
+		$this->assertEquals($a, $this->uri->uri_string);
+
 		// death to path info
 		// At this point your server must be seriously drunk
 		unset($_SERVER['PATH_INFO']);
-		
-		$_SERVER['QUERY_STRING'] = '/controller/method/';
-		
-		$this->uri->_fetch_uri_string();
 
-		$a = '/controller/method/';
-		$b = $this->uri->uri_string;
-		
-		$this->assertEquals($a, $b);
-		
-		// At this point your server is a labotomy victim
-		
-		unset($_SERVER['QUERY_STRING']);
-		
-		$_GET['/controller/method/'] = '';
-		
+		$_SERVER['QUERY_STRING'] = '/controller/method/';
+
 		$this->uri->_fetch_uri_string();
-		$this->assertEquals($a, $b);
+		$this->assertEquals($a, $this->uri->uri_string);
+
+		// At this point your server is a labotomy victim
+		unset($_SERVER['QUERY_STRING']);
+
+		$_GET['/controller/method/'] = '';
+
+		$this->uri->_fetch_uri_string();
+		$this->assertEquals($a, $this->uri->uri_string);
 
 		// Test coverage implies that these will work
 		// uri_protocol: REQUEST_URI
 		// uri_protocol: CLI
-				
 	}
-	
+
 	// --------------------------------------------------------------------
 
 	public function test_explode_segments()
@@ -113,18 +97,15 @@
 			'/test2/uri2' => array('test2', 'uri2'),
 			'//test3/test3///' => array('test3', 'test3')
 		);
-		
-		foreach($uris as $uri => $a)
+
+		foreach ($uris as $uri => $a)
 		{
 			$this->uri->segments = array();
 			$this->uri->uri_string = $uri;
 			$this->uri->_explode_segments();
-			
-			$b = $this->uri->segments;
-			
-			$this->assertEquals($a, $b);
+
+			$this->assertEquals($a, $this->uri->segments);
 		}
-		
 	}
 
 	// --------------------------------------------------------------------
@@ -133,7 +114,7 @@
 	{
 		$this->uri->config->set_item('enable_query_strings', FALSE);
 		$this->uri->config->set_item('permitted_uri_chars', 'a-z 0-9~%.:_\-');
-		
+
 		$str_in = 'abc01239~%.:_-';
 		$str = $this->uri->_filter_uri($str_in);
 
@@ -145,52 +126,52 @@
 	public function test_filter_uri_escaping()
 	{
 		// ensure escaping even if dodgey characters are permitted
-		
+
 		$this->uri->config->set_item('enable_query_strings', FALSE);
 		$this->uri->config->set_item('permitted_uri_chars', 'a-z 0-9~%.:_\-()$');
 
 		$str = $this->uri->_filter_uri('$destroy_app(foo)');
-		
+
 		$this->assertEquals($str, '&#36;destroy_app&#40;foo&#41;');
 	}
 
 	// --------------------------------------------------------------------
 
-    public function test_filter_uri_throws_error()
-    {
+	public function test_filter_uri_throws_error()
+	{
 		$this->setExpectedException('RuntimeException');
-		
+
 		$this->uri->config->set_item('enable_query_strings', FALSE);
 		$this->uri->config->set_item('permitted_uri_chars', 'a-z 0-9~%.:_\-');
 		$this->uri->_filter_uri('$this()');
-    }
+	}
 
 	// --------------------------------------------------------------------
 
 	public function test_remove_url_suffix()
 	{
 		$this->uri->config->set_item('url_suffix', '.html');
-		
+
 		$this->uri->uri_string = 'controller/method/index.html';
 		$this->uri->_remove_url_suffix();
-		
+
 		$this->assertEquals($this->uri->uri_string, 'controller/method/index');
-		
+
 		$this->uri->uri_string = 'controller/method/index.htmlify.html';
 		$this->uri->_remove_url_suffix();
-		
+
 		$this->assertEquals($this->uri->uri_string, 'controller/method/index.htmlify');
 	}
 
 	// --------------------------------------------------------------------
-	
+
 	public function test_segment()
 	{
 		$this->uri->segments = array(1 => 'controller');
 		$this->assertEquals($this->uri->segment(1), 'controller');
 		$this->assertEquals($this->uri->segment(2, 'default'), 'default');
 	}
-	
+
 	// --------------------------------------------------------------------
 
 	public function test_rsegment()
@@ -205,32 +186,33 @@
 	public function test_uri_to_assoc()
 	{
 		$this->uri->segments = array('a', '1', 'b', '2', 'c', '3');
-		
-		$a = array('a' => '1', 'b' => '2', 'c' => '3');
-		$b = $this->uri->uri_to_assoc(1);
-		$this->assertEquals($a, $b);
-		
-		$a = array('b' => '2', 'c' => '3');
-		$b = $this->uri->uri_to_assoc(3);
-		$this->assertEquals($a, $b);
-		
-		
+
+		$this->assertEquals(
+			array('a' => '1', 'b' => '2', 'c' => '3'),
+			$this->uri->uri_to_assoc(1)
+		);
+
+		$this->assertEquals(
+			array('b' => '2', 'c' => '3'),
+			$this->uri->uri_to_assoc(3)
+		);
+
 		$this->uri->keyval = array(); // reset cache
-				
 		$this->uri->segments = array('a', '1', 'b', '2', 'c');
-		
-		$a = array('a' => '1', 'b' => '2', 'c' => FALSE);
-		$b = $this->uri->uri_to_assoc(1);
-		$this->assertEquals($a, $b);
-		
+
+		$this->assertEquals(
+			array('a' => '1', 'b' => '2', 'c' => FALSE),
+			$this->uri->uri_to_assoc(1)
+		);
+
 		$this->uri->keyval = array(); // reset cache
-		
 		$this->uri->segments = array('a', '1');
-		
+
 		// test default
-		$a = array('a' => '1', 'b' => FALSE);
-		$b = $this->uri->uri_to_assoc(1, array('a', 'b'));
-		$this->assertEquals($a, $b);
+		$this->assertEquals(
+			array('a' => '1', 'b' => FALSE),
+			$this->uri->uri_to_assoc(1, array('a', 'b'))
+		);
 	}
 
 	// --------------------------------------------------------------------
@@ -238,33 +220,33 @@
 	public function test_ruri_to_assoc()
 	{
 		$this->uri->rsegments = array('x', '1', 'y', '2', 'z', '3');
-		
-		$a = array('x' => '1', 'y' => '2', 'z' => '3');
-		$b = $this->uri->ruri_to_assoc(1);
-		$this->assertEquals($a, $b);
-		
-		$a = array('y' => '2', 'z' => '3');
-		$b = $this->uri->ruri_to_assoc(3);
-		$this->assertEquals($a, $b);
-		
-		
-		$this->uri->keyval = array(); // reset cache
-				
-		$this->uri->rsegments = array('x', '1', 'y', '2', 'z');
-		
-		$a = array('x' => '1', 'y' => '2', 'z' => FALSE);
-		$b = $this->uri->ruri_to_assoc(1);
-		$this->assertEquals($a, $b);
-		
-		$this->uri->keyval = array(); // reset cache
-		
-		$this->uri->rsegments = array('x', '1');
-		
-		// test default
-		$a = array('x' => '1', 'y' => FALSE);
-		$b = $this->uri->ruri_to_assoc(1, array('x', 'y'));
-		$this->assertEquals($a, $b);
 
+		$this->assertEquals(
+			array('x' => '1', 'y' => '2', 'z' => '3'),
+			$this->uri->ruri_to_assoc(1)
+		);
+
+		$this->assertEquals(
+			array('y' => '2', 'z' => '3'),
+			$this->uri->ruri_to_assoc(3)
+		);
+
+		$this->uri->keyval = array(); // reset cache
+		$this->uri->rsegments = array('x', '1', 'y', '2', 'z');
+
+		$this->assertEquals(
+			array('x' => '1', 'y' => '2', 'z' => FALSE),
+			$this->uri->ruri_to_assoc(1)
+		);
+
+		$this->uri->keyval = array(); // reset cache
+		$this->uri->rsegments = array('x', '1');
+
+		// test default
+		$this->assertEquals(
+			array('x' => '1', 'y' => FALSE),
+			$this->uri->ruri_to_assoc(1, array('x', 'y'))
+		);
 	}
 
 	// --------------------------------------------------------------------
@@ -272,11 +254,7 @@
 	public function test_assoc_to_uri()
 	{
 		$this->uri->config->set_item('uri_string_slashes', 'none');
-		
-		$arr = array('a' => 1, 'b' => 2);
-		$a = 'a/1/b/2';
-		$b = $this->uri->assoc_to_uri($arr);
-		$this->assertEquals($a, $b);
+		$this->assertEquals('a/1/b/2', $this->uri->assoc_to_uri(array('a' => '1', 'b' => '2')));
 	}
 
 	// --------------------------------------------------------------------
@@ -286,28 +264,18 @@
 		$this->uri->segments[1] = 'segment';
 		$this->uri->rsegments[1] = 'segment';
 
-		$a = '/segment/';
-		$b = $this->uri->slash_segment(1, 'both');
-		$this->assertEquals($a, $b);
-		$b = $this->uri->slash_rsegment(1, 'both');
-		$this->assertEquals($a, $b);
-		
+		$this->assertEquals('/segment/', $this->uri->slash_segment(1, 'both'));
+		$this->assertEquals('/segment/', $this->uri->slash_rsegment(1, 'both'));
+
 		$a = '/segment';
-		$b = $this->uri->slash_segment(1, 'leading');
-		$this->assertEquals($a, $b);
-		$b = $this->uri->slash_rsegment(1, 'leading');
-		$this->assertEquals($a, $b);
-		
-		$a = 'segment/';
-		$b = $this->uri->slash_segment(1, 'trailing');
-		$this->assertEquals($a, $b);
-		$b = $this->uri->slash_rsegment(1, 'trailing');
-		$this->assertEquals($a, $b);
+		$this->assertEquals('/segment', $this->uri->slash_segment(1, 'leading'));
+		$this->assertEquals('/segment', $this->uri->slash_rsegment(1, 'leading'));
+
+		$this->assertEquals('segment/', $this->uri->slash_segment(1, 'trailing'));
+		$this->assertEquals('segment/', $this->uri->slash_rsegment(1, 'trailing'));
 	}
 
-
 }
-// END URI_test Class
 
 /* End of file URI_test.php */
-/* Location: ./tests/core/URI_test.php */
+/* Location: ./tests/core/URI_test.php */
\ No newline at end of file
diff --git a/tests/codeigniter/database/query_builder/count_test.php b/tests/codeigniter/database/query_builder/count_test.php
index 5e69169..90ac528 100644
--- a/tests/codeigniter/database/query_builder/count_test.php
+++ b/tests/codeigniter/database/query_builder/count_test.php
@@ -22,10 +22,7 @@
 	 */
 	public function test_count_all()
 	{
-		$job_count = $this->db->count_all('job');
-		
-		// Check the result
-		$this->assertEquals(4, $job_count);
+		$this->assertEquals(4, $this->db->count_all('job'));
 	}
 
 	// ------------------------------------------------------------------------
@@ -35,10 +32,7 @@
 	 */
 	public function test_count_all_results()
 	{
-		$job_count = $this->db->like('name', 'ian')
-		                      ->count_all_results('job');
-		
-		// Check the result
-		$this->assertEquals(2, $job_count);
+		$this->assertEquals(2, $this->db->like('name', 'ian')->count_all_results('job'));
 	}
+
 }
\ No newline at end of file
diff --git a/tests/codeigniter/database/query_builder/delete_test.php b/tests/codeigniter/database/query_builder/delete_test.php
index 84ea761..ab9d97f 100644
--- a/tests/codeigniter/database/query_builder/delete_test.php
+++ b/tests/codeigniter/database/query_builder/delete_test.php
@@ -23,9 +23,7 @@
 	public function test_delete()
 	{
 		// Check initial record
-		$job1 = $this->db->where('id', 1)
-							->get('job')
-							->row();
+		$job1 = $this->db->where('id', 1)->get('job')->row();
 
 		$this->assertEquals('Developer', $job1->name);
 
@@ -33,8 +31,7 @@
 		$this->db->delete('job', array('id' => 1));
 
 		// Check the record
-		$job1 = $this->db->where('id', 1)
-							->get('job');
+		$job1 = $this->db->where('id', 1)->get('job');
 
 		$this->assertEmpty($job1->result_array());
 	}
@@ -47,13 +44,8 @@
 	public function test_delete_several_tables()
 	{
 		// Check initial record
-		$user4 = $this->db->where('id', 4)
-							->get('user')
-							->row();
-
-		$job4 = $this->db->where('id', 4)
-							->get('job')
-							->row();
+		$user4 = $this->db->where('id', 4)->get('user')->row();
+		$job4 = $this->db->where('id', 4)->get('job')->row();
 
 		$this->assertEquals('Musician', $job4->name);
 		$this->assertEquals('Chris Martin', $user4->name);
diff --git a/tests/codeigniter/database/query_builder/distinct_test.php b/tests/codeigniter/database/query_builder/distinct_test.php
index 925eadb..cc98009 100644
--- a/tests/codeigniter/database/query_builder/distinct_test.php
+++ b/tests/codeigniter/database/query_builder/distinct_test.php
@@ -23,11 +23,10 @@
 	public function test_distinct()
 	{
 		$users = $this->db->select('country')
-							  ->distinct()
-		                      ->get('user')
-		                      ->result_array();
-		
-		// Check the result
+					->distinct()
+					->get('user')
+					->result_array();
+
 		$this->assertEquals(3, count($users));
 	}
 
diff --git a/tests/codeigniter/database/query_builder/escape_test.php b/tests/codeigniter/database/query_builder/escape_test.php
index 5d575a3..c6380dd 100644
--- a/tests/codeigniter/database/query_builder/escape_test.php
+++ b/tests/codeigniter/database/query_builder/escape_test.php
@@ -35,7 +35,7 @@
 		}
 
 		$res = $this->db->query($sql)->result_array();
-		
+
 		// Check the result
 		$this->assertEquals(1, count($res));
 	}
@@ -60,8 +60,9 @@
 		}
 
 		$res = $this->db->query($sql)->result_array();
-		
+
 		// Check the result
 		$this->assertEquals(2, count($res));
 	}
+
 }
\ No newline at end of file
diff --git a/tests/codeigniter/database/query_builder/from_test.php b/tests/codeigniter/database/query_builder/from_test.php
index 95ae4df..7aaae34 100644
--- a/tests/codeigniter/database/query_builder/from_test.php
+++ b/tests/codeigniter/database/query_builder/from_test.php
@@ -23,10 +23,9 @@
 	public function test_from_simple()
 	{
 		$jobs = $this->db->from('job')
-		                      ->get()
-		                      ->result_array();
-		
-		// Check items
+					->get()
+					->result_array();
+
 		$this->assertEquals(4, count($jobs));
 	}
 
@@ -38,14 +37,13 @@
 	public function test_from_with_where()
 	{
 		$job1 = $this->db->from('job')
-							->where('id', 1)
-		                    ->get()
-		                    ->row();
-		
-		// Check the result
+					->where('id', 1)
+					->get()
+					->row();
+
 		$this->assertEquals('1', $job1->id);
 		$this->assertEquals('Developer', $job1->name);
 		$this->assertEquals('Awesome job, but sometimes makes you bored', $job1->description);
 	}
-	
+
 }
\ No newline at end of file
diff --git a/tests/codeigniter/database/query_builder/get_test.php b/tests/codeigniter/database/query_builder/get_test.php
index 0751c93..699d290 100644
--- a/tests/codeigniter/database/query_builder/get_test.php
+++ b/tests/codeigniter/database/query_builder/get_test.php
@@ -23,7 +23,7 @@
 	public function test_get_simple()
 	{
 		$jobs = $this->db->get('job')->result_array();
-		
+
 		// Dummy jobs contain 4 rows
 		$this->assertCount(4, $jobs);
 
@@ -42,12 +42,12 @@
 	public function test_get_where()
 	{
 		$job1 = $this->db->get('job', array('id' => 1))->result_array();
-		
+
 		// Dummy jobs contain 1 rows
 		$this->assertCount(1, $job1);
 
 		// Check rows item
 		$this->assertEquals('Developer', $job1[0]['name']);
 	}
-	
+
 }
\ No newline at end of file
diff --git a/tests/codeigniter/database/query_builder/group_test.php b/tests/codeigniter/database/query_builder/group_test.php
index 7d8abc3..5249f7c 100644
--- a/tests/codeigniter/database/query_builder/group_test.php
+++ b/tests/codeigniter/database/query_builder/group_test.php
@@ -23,12 +23,11 @@
 	public function test_group_by()
 	{
 		$jobs = $this->db->select('name')
-							  ->from('job')
-							  ->group_by('name')
-		                      ->get()
-		                      ->result_array();
-		
-		// Check the result
+					->from('job')
+					->group_by('name')
+					->get()
+					->result_array();
+
 		$this->assertEquals(4, count($jobs));
 	}
 
@@ -40,14 +39,13 @@
 	public function test_having_by()
 	{
 		$jobs = $this->db->select('name')
-							  ->from('job')
-							  ->group_by('name')
-							  ->having('SUM(id) > 2')
-		                      ->get()
-		                      ->result_array();
-		
-		// Check the result
+					->from('job')
+					->group_by('name')
+					->having('SUM(id) > 2')
+					->get()
+					->result_array();
+
 		$this->assertEquals(2, count($jobs));
 	}
-	
+
 }
\ No newline at end of file
diff --git a/tests/codeigniter/database/query_builder/join_test.php b/tests/codeigniter/database/query_builder/join_test.php
index e05329d..b8cf2a8 100644
--- a/tests/codeigniter/database/query_builder/join_test.php
+++ b/tests/codeigniter/database/query_builder/join_test.php
@@ -34,5 +34,5 @@
 		$this->assertEquals('Derek Jones', $job_user[0]['user_name']);
 		$this->assertEquals('Developer', $job_user[0]['job_name']);
 	}
-	
+
 }
\ No newline at end of file
diff --git a/tests/codeigniter/database/query_builder/like_test.php b/tests/codeigniter/database/query_builder/like_test.php
index df98c71..5f3e522 100644
--- a/tests/codeigniter/database/query_builder/like_test.php
+++ b/tests/codeigniter/database/query_builder/like_test.php
@@ -86,5 +86,5 @@
 		$this->assertEquals('Accountant', $jobs[1]['name']);
 		$this->assertEquals('Musician', $jobs[2]['name']);
 	}
-	
+
 }
\ No newline at end of file
diff --git a/tests/codeigniter/database/query_builder/limit_test.php b/tests/codeigniter/database/query_builder/limit_test.php
index 704f3b6..a0954c7 100644
--- a/tests/codeigniter/database/query_builder/limit_test.php
+++ b/tests/codeigniter/database/query_builder/limit_test.php
@@ -25,8 +25,7 @@
 		$jobs = $this->db->limit(2)
 		                      ->get('job')
 		                      ->result_array();
-		
-		// Check the result
+
 		$this->assertEquals(2, count($jobs));
 	}
 
@@ -40,10 +39,10 @@
 		$jobs = $this->db->limit(2, 2)
 		                      ->get('job')
 		                      ->result_array();
-		
-		// Check the result
+
 		$this->assertEquals(2, count($jobs));
 		$this->assertEquals('Accountant', $jobs[0]['name']);
 		$this->assertEquals('Musician', $jobs[1]['name']);
 	}
+
 }
\ No newline at end of file
diff --git a/tests/codeigniter/database/query_builder/order_test.php b/tests/codeigniter/database/query_builder/order_test.php
index 01aa1c2..46f452b 100644
--- a/tests/codeigniter/database/query_builder/order_test.php
+++ b/tests/codeigniter/database/query_builder/order_test.php
@@ -25,7 +25,7 @@
 		$jobs = $this->db->order_by('name', 'asc')
 		                      ->get('job')
 		                      ->result_array();
-		
+
 		// Check the result
 		$this->assertEquals(4, count($jobs));
 		$this->assertEquals('Accountant', $jobs[0]['name']);
@@ -44,12 +44,12 @@
 		$jobs = $this->db->order_by('name', 'desc')
 		                      ->get('job')
 		                      ->result_array();
-		
-		// Check the result
+
 		$this->assertEquals(4, count($jobs));
 		$this->assertEquals('Politician', $jobs[0]['name']);
 		$this->assertEquals('Musician', $jobs[1]['name']);
 		$this->assertEquals('Developer', $jobs[2]['name']);
 		$this->assertEquals('Accountant', $jobs[3]['name']);
 	}
+
 }
\ No newline at end of file
diff --git a/tests/codeigniter/database/query_builder/select_test.php b/tests/codeigniter/database/query_builder/select_test.php
index 0d299ed..877b5d8 100644
--- a/tests/codeigniter/database/query_builder/select_test.php
+++ b/tests/codeigniter/database/query_builder/select_test.php
@@ -25,7 +25,7 @@
 		$jobs_name = $this->db->select('name')
 		                      ->get('job')
 		                      ->result_array();
-		
+
 		// Check rows item
 		$this->assertArrayHasKey('name',$jobs_name[0]);
 		$this->assertFalse(array_key_exists('id', $jobs_name[0]));
@@ -42,7 +42,7 @@
 		$job_min = $this->db->select_min('id')
 		                    ->get('job')
 		                    ->row();
-		
+
 		// Minimum id was 1
 		$this->assertEquals('1', $job_min->id);
 	}
@@ -57,7 +57,7 @@
 		$job_max = $this->db->select_max('id')
 		                    ->get('job')
 		                    ->row();
-		
+
 		// Maximum id was 4
 		$this->assertEquals('4', $job_max->id);
 	}
@@ -72,7 +72,7 @@
 		$job_avg = $this->db->select_avg('id')
 		                    ->get('job')
 		                    ->row();
-		
+
 		// Average should be 2.5
 		$this->assertEquals('2.5', $job_avg->id);
 	}
@@ -87,9 +87,9 @@
 		$job_sum = $this->db->select_sum('id')
 		                    ->get('job')
 		                    ->row();
-		
+
 		// Sum of ids should be 10
 		$this->assertEquals('10', $job_sum->id);
 	}
-	
+
 }
\ No newline at end of file
diff --git a/tests/codeigniter/database/query_builder/truncate_test.php b/tests/codeigniter/database/query_builder/truncate_test.php
index 2a9c8a9..09923c7 100644
--- a/tests/codeigniter/database/query_builder/truncate_test.php
+++ b/tests/codeigniter/database/query_builder/truncate_test.php
@@ -24,7 +24,6 @@
 	{
 		// Check initial record
 		$jobs = $this->db->get('job')->result_array();
-
 		$this->assertEquals(4, count($jobs));
 
 		// Do the empty
@@ -32,7 +31,6 @@
 
 		// Check the record
 		$jobs = $this->db->get('job');
-
 		$this->assertEmpty($jobs->result_array());
 	}
 
@@ -45,16 +43,13 @@
 	{
 		// Check initial record
 		$users = $this->db->get('user')->result_array();
-
 		$this->assertEquals(4, count($users));
 
 		// Do the empty
-		$this->db->from('user')
-					->truncate();
+		$this->db->from('user')->truncate();
 
 		// Check the record
 		$users = $this->db->get('user');
-
 		$this->assertEmpty($users->result_array());
 	}
 
diff --git a/tests/codeigniter/database/query_builder/update_test.php b/tests/codeigniter/database/query_builder/update_test.php
index f5bbffd..27a647c 100644
--- a/tests/codeigniter/database/query_builder/update_test.php
+++ b/tests/codeigniter/database/query_builder/update_test.php
@@ -23,23 +23,14 @@
 	public function test_update()
 	{
 		// Check initial record
-		$job1 = $this->db->where('id', 1)
-							->get('job')
-							->row();
-
+		$job1 = $this->db->where('id', 1)->get('job')->row();
 		$this->assertEquals('Developer', $job1->name);
 
 		// Do the update
-		$job_data = array('name' => 'Programmer');
-
-		$this->db->where('id', 1)
-						->update('job', $job_data);
+		$this->db->where('id', 1)->update('job', array('name' => 'Programmer'));
 
 		// Check updated record
-		$job1 = $this->db->where('id', 1)
-							->get('job')
-							->row();
-
+		$job1 = $this->db->where('id', 1)->get('job')->row();
 		$this->assertEquals('Programmer', $job1->name);
 	}
 
@@ -51,10 +42,7 @@
 	public function test_update_with_set()
 	{
 		// Check initial record
-		$job1 = $this->db->where('id', 4)
-							->get('job')
-							->row();
-
+		$job1 = $this->db->where('id', 4)->get('job')->row();
 		$this->assertEquals('Musician', $job1->name);
 
 		// Do the update
@@ -62,10 +50,8 @@
 		$this->db->update('job', NULL, 'id = 4');
 
 		// Check updated record
-		$job1 = $this->db->where('id', 4)
-							->get('job')
-							->row();
-
+		$job1 = $this->db->where('id', 4)->get('job')->row();
 		$this->assertEquals('Vocalist', $job1->name);
 	}
+
 }
\ No newline at end of file
diff --git a/tests/codeigniter/database/query_builder/where_test.php b/tests/codeigniter/database/query_builder/where_test.php
index 607eaa0..20b7a56 100644
--- a/tests/codeigniter/database/query_builder/where_test.php
+++ b/tests/codeigniter/database/query_builder/where_test.php
@@ -22,11 +22,8 @@
 	 */
 	public function test_where_simple_key_value()
 	{
-		$job1 = $this->db->where('id', 1)
-							->get('job')
-							->row();
+		$job1 = $this->db->where('id', 1)->get('job')->row();
 
-		// Check the result
 		$this->assertEquals('1', $job1->id);
 		$this->assertEquals('Developer', $job1->name);
 	}
@@ -38,11 +35,7 @@
 	 */
 	public function test_where_custom_key_value()
 	{
-		$jobs = $this->db->where('id !=', 1)
-							->get('job')
-							->result_array();
-
-		// Check the result
+		$jobs = $this->db->where('id !=', 1)->get('job')->result_array();
 		$this->assertEquals(3, count($jobs));
 	}
 
@@ -54,16 +47,12 @@
 	public function test_where_associative_array()
 	{
 		$where = array('id >' => 2, 'name !=' => 'Accountant');
-		$jobs = $this->db->where($where)
-							->get('job')
-							->result_array();
+		$jobs = $this->db->where($where)->get('job')->result_array();
 
-		// Check the result
 		$this->assertEquals(1, count($jobs));
 
 		// Should be Musician
 		$job = current($jobs);
-
 		$this->assertEquals('Musician', $job['name']);
 	}
 
@@ -75,16 +64,12 @@
 	public function test_where_custom_string()
 	{
 		$where = "id > 2 AND name != 'Accountant'";
-		$jobs = $this->db->where($where)
-							->get('job')
-							->result_array();
+		$jobs = $this->db->where($where)->get('job')->result_array();
 
-		// Check the result
 		$this->assertEquals(1, count($jobs));
 
 		// Should be Musician
 		$job = current($jobs);
-
 		$this->assertEquals('Musician', $job['name']);
 	}
 
@@ -100,7 +85,6 @@
 							->get('job')
 							->result_array();
 
-		// Check the result
 		$this->assertEquals(3, count($jobs));
 		$this->assertEquals('Developer', $jobs[0]['name']);
 		$this->assertEquals('Politician', $jobs[1]['name']);
@@ -118,7 +102,6 @@
 							->get('job')
 							->result_array();
 
-		// Check the result
 		$this->assertEquals(2, count($jobs));
 		$this->assertEquals('Politician', $jobs[0]['name']);
 		$this->assertEquals('Accountant', $jobs[1]['name']);
@@ -135,10 +118,9 @@
 							->get('job')
 							->result_array();
 
-		// Check the result
 		$this->assertEquals(2, count($jobs));
 		$this->assertEquals('Developer', $jobs[0]['name']);
 		$this->assertEquals('Musician', $jobs[1]['name']);
 	}
-	
+
 }
\ No newline at end of file
diff --git a/tests/codeigniter/helpers/array_helper_test.php b/tests/codeigniter/helpers/array_helper_test.php
index 9cd1596..ba46e86 100644
--- a/tests/codeigniter/helpers/array_helper_test.php
+++ b/tests/codeigniter/helpers/array_helper_test.php
@@ -1,7 +1,7 @@
 <?php
 
 class Array_helper_test extends CI_TestCase {
-	
+
 	public function set_up()
 	{
 		$this->helper('array');
@@ -13,31 +13,31 @@
 			'herb'		=> 'cook'
 		);
 	}
-	
+
 	// ------------------------------------------------------------------------
-	
+
 	public function test_element_with_existing_item()
-	{	
+	{
 		$this->assertEquals(FALSE, element('testing', $this->my_array));
-		
+
 		$this->assertEquals('not set', element('testing', $this->my_array, 'not set'));
-		
+
 		$this->assertEquals('bar', element('foo', $this->my_array));
 	}
-	
-	// ------------------------------------------------------------------------	
+
+	// ------------------------------------------------------------------------
 
 	public function test_random_element()
 	{
 		// Send a string, not an array to random_element
 		$this->assertEquals('my string', random_element('my string'));
-		
+
 		// Test sending an array
 		$this->assertEquals(TRUE, in_array(random_element($this->my_array), $this->my_array));
 	}
 
-	// ------------------------------------------------------------------------	
-	
+	// ------------------------------------------------------------------------
+
 	public function test_elements()
 	{
 		$this->assertEquals(TRUE, is_array(elements('test', $this->my_array)));
diff --git a/tests/codeigniter/helpers/date_helper_test.php b/tests/codeigniter/helpers/date_helper_test.php
index 17d1ef2..1d397ac 100644
--- a/tests/codeigniter/helpers/date_helper_test.php
+++ b/tests/codeigniter/helpers/date_helper_test.php
@@ -5,153 +5,165 @@
 	public function set_up()
 	{
 		$this->helper('date');
+
+		$this->time = time();
 	}
 
 	// ------------------------------------------------------------------------
 
 	public function test_now_local()
 	{
+		/*
+
 		// This stub job, is simply to cater $config['time_reference']
 		$config = $this->getMock('CI_Config');
 		$config->expects($this->any())
 			   ->method('item')
 			   ->will($this->returnValue('local'));
-		
+
 		// Add the stub to our test instance
 		$this->ci_instance_var('config', $config);
 
-		$expected = time();
-		$test = now();
-		$this->assertEquals($expected, $test);
+		*/
+
+		$this->ci_set_config('time_reference', 'local');
+
+		$this->assertEquals(time(), now());
 	}
 
 	// ------------------------------------------------------------------------
 
-	public function test_now_gmt()
+	public function test_now_utc()
 	{
+		/*
+
 		// This stub job, is simply to cater $config['time_reference']
 		$config = $this->getMock('CI_Config');
 		$config->expects($this->any())
 			   ->method('item')
-			   ->will($this->returnValue('gmt'));
-		
+			   ->will($this->returnValue('UTC'));
+
 		// Add the stub to our stdClass
 		$this->ci_instance_var('config', $config);
 
-		$t = time();
-		$expected = mktime(gmdate("H", $t), gmdate("i", $t), gmdate("s", $t), gmdate("m", $t), gmdate("d", $t), gmdate("Y", $t));
-		$test = now();
-		$this->assertEquals($expected, $test);
+		*/
+
+		$this->ci_set_config('time_reference', 'UTC');
+
+		$this->assertEquals(
+			gmmktime(date('G'), date('i'), date('s'), date('n'), date('j'), date('Y')),
+			now()
+		);
 	}
 
 	// ------------------------------------------------------------------------
 
 	public function test_mdate()
 	{
-		$time = time();
-		$expected = date("Y-m-d - h:i a", $time);
-		$test = mdate("%Y-%m-%d - %h:%i %a", $time);
-		$this->assertEquals($expected, $test);
+		$this->assertEquals(
+			date('Y-m-d - h:i a', $this->time),
+			mdate('%Y-%m-%d - %h:%i %a', $this->time)
+		);
 	}
 
 	// ------------------------------------------------------------------------
 
 	public function test_standard_date_rfc822()
 	{
-		$time = time();
-		$format = 'DATE_RFC822';
-		$expected = date("D, d M y H:i:s O", $time);
-		$this->assertEquals($expected, standard_date($format, $time));
+		$this->assertEquals(
+			date('D, d M y H:i:s O', $this->time),
+			standard_date('DATE_RFC822', $this->time)
+		);
 	}
 
 	// ------------------------------------------------------------------------
 
 	public function test_standard_date_atom()
 	{
-		$time = time();
-		$format = 'DATE_ATOM';
-		$expected = date("Y-m-d\TH:i:sO", $time);
-		$this->assertEquals($expected, standard_date($format, $time));
+		$this->assertEquals(
+			date("Y-m-d\TH:i:sO", $this->time),
+			standard_date('DATE_ATOM', $this->time)
+		);
 	}
 
 	// ------------------------------------------------------------------------
 
 	public function test_standard_date_cookie()
 	{
-		$time = time();
-		$format = 'DATE_COOKIE';
-		$expected = date("l, d-M-y H:i:s \U\T\C", $time);
-		$this->assertEquals($expected, standard_date($format, $time));
+		$this->assertEquals(
+			date("l, d-M-y H:i:s \U\T\C", $this->time),
+			standard_date('DATE_COOKIE', $this->time)
+		);
 	}
 
 	// ------------------------------------------------------------------------
 
 	public function test_standard_date_iso8601()
 	{
-		$time = time();
-		$format = 'DATE_ISO8601';
-		$expected = date("Y-m-d\TH:i:sO", $time);
-		$this->assertEquals($expected, standard_date($format, $time));
+		$this->assertEquals(
+			date("Y-m-d\TH:i:sO", $this->time),
+			standard_date('DATE_ISO8601', $this->time)
+		);
 	}
 
 	// ------------------------------------------------------------------------
 
 	public function test_standard_date_rfc850()
 	{
-		$time = time();
-		$format = 'DATE_RFC850';
-		$expected = date("l, d-M-y H:i:s \U\T\C", $time);
-		$this->assertEquals($expected, standard_date($format, $time));
+		$this->assertEquals(
+			date("l, d-M-y H:i:s \U\T\C", $this->time),
+			standard_date('DATE_RFC850', $this->time)
+		);
 	}
 
 	// ------------------------------------------------------------------------
 
 	public function test_standard_date_rfc1036()
 	{
-		$time = time();
-		$format = 'DATE_RFC1036';
-		$expected = date("D, d M y H:i:s O", $time);
-		$this->assertEquals($expected, standard_date($format, $time));
+		$this->assertEquals(
+			date('D, d M y H:i:s O', $this->time),
+			standard_date('DATE_RFC1036', $this->time)
+		);
 	}
 
 	// ------------------------------------------------------------------------
 
 	public function test_standard_date_rfc1123()
 	{
-		$time = time();
-		$format = 'DATE_RFC1123';
-		$expected = date("D, d M Y H:i:s O", $time);
-		$this->assertEquals($expected, standard_date($format, $time));
+		$this->assertEquals(
+			date('D, d M Y H:i:s O', $this->time),
+			standard_date('DATE_RFC1123', $this->time)
+		);
 	}
 
 	// ------------------------------------------------------------------------
 
 	public function test_standard_date_rfc2822()
 	{
-		$time = time();
-		$format = 'DATE_RFC2822';
-		$expected = date("D, d M Y H:i:s O", $time);
-		$this->assertEquals($expected, standard_date($format, $time));
+		$this->assertEquals(
+			date('D, d M Y H:i:s O', $this->time),
+			standard_date('DATE_RFC2822', $this->time)
+		);
 	}
 
 	// ------------------------------------------------------------------------
 
 	public function test_standard_date_rss()
 	{
-		$time = time();
-		$format = 'DATE_RSS';
-		$expected = date("D, d M Y H:i:s O", $time);
-		$this->assertEquals($expected, standard_date($format, $time));
+		$this->assertEquals(
+			date('D, d M Y H:i:s O', $this->time),
+			standard_date('DATE_RSS', $this->time)
+		);
 	}
 
 	// ------------------------------------------------------------------------
 
 	public function test_standard_date_w3c()
 	{
-		$time = time();
-		$format = 'DATE_W3C';
-		$expected = date("Y-m-d\TH:i:sO", $time);
-		$this->assertEquals($expected, standard_date($format, $time));
+		$this->assertEquals(
+			date("Y-m-d\TH:i:sO", $this->time),
+			standard_date('DATE_W3C', $this->time)
+		);
 	}
 
 	// ------------------------------------------------------------------------
@@ -183,39 +195,36 @@
 
 	public function test_local_to_gmt()
 	{
-		$t = time();
-		$expected = mktime(gmdate("H", $t), gmdate("i", $t), gmdate("s", $t), gmdate("m", $t), gmdate("d", $t), gmdate("Y", $t));
-		$this->assertEquals($expected, local_to_gmt($t));
+		$this->assertEquals(
+			gmmktime(
+				date('G', $this->time), date('i', $this->time), date('s', $this->time),
+				date('n', $this->time), date('j', $this->time), date('Y', $this->time)
+			),
+			local_to_gmt($this->time)
+		);
 	}
 
 	// ------------------------------------------------------------------------
 
 	public function test_gmt_to_local()
 	{
-		$timestamp = '1140153693';
-		$timezone = 'UM8';
-		$daylight_saving = TRUE;
-
-		$this->assertEquals(1140128493, gmt_to_local($timestamp, $timezone, $daylight_saving));
+		$this->assertEquals(1140128493, gmt_to_local('1140153693', 'UM8', TRUE));
 	}
 
 	// ------------------------------------------------------------------------
 
 	public function test_mysql_to_unix()
 	{
-		$time = time();
-		$this->assertEquals($time, 
-				mysql_to_unix(date("Y-m-d H:i:s", $time)));
+		$this->assertEquals($this->time, mysql_to_unix(date('Y-m-d H:i:s', $this->time)));
 	}
 
 	// ------------------------------------------------------------------------
 
 	public function test_unix_to_human()
 	{
-		$time = time();
-		$this->assertEquals(date("Y-m-d h:i A", $time), unix_to_human($time));
-		$this->assertEquals(date("Y-m-d h:i:s A", $time), unix_to_human($time, TRUE, 'us'));
-		$this->assertEquals(date("Y-m-d H:i:s", $time), unix_to_human($time, TRUE, 'eu'));
+		$this->assertEquals(date('Y-m-d h:i A', $this->time), unix_to_human($this->time));
+		$this->assertEquals(date('Y-m-d h:i:s A', $this->time), unix_to_human($this->time, TRUE, 'us'));
+		$this->assertEquals(date('Y-m-d H:i:s', $this->time), unix_to_human($this->time, TRUE, 'eu'));
 	}
 
 	// ------------------------------------------------------------------------
@@ -223,8 +232,7 @@
 	public function test_human_to_unix()
 	{
 		$date = '2000-12-31 10:00:00 PM';
-		$expected = strtotime($date);
-		$this->assertEquals($expected, human_to_unix($date));
+		$this->assertEquals(strtotime($date), human_to_unix($date));
 		$this->assertFalse(human_to_unix());
 	}
 
@@ -283,6 +291,7 @@
 		$this->assertArrayHasKey('UP3', timezones());
 		$this->assertEquals(0, timezones('non_existant'));
 	}
+
 }
 
 /* End of file date_helper_test.php */
\ No newline at end of file
diff --git a/tests/codeigniter/helpers/directory_helper_test.php b/tests/codeigniter/helpers/directory_helper_test.php
index 3937d29..176ff1d 100644
--- a/tests/codeigniter/helpers/directory_helper_test.php
+++ b/tests/codeigniter/helpers/directory_helper_test.php
@@ -1,41 +1,50 @@
 <?php
 
 class Directory_helper_test extends CI_TestCase {
-	
+
 	public function set_up()
 	{
 		$this->helper('directory');
 
 		vfsStreamWrapper::register();
 		vfsStreamWrapper::setRoot(new vfsStreamDirectory('testDir'));
-		
+
 		$this->_test_dir = vfsStreamWrapper::getRoot();
-	}	
-	
+	}
+
 	public function test_directory_map()
 	{
-		$structure = array('libraries' => array('benchmark.html' => '', 'database' =>
-			array('active_record.html' => '', 'binds.html' => ''), 'email.html' => '', '.hiddenfile.txt' => ''));
-		
+		$structure = array(
+			'libraries' => array(
+				'benchmark.html' => '',
+				'database' => array('active_record.html' => '', 'binds.html' => ''),
+				'email.html' => '',
+				'.hiddenfile.txt' => ''
+			)
+		);
+
 		vfsStream::create($structure, $this->_test_dir);
 
 		// test default recursive behavior
-		$expected = array('libraries' => array('benchmark.html', 'database' =>
-			array('active_record.html', 'binds.html'), 'email.html'));
-			
+		$expected = array(
+			'libraries' => array(
+				'benchmark.html',
+				'database' => array('active_record.html', 'binds.html'),
+				'email.html'
+			)
+		);
+
 		$this->assertEquals($expected, directory_map(vfsStream::url('testDir')));
 
-		// test recursion depth behavior
-		$expected = array('libraries');
-			
-		$this->assertEquals($expected, directory_map(vfsStream::url('testDir'), 1));
-
 		// test detection of hidden files
-		$expected = array('libraries' => array('benchmark.html', 'database' =>
-			array('active_record.html', 'binds.html'), 'email.html', '.hiddenfile.txt'));
-			
+		$expected['libraries'][] = '.hiddenfile.txt';
+
 		$this->assertEquals($expected, directory_map(vfsStream::url('testDir'), FALSE, TRUE));
-  }  
+
+		// test recursion depth behavior
+		$this->assertEquals(array('libraries'), directory_map(vfsStream::url('testDir'), 1));
+	}
+
 }
 
 /* End of file directory_helper_test.php */
\ No newline at end of file
diff --git a/tests/codeigniter/helpers/email_helper_test.php b/tests/codeigniter/helpers/email_helper_test.php
index a01f3d5..fea452f 100644
--- a/tests/codeigniter/helpers/email_helper_test.php
+++ b/tests/codeigniter/helpers/email_helper_test.php
@@ -14,5 +14,5 @@
 		$this->assertEquals(TRUE, valid_email('test@test.com'));
 		$this->assertEquals(TRUE, valid_email('my.test@test.com'));
 	}
-	
+
 }
\ No newline at end of file
diff --git a/tests/codeigniter/helpers/file_helper_test.php b/tests/codeigniter/helpers/file_helper_test.php
index 4b9c294..9b03da9 100644
--- a/tests/codeigniter/helpers/file_helper_test.php
+++ b/tests/codeigniter/helpers/file_helper_test.php
@@ -5,24 +5,23 @@
 	public function set_up()
 	{
 		$this->helper('file');
-		
+
 		vfsStreamWrapper::register();
 		vfsStreamWrapper::setRoot(new vfsStreamDirectory('testDir'));
-		
+
 		$this->_test_dir = vfsStreamWrapper::getRoot();
 	}
-	
+
 	// --------------------------------------------------------------------
-	
+
 	public function test_read_file()
 	{
 		$this->assertFalse(read_file('does_not_exist'));
-		
+
 		$content = 'Jack and Jill went up the mountain to fight a billy goat.';
-		
-		$file = vfsStream::newFile('my_file.txt')->withContent($content)
-												 ->at($this->_test_dir);
-		
+
+		$file = vfsStream::newFile('my_file.txt')->withContent($content)->at($this->_test_dir);
+
 		$this->assertEquals($content, read_file(vfsStream::url('my_file.txt')));
 	}
 
@@ -31,126 +30,124 @@
 	public function test_octal_permissions()
 	{
 		$content = 'Jack and Jill went up the mountain to fight a billy goat.';
-		
+
 		$file = vfsStream::newFile('my_file.txt', 0777)->withContent($content)
-												 ->lastModified(time() - 86400)
-												 ->at($this->_test_dir);
-		
-		$this->assertEquals('777', octal_permissions($file->getPermissions()));		
+											 ->lastModified(time() - 86400)
+											 ->at($this->_test_dir);
+
+		$this->assertEquals('777', octal_permissions($file->getPermissions()));
 	}
 
-	// --------------------------------------------------------------------	
-	
+	// --------------------------------------------------------------------
+
 	/**
 	 * More tests should happen here, since I'm not hitting the whole function.
 	 */
 	public function test_symbolic_permissions()
 	{
 		$content = 'Jack and Jill went up the mountain to fight a billy goat.';
-		
+
 		$file = vfsStream::newFile('my_file.txt', 0777)->withContent($content)
-												 ->lastModified(time() - 86400)
-												 ->at($this->_test_dir);
-												
-		$this->assertEquals('urwxrwxrwx', symbolic_permissions($file->getPermissions()));		
+											 ->lastModified(time() - 86400)
+											 ->at($this->_test_dir);
+
+		$this->assertEquals('urwxrwxrwx', symbolic_permissions($file->getPermissions()));
 	}
 
-	// --------------------------------------------------------------------	
-	
+	// --------------------------------------------------------------------
+
 	public function test_get_mime_by_extension()
 	{
 		$content = 'Jack and Jill went up the mountain to fight a billy goat.';
-		
+
 		$file = vfsStream::newFile('my_file.txt', 0777)->withContent($content)
-												 ->lastModified(time() - 86400)
-												 ->at($this->_test_dir);
-												
-		$this->assertEquals('text/plain', 
-						get_mime_by_extension(vfsStream::url('my_file.txt')));
-						
-		// Test a mime with an array, such as png		
+											 ->lastModified(time() - 86400)
+											 ->at($this->_test_dir);
+
+		$this->assertEquals('text/plain', get_mime_by_extension(vfsStream::url('my_file.txt')));
+
+		// Test a mime with an array, such as png
 		$file = vfsStream::newFile('foo.png')->at($this->_test_dir);
-		
-		$this->assertEquals('image/png', get_mime_by_extension(vfsStream::url('foo.png')));			
-			
+
+		$this->assertEquals('image/png', get_mime_by_extension(vfsStream::url('foo.png')));
+
 		// Test a file not in the mimes array
 		$file = vfsStream::newFile('foo.blarfengar')->at($this->_test_dir);
-		
+
 		$this->assertFalse(get_mime_by_extension(vfsStream::url('foo.blarfengar')));
 	}
 
-	// --------------------------------------------------------------------	
+	// --------------------------------------------------------------------
 
 	public function test_get_file_info()
 	{
 		// Test Bad File
 		$this->assertFalse(get_file_info('i_am_bad_boo'));
-		
+
 		// Test the rest
-		
+
 		// First pass in an array
 		$vals = array(
 			'name', 'server_path', 'size', 'date',
-			'readable', 'writable', 'executable',  'fileperms'
+			'readable', 'writable', 'executable', 'fileperms'
 		);
-		
+
 		$this->_test_get_file_info($vals);
 
 		// Test passing in vals as a string.
-		$vals = 'name, server_path, size, date, readable, writable, executable, fileperms';
-		$this->_test_get_file_info($vals);
+		$this->_test_get_file_info(implode(', ', $vals));
 	}
-	
+
 	private function _test_get_file_info($vals)
 	{
 		$content = 'Jack and Jill went up the mountain to fight a billy goat.';
 		$last_modified = time() - 86400;
-		
+
 		$file = vfsStream::newFile('my_file.txt', 0777)->withContent($content)
-												 ->lastModified($last_modified)
-												 ->at($this->_test_dir);
-		
+											 ->lastModified($last_modified)
+											 ->at($this->_test_dir);
+
 		$ret_values = array(
-			'name'			=> 'my_file.txt', 
-			'server_path'	=> 'vfs://my_file.txt', 
-			'size'			=> 57, 
-			'date'			=> $last_modified, 
+			'name'			=> 'my_file.txt',
+			'server_path'	=> 'vfs://my_file.txt',
+			'size'			=> 57,
+			'date'			=> $last_modified,
 			'readable'		=> TRUE,
-			'writable'		=> TRUE, 
-			'executable'	=> TRUE, 
+			'writable'		=> TRUE,
+			'executable'	=> TRUE,
 			'fileperms'		=> 33279
 		);
-		
+
 		$info = get_file_info(vfsStream::url('my_file.txt'), $vals);
-		
+
 		foreach ($info as $k => $v)
 		{
 			$this->assertEquals($ret_values[$k], $v);
 		}
 	}
-	
-	// --------------------------------------------------------------------	
+
+	// --------------------------------------------------------------------
 
 	// Skipping for now, as it's not implemented in vfsStreamWrapper
 	// flock(): vfsStreamWrapper::stream_lock is not implemented!
-	
+
 	// public function test_write_file()
 	// {
-	// 	if ( ! defined('FOPEN_WRITE_CREATE_DESTRUCTIVE'))
-	// 	{
-	// 		define('FOPEN_WRITE_CREATE_DESTRUCTIVE', 'wb');
-	// 	}
-	// 	
-	// 	$content = 'Jack and Jill went up the mountain to fight a billy goat.';
-	// 	
-	// 	$file = vfsStream::newFile('write.txt', 0777)->withContent('')
-	// 											 	 ->lastModified(time() - 86400)
-	// 											 	 ->at($this->_test_dir);
-	// 	
-	// 	$this->assertTrue(write_file(vfsStream::url('write.txt'), $content));
-	// 		
+	//	if ( ! defined('FOPEN_WRITE_CREATE_DESTRUCTIVE'))
+	//	{
+	//		define('FOPEN_WRITE_CREATE_DESTRUCTIVE', 'wb');
+	//	}
+	//
+	//	$content = 'Jack and Jill went up the mountain to fight a billy goat.';
+	//
+	//	$file = vfsStream::newFile('write.txt', 0777)->withContent('')
+	//								 	 ->lastModified(time() - 86400)
+	//								 	 ->at($this->_test_dir);
+	//
+	//	$this->assertTrue(write_file(vfsStream::url('write.txt'), $content));
+	//
 	// }
 
-	// --------------------------------------------------------------------		
-	
+	// --------------------------------------------------------------------
+
 }
\ No newline at end of file
diff --git a/tests/codeigniter/helpers/form_helper_test.php b/tests/codeigniter/helpers/form_helper_test.php
index 80bace9..1a30ed9 100644
--- a/tests/codeigniter/helpers/form_helper_test.php
+++ b/tests/codeigniter/helpers/form_helper_test.php
@@ -3,26 +3,26 @@
 require BASEPATH . 'core/Common.php';
 require BASEPATH . 'helpers/form_helper.php';
 
-class Form_helper_test extends CI_TestCase 
+class Form_helper_test extends CI_TestCase
 {
 	public function test_form_hidden()
-	{				
+	{
 		$expected = <<<EOH
 
 <input type="hidden" name="username" value="johndoe" />
 
 EOH;
-	
+
 		$this->assertEquals($expected, form_hidden('username', 'johndoe'));
 	}
-	
+
 	public function test_form_input()
 	{
 		$expected = <<<EOH
 <input type="text" name="username" value="johndoe" id="username" maxlength="100" size="50" style="width:50%"  />
 
 EOH;
-	
+
 		$data = array(
 			'name'        => 'username',
 			'id'          => 'username',
@@ -34,37 +34,37 @@
 
 		$this->assertEquals($expected, form_input($data));
 	}
-	
+
 	public function test_form_password()
-	{				
+	{
 		$expected = <<<EOH
 <input type="password" name="password" value=""  />
 
 EOH;
-	
+
 		$this->assertEquals($expected, form_password('password'));
 	}
-	
+
 	public function test_form_upload()
-	{				
+	{
 		$expected = <<<EOH
 <input type="file" name="attachment" value=""  />
 
 EOH;
-	
+
 		$this->assertEquals($expected, form_upload('attachment'));
 	}
-	
+
 	public function test_form_textarea()
-	{				
+	{
 		$expected = <<<EOH
 <textarea name="notes" cols="40" rows="10" >Notes</textarea>
 
 EOH;
-	
+
 		$this->assertEquals($expected, form_textarea('notes', 'Notes'));
 	}
-	
+
 	public function test_form_dropdown()
 	{
 		$expected = <<<EOH
@@ -76,16 +76,16 @@
 </select>
 
 EOH;
-		
+
 		$options = array(
-			'small'  => 'Small Shirt',
-			'med'    => 'Medium Shirt',
-			'large'   => 'Large Shirt',
-			'xlarge' => 'Extra Large Shirt',
+			'small'		=> 'Small Shirt',
+			'med'		=> 'Medium Shirt',
+			'large'		=> 'Large Shirt',
+			'xlarge'	=> 'Extra Large Shirt',
 		);
-		
+
 		$this->assertEquals($expected, form_dropdown('shirts', $options, 'large'));
-		
+
 		$expected = <<<EOH
 <select name="shirts" multiple="multiple">
 <option value="small" selected="selected">Small Shirt</option>
@@ -95,22 +95,22 @@
 </select>
 
 EOH;
-		
+
 		$shirts_on_sale = array('small', 'large');
-		
+
 		$this->assertEquals($expected, form_dropdown('shirts', $options, $shirts_on_sale));
-		
+
 		$options = array(
 			'Swedish Cars' => array(
-				'volvo'  => 'Volvo',
-				'saab'    => 'Saab'
+				'volvo'	=> 'Volvo',
+				'saab'	=> 'Saab'
 			),
 			'German Cars' => array(
-				'mercedes'  => 'Mercedes',
-				'audi'    => 'Audi'
+				'mercedes'	=> 'Mercedes',
+				'audi'		=> 'Audi'
 			)
 		);
-		
+
 		$expected = <<<EOH
 <select name="cars" multiple="multiple">
 <optgroup label="Swedish Cars">
@@ -124,13 +124,10 @@
 </select>
 
 EOH;
-		
-		$cars_on_sale = array('volvo', 'audi');
-		
-		$this->assertEquals($expected, form_dropdown('cars', $options, $cars_on_sale));
-		
+
+		$this->assertEquals($expected, form_dropdown('cars', $options, array('volvo', 'audi')));
 	}
-	
+
 	public function test_form_multiselect()
 	{
 		$expected = <<<EOH
@@ -142,17 +139,17 @@
 </select>
 
 EOH;
-		
+
 		$options = array(
-                  'small'  => 'Small Shirt',
-                  'med'    => 'Medium Shirt',
-                  'large'   => 'Large Shirt',
-                  'xlarge' => 'Extra Large Shirt',
-                );
-		
+			'small'		=> 'Small Shirt',
+			'med'		=> 'Medium Shirt',
+			'large'		=> 'Large Shirt',
+			'xlarge'	=> 'Extra Large Shirt',
+		);
+
 		$this->assertEquals($expected, form_multiselect('shirts[]', $options, array('med', 'large')));
 	}
-	
+
 	public function test_form_fieldset()
 	{
 		$expected = <<<EOH
@@ -160,7 +157,7 @@
 <legend>Address Information</legend>
 
 EOH;
-		
+
 		$this->assertEquals($expected, form_fieldset('Address Information'));
 	}
 
@@ -169,10 +166,10 @@
 		$expected = <<<EOH
 </fieldset></div></div>
 EOH;
-		
+
 		$this->assertEquals($expected, form_fieldset_close('</div></div>'));
 	}
-	
+
 	public function test_form_checkbox()
 	{
 		$expected = <<<EOH
@@ -182,7 +179,7 @@
 
 		$this->assertEquals($expected, form_checkbox('newsletter', 'accept', TRUE));
 	}
-	
+
 	public function test_form_radio()
 	{
 		$expected = <<<EOH
@@ -192,7 +189,7 @@
 
 		$this->assertEquals($expected, form_radio('newsletter', 'accept', TRUE));
 	}
-	
+
 	public function test_form_submit()
 	{
 		$expected = <<<EOH
@@ -202,7 +199,7 @@
 
 		$this->assertEquals($expected, form_submit('mysubmit', 'Submit Post!'));
 	}
-	
+
 	public function test_form_label()
 	{
 		$expected = <<<EOH
@@ -211,7 +208,7 @@
 
 		$this->assertEquals($expected, form_label('What is your Name', 'username'));
 	}
-	
+
 	public function test_form_reset()
 	{
 		$expected = <<<EOH
@@ -221,7 +218,7 @@
 
 		$this->assertEquals($expected, form_reset('myreset', 'Reset'));
 	}
-	
+
 	public function test_form_button()
 	{
 		$expected = <<<EOH
@@ -229,9 +226,9 @@
 
 EOH;
 
-		$this->assertEquals($expected, form_button('name','content'));
+		$this->assertEquals($expected, form_button('name', 'content'));
 	}
-	
+
 	public function test_form_close()
 	{
 		$expected = <<<EOH
@@ -240,13 +237,14 @@
 
 		$this->assertEquals($expected, form_close('</div></div>'));
 	}
-	
+
 	public function test_form_prep()
 	{
-		$expected = "Here is a string containing &quot;quoted&quot; text.";
-		
+		$expected = 'Here is a string containing &quot;quoted&quot; text.';
+
 		$this->assertEquals($expected, form_prep('Here is a string containing "quoted" text.'));
 	}
+
 }
 
 /* End of file form_helper_test.php */
\ No newline at end of file
diff --git a/tests/codeigniter/helpers/html_helper_test.php b/tests/codeigniter/helpers/html_helper_test.php
index 28974b0..9a7bb48 100644
--- a/tests/codeigniter/helpers/html_helper_test.php
+++ b/tests/codeigniter/helpers/html_helper_test.php
@@ -6,16 +6,16 @@
 	{
 		$this->helper('html');
 	}
-	
+
 	// ------------------------------------------------------------------------
-	
+
 	public function test_br()
 	{
 		$this->assertEquals('<br /><br />', br(2));
 	}
-	
+
 	// ------------------------------------------------------------------------
-	
+
 	public function test_heading()
 	{
 		$this->assertEquals('<h1>foobar</h1>', heading('foobar'));
@@ -23,7 +23,7 @@
 	}
 
 	// ------------------------------------------------------------------------
-	
+
 	public function test_Ul()
 	{
 		$expect = <<<EOH
@@ -35,11 +35,9 @@
 EOH;
 
 		$expect = ltrim($expect);
-
 		$list = array('foo', 'bar');
-		
-		$this->assertEquals($expect, ul($list));
 
+		$this->assertEquals(ltrim($expect), ul($list));
 
 		$expect = <<<EOH
 <ul class="test">
@@ -51,13 +49,11 @@
 
 		$expect = ltrim($expect);
 
-		$list = array('foo', 'bar');
-
 		$this->assertEquals($expect, ul($list, 'class="test"'));
 
 		$this->assertEquals($expect, ul($list, array('class' => 'test')));
 	}
-	
+
 	// ------------------------------------------------------------------------
 
 	public function test_NBS()
@@ -66,15 +62,15 @@
 	}
 
 	// ------------------------------------------------------------------------
-	
+
 	public function test_meta()
 	{
 		$this->assertEquals("<meta name=\"test\" content=\"foo\" />\n", meta('test', 'foo'));
-		
+
 		$expect = "<meta name=\"foo\" content=\"\" />\n";
-		
+
 		$this->assertEquals($expect, meta(array('name' => 'foo')));
-		
+
 	}
-	
+
 }
\ No newline at end of file
diff --git a/tests/codeigniter/helpers/inflector_helper_test.php b/tests/codeigniter/helpers/inflector_helper_test.php
index 9e94787..f3b0ebb 100644
--- a/tests/codeigniter/helpers/inflector_helper_test.php
+++ b/tests/codeigniter/helpers/inflector_helper_test.php
@@ -1,12 +1,12 @@
 <?php
 
 class Inflector_helper_test extends CI_TestCase {
-	
+
 	public function set_up()
 	{
 		$this->helper('inflector');
 	}
-	
+
 	public function test_singular()
 	{
 		$strs = array(
@@ -16,15 +16,15 @@
 			'smells'		=> 'smell',
 			'equipment'		=> 'equipment'
 		);
-		
+
 		foreach ($strs as $str => $expect)
 		{
 			$this->assertEquals($expect, singular($str));
 		}
 	}
-	
+
 	// --------------------------------------------------------------------
-	
+
 	public function test_plural()
 	{
 		$strs = array(
@@ -35,15 +35,15 @@
 			'witch'			=> 'witches',
 			'equipment'		=> 'equipment'
 		);
-		
+
 		foreach ($strs as $str => $expect)
 		{
 			$this->assertEquals($expect, plural($str));
-		}		
-	}	
+		}
+	}
 
 	// --------------------------------------------------------------------
-	
+
 	public function test_camelize()
 	{
 		$strs = array(
@@ -52,15 +52,15 @@
 			'i-am-playing-a-trick'	=> 'i-am-playing-a-trick',
 			'what_do_you_think-yo?'	=> 'whatDoYouThink-yo?',
 		);
-		
+
 		foreach ($strs as $str => $expect)
 		{
 			$this->assertEquals($expect, camelize($str));
 		}
-	}	
+	}
 
 	// --------------------------------------------------------------------
-	
+
 	public function test_underscore()
 	{
 		$strs = array(
@@ -69,7 +69,7 @@
 			'i-am-playing-a-trick'	=> 'i-am-playing-a-trick',
 			'what_do_you_think-yo?'	=> 'what_do_you_think-yo?',
 		);
-		
+
 		foreach ($strs as $str => $expect)
 		{
 			$this->assertEquals($expect, underscore($str));
@@ -77,7 +77,7 @@
 	}
 
 	// --------------------------------------------------------------------
-	
+
 	public function test_humanize()
 	{
 		$strs = array(
@@ -86,10 +86,11 @@
 			'i-am-playing-a-trick'	=> 'I-am-playing-a-trick',
 			'what_do_you_think-yo?'	=> 'What Do You Think-yo?',
 		);
-		
+
 		foreach ($strs as $str => $expect)
 		{
 			$this->assertEquals($expect, humanize($str));
 		}
 	}
+
 }
\ No newline at end of file
diff --git a/tests/codeigniter/helpers/number_helper_test.php b/tests/codeigniter/helpers/number_helper_test.php
index 4bb9a91..ef6aae1 100644
--- a/tests/codeigniter/helpers/number_helper_test.php
+++ b/tests/codeigniter/helpers/number_helper_test.php
@@ -1,35 +1,35 @@
 <?php
 
 class Number_helper_test extends CI_TestCase {
-	
+
 	public function set_up()
 	{
 		$this->helper('number');
-		
+
 		// Grab the core lang class
 		$lang_cls = $this->ci_core_class('lang');
-		
+
 		// Mock away load, too much going on in there,
 		// we'll just check for the expected parameter
-		
+
 		$lang = $this->getMock($lang_cls, array('load'));
 		$lang->expects($this->once())
 			 ->method('load')
 			 ->with($this->equalTo('number'));
-		
+
 		// Assign the proper language array
-		
+
 		$lang->language = $this->_get_lang('number');
-		
+
 		// We don't have a controller, so just create
 		// a cheap class to act as our super object.
 		// Make sure it has a lang attribute.
-		
-		$obj = new StdClass;
+
+		$obj = new stdClass;
 		$obj->lang = $lang;
 		$this->ci_instance($obj);
 	}
-	
+
 	// Quick helper to actually grab the language
 	// file. Consider moving this to ci_testcase?
 	public function _get_lang($name)
@@ -37,41 +37,40 @@
 		require BASEPATH.'language/english/'.$name.'_lang.php';
 		return $lang;
 	}
-	
+
 	public function test_byte_format()
 	{
 		$this->assertEquals('456 Bytes', byte_format(456));
 	}
-	
+
 	public function test_kb_format()
 	{
 		$this->assertEquals('4.5 KB', byte_format(4567));
 	}
-	
+
 	public function test_kb_format_medium()
 	{
 		$this->assertEquals('44.6 KB', byte_format(45678));
 	}
-	
+
 	public function test_kb_format_large()
 	{
 		$this->assertEquals('446.1 KB', byte_format(456789));
 	}
-	
+
 	public function test_mb_format()
 	{
 		$this->assertEquals('3.3 MB', byte_format(3456789));
 	}
-	
+
 	public function test_gb_format()
 	{
 		$this->assertEquals('1.8 GB', byte_format(1932735283.2));
 	}
-	
+
 	public function test_tb_format()
 	{
 		$this->assertEquals('112,283.3 TB', byte_format(123456789123456789));
 	}
-}
 
-// EOF
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/tests/codeigniter/helpers/path_helper_test.php b/tests/codeigniter/helpers/path_helper_test.php
index 632f575..0faf6f3 100644
--- a/tests/codeigniter/helpers/path_helper_test.php
+++ b/tests/codeigniter/helpers/path_helper_test.php
@@ -8,9 +8,8 @@
 	}
 
 	public function test_set_realpath()
-	{				
-		$expected = getcwd() . DIRECTORY_SEPARATOR;
-		$this->assertEquals($expected, set_realpath(getcwd()));		
+	{
+		$this->assertEquals(getcwd().DIRECTORY_SEPARATOR, set_realpath(getcwd()));
 	}
 
 	public function test_set_realpath_nonexistent_directory()
diff --git a/tests/codeigniter/helpers/string_helper_test.php b/tests/codeigniter/helpers/string_helper_test.php
index 29c3d65..75701ec 100644
--- a/tests/codeigniter/helpers/string_helper_test.php
+++ b/tests/codeigniter/helpers/string_helper_test.php
@@ -10,18 +10,18 @@
 	public function test_strip_slashes()
 	{
 		$expected = array(
-			"Is your name O'reilly?", 
+			"Is your name O'reilly?",
 			"No, my name is O'connor."
 		);
-		
+
 		$str = array(
 			"Is your name O\'reilly?",
 			"No, my name is O\'connor."
 		);
-		
+
 		$this->assertEquals($expected, strip_slashes($str));
 	}
-	
+
 	public function test_trim_slashes()
 	{
 		$strs = array(
@@ -144,4 +144,5 @@
 		$this->assertEquals('file-1', increment_string('file', '-', '1'));
 		$this->assertEquals(124, increment_string('123', ''));
 	}
+
 }
\ No newline at end of file
diff --git a/tests/codeigniter/helpers/text_helper_test.php b/tests/codeigniter/helpers/text_helper_test.php
index 584066b..f131469 100644
--- a/tests/codeigniter/helpers/text_helper_test.php
+++ b/tests/codeigniter/helpers/text_helper_test.php
@@ -3,16 +3,16 @@
 class Text_helper_test extends CI_TestCase {
 
 	private $_long_string;
-	
+
 	public function set_up()
 	{
 		$this->helper('text');
-		
+
 		$this->_long_string = 'Once upon a time, a framework had no tests.  It sad.  So some nice people began to write tests.  The more time that went on, the happier it became.  Everyone was happy.';
 	}
-	
+
 	// ------------------------------------------------------------------------
-	
+
 	public function test_word_limiter()
 	{
 		$this->assertEquals('Once upon a time,&#8230;', word_limiter($this->_long_string, 4));
@@ -20,8 +20,8 @@
 		$this->assertEquals('', word_limiter('', 4));
 	}
 
-	// ------------------------------------------------------------------------	
-	
+	// ------------------------------------------------------------------------
+
 	public function test_character_limiter()
 	{
 		$this->assertEquals('Once upon a time, a&#8230;', character_limiter($this->_long_string, 20));
@@ -30,22 +30,22 @@
 		$this->assertEquals('Short', character_limiter('Short', 5));
 	}
 
-	// ------------------------------------------------------------------------	
-	
+	// ------------------------------------------------------------------------
+
 	public function test_ascii_to_entities()
 	{
 		$strs = array(
 			'“‘ “test”'			=> '&#8220;&#8216; &#8220;test&#8221;',
 			'†¥¨ˆøåß∂ƒ©Ë™âˆ†Ëš¬'	=> '&#8224;&#165;&#168;&#710;&#248;&#229;&#223;&#8706;&#402;&#169;&#729;&#8710;&#730;&#172;'
 		);
-		
+
 		foreach ($strs as $str => $expect)
 		{
 			$this->assertEquals($expect, ascii_to_entities($str));
 		}
 	}
 
-	// ------------------------------------------------------------------------	
+	// ------------------------------------------------------------------------
 
 	public function test_entities_to_ascii()
 	{
@@ -53,27 +53,27 @@
 			'&#8220;&#8216; &#8220;test&#8221;' => '“‘ “test”',
 			'&#8224;&#165;&#168;&#710;&#248;&#229;&#223;&#8706;&#402;&#169;&#729;&#8710;&#730;&#172;' => '†¥¨ˆøåß∂ƒ©Ë™âˆ†Ëš¬'
 		);
-		
+
 		foreach ($strs as $str => $expect)
 		{
 			$this->assertEquals($expect, entities_to_ascii($str));
-		}		
+		}
 	}
-	
-	// ------------------------------------------------------------------------	
-	
-	function test_convert_accented_characters() 
+
+	// ------------------------------------------------------------------------
+
+	public function test_convert_accented_characters()
 	{
 		$this->assertEquals('AAAeEEEIIOOEUUUeY', convert_accented_characters('ÀÂÄÈÊËÎÏÔŒÙÛÜŸ'));
 		$this->assertEquals('a e i o u n ue', convert_accented_characters('á é í ó ú ñ ü'));
 	}
 
-	// ------------------------------------------------------------------------	
-	
+	// ------------------------------------------------------------------------
+
 	public function test_censored_words()
 	{
 		$censored = array('boob', 'nerd', 'ass', 'fart');
-		
+
 		$strs = array(
 			'Ted bobbled the ball' 			=> 'Ted bobbled the ball',
 			'Jake is a nerdo'				=> 'Jake is a nerdo',
@@ -81,28 +81,26 @@
 			'Did Mary Fart?'				=> 'Did Mary $*#?',
 			'Jake is really a boob'			=> 'Jake is really a $*#'
 		);
-		
-		
+
 		foreach ($strs as $str => $expect)
 		{
 			$this->assertEquals($expect, word_censor($str, $censored, '$*#'));
 		}
-		
+
 		// test censored words being sent as a string
 		$this->assertEquals('test', word_censor('test', 'test'));
 	}
 
-	// ------------------------------------------------------------------------	
+	// ------------------------------------------------------------------------
 
 	public function test_highlight_code()
 	{
-		$code = '<?php var_dump($this); ?>';
 		$expect = "<code><span style=\"color: #000000\">\n<span style=\"color: #0000BB\">&lt;?php&nbsp;var_dump</span><span style=\"color: #007700\">(</span><span style=\"color: #0000BB\">\$this</span><span style=\"color: #007700\">);&nbsp;</span><span style=\"color: #0000BB\">?&gt;&nbsp;</span>\n</span>\n</code>";
 
-		$this->assertEquals($expect, highlight_code($code));
+		$this->assertEquals($expect, highlight_code('<?php var_dump($this); ?>'));
 	}
 
-	// ------------------------------------------------------------------------	
+	// ------------------------------------------------------------------------
 
 	public function test_highlight_phrase()
 	{
@@ -113,16 +111,16 @@
 			'Or tell me what this is'	=> 'Or tell me what <strong>this is</strong>',
 			''							=> ''
 		);
-		
+
 		foreach ($strs as $str => $expect)
 		{
 			$this->assertEquals($expect, highlight_phrase($str, 'this is'));
 		}
 	}
 
-	// ------------------------------------------------------------------------	
+	// ------------------------------------------------------------------------
 
-	public function test_ellipsizing()
+	public function test_ellipsize()
 	{
 		$strs = array(
 			'0'		=> array(
@@ -144,16 +142,30 @@
 				'short'							=> 'short'
 			),
 		);
-		
+
 		foreach ($strs as $pos => $s)
 		{
 			foreach ($s as $str => $expect)
 			{
-				$this->assertEquals($expect, ellipsize($str, 10, $pos));				
+				$this->assertEquals($expect, ellipsize($str, 10, $pos));
 			}
 		}
 	}
 
-	// ------------------------------------------------------------------------	
+	// ------------------------------------------------------------------------
+
+	public function test_word_wrap()
+	{
+		$string = 'Here is a simple string of text that will help us demonstrate this function.';
+		$this->assertEquals(substr_count(word_wrap($string, 25), "\n"), 4);
+	}
+
+	// ------------------------------------------------------------------------
+
+	public function test_default_word_wrap_charlim()
+	{
+		$string = "Here is a longer string of text that will help us demonstrate the default charlim of this function.";
+		$this->assertEquals(strpos(word_wrap($string), "\n"), 73);
+	}
 
 }
\ No newline at end of file
diff --git a/tests/codeigniter/helpers/url_helper_test.php b/tests/codeigniter/helpers/url_helper_test.php
index c561809..c81c5f1 100644
--- a/tests/codeigniter/helpers/url_helper_test.php
+++ b/tests/codeigniter/helpers/url_helper_test.php
@@ -72,4 +72,5 @@
 			$this->assertEquals($out, auto_link($in, 'url'));
 		}
 	}
+
 }
\ No newline at end of file
diff --git a/tests/codeigniter/helpers/xml_helper_test.php b/tests/codeigniter/helpers/xml_helper_test.php
index a83fef9..e8cf411 100644
--- a/tests/codeigniter/helpers/xml_helper_test.php
+++ b/tests/codeigniter/helpers/xml_helper_test.php
@@ -6,10 +6,10 @@
 	{
 		$this->helper('xml');
 	}
-	
+
 	public function test_xml_convert()
 	{
 		$this->assertEquals('&lt;tag&gt;my &amp; test &#45; &lt;/tag&gt;', xml_convert('<tag>my & test - </tag>'));
 	}
-	
+
 }
\ No newline at end of file
diff --git a/tests/codeigniter/libraries/Encrypt_test.php b/tests/codeigniter/libraries/Encrypt_test.php
new file mode 100644
index 0000000..153a25e
--- /dev/null
+++ b/tests/codeigniter/libraries/Encrypt_test.php
@@ -0,0 +1,72 @@
+<?php
+
+class Encrypt_test extends CI_TestCase {
+
+	public function set_up()
+	{
+		$obj = new stdClass;
+		$obj->encrypt = new Mock_Libraries_Encrypt();
+
+		$this->ci_instance($obj);
+		$this->encrypt = $obj->encrypt;
+
+		$this->ci_set_config('encryption_key', "Encryptin'glike@boss!");
+		$this->msg = 'My secret message';
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_encode()
+	{
+		$this->assertNotEquals($this->msg, $this->encrypt->encode($this->msg));
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_decode()
+	{
+		$encoded_msg = $this->encrypt->encode($this->msg);
+		$this->assertEquals($this->msg, $this->encrypt->decode($encoded_msg));
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_optional_key()
+	{
+		$key = 'Ohai!ù0129°03182%HD1892P0';
+		$encoded_msg = $this->encrypt->encode($this->msg, $key);
+		$this->assertEquals($this->msg, $this->encrypt->decode($encoded_msg, $key));
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_default_cipher()
+	{
+		$this->assertEquals('rijndael-256', $this->encrypt->get_cipher());
+	}
+
+	// --------------------------------------------------------------------
+
+
+	public function test_set_cipher()
+	{
+		$this->encrypt->set_cipher(MCRYPT_BLOWFISH);
+		$this->assertEquals('blowfish', $this->encrypt->get_cipher());
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_default_mode()
+	{
+		$this->assertEquals('cbc', $this->encrypt->get_mode());
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_set_mode()
+	{
+		$this->encrypt->set_mode(MCRYPT_MODE_CFB);
+		$this->assertEquals('cfb', $this->encrypt->get_mode());
+	}
+
+}
\ No newline at end of file
diff --git a/tests/codeigniter/libraries/Parser_test.php b/tests/codeigniter/libraries/Parser_test.php
index c3d88fa..b68f44a 100644
--- a/tests/codeigniter/libraries/Parser_test.php
+++ b/tests/codeigniter/libraries/Parser_test.php
@@ -1,73 +1,74 @@
 <?php
 
 class Parser_test extends CI_TestCase {
-	
+
 	public function set_up()
 	{
-		$obj = new StdClass;
+		$obj = new stdClass;
 		$obj->parser = new Mock_Libraries_Parser();
-		
+
 		$this->ci_instance($obj);
-		
+
 		$this->parser = $obj->parser;
 	}
+
 	// --------------------------------------------------------------------
-	
+
 	public function test_set_delimiters()
 	{
 		// Make sure default delimiters are there
 		$this->assertEquals('{', $this->parser->l_delim);
 		$this->assertEquals('}', $this->parser->r_delim);
-		
+
 		// Change them to square brackets
 		$this->parser->set_delimiters('[', ']');
-		
+
 		// Make sure they changed
 		$this->assertEquals('[', $this->parser->l_delim);
 		$this->assertEquals(']', $this->parser->r_delim);
-		
+
 		// Reset them
 		$this->parser->set_delimiters();
-		
+
 		// Make sure default delimiters are there
 		$this->assertEquals('{', $this->parser->l_delim);
 		$this->assertEquals('}', $this->parser->r_delim);
 	}
-	
+
 	// --------------------------------------------------------------------
-	
+
 	public function test_parse_simple_string()
 	{
 		$data = array(
 			'title' => 'Page Title',
 			'body' => 'Lorem ipsum dolor sit amet.'
 		);
-		
+
 		$template = "{title}\n{body}";
-		
+
 		$result = implode("\n", $data);
-		
+
 		$this->assertEquals($result, $this->parser->parse_string($template, $data, TRUE));
 	}
-	
+
 	// --------------------------------------------------------------------
-	
+
 	public function test_parse()
 	{
 		$this->_parse_no_template();
 		$this->_parse_var_pair();
 		$this->_mismatched_var_pair();
 	}
-	
+
 	// --------------------------------------------------------------------
-	
+
 	private function _parse_no_template()
 	{
 		$this->assertFalse($this->parser->parse_string('', '', TRUE));
 	}
-	
+
 	// --------------------------------------------------------------------
-	
+
 	private function _parse_var_pair()
 	{
 		$data = array(
@@ -78,16 +79,14 @@
 						'flying'		=> 'no'),
 			)
 		);
-		
+
 		$template = "{title}\n{powers}{invisibility}\n{flying}{/powers}";
-		
-		$result = "Super Heroes\nyes\nno";
-		
-		$this->assertEquals($result, $this->parser->parse_string($template, $data, TRUE));	
+
+		$this->assertEquals("Super Heroes\nyes\nno", $this->parser->parse_string($template, $data, TRUE));
 	}
-	
+
 	// --------------------------------------------------------------------
-	
+
 	private function _mismatched_var_pair()
 	{
 		$data = array(
@@ -98,13 +97,11 @@
 						'flying'		=> 'no'),
 			)
 		);
-		
+
 		$template = "{title}\n{powers}{invisibility}\n{flying}";
-		
 		$result = "Super Heroes\n{powers}{invisibility}\n{flying}";
-		
-		$this->assertEquals($result, $this->parser->parse_string($template, $data, TRUE));			
+
+		$this->assertEquals($result, $this->parser->parse_string($template, $data, TRUE));
 	}
 
-	// --------------------------------------------------------------------
 }
\ No newline at end of file
diff --git a/tests/codeigniter/libraries/Table_test.php b/tests/codeigniter/libraries/Table_test.php
index f5133de..edfc83d 100644
--- a/tests/codeigniter/libraries/Table_test.php
+++ b/tests/codeigniter/libraries/Table_test.php
@@ -4,43 +4,39 @@
 
 	public function set_up()
 	{
-		$obj = new StdClass;
+		$obj = new stdClass;
 		$obj->table = new Mock_Libraries_Table();
-		
+
 		$this->ci_instance($obj);
-		
+
 		$this->table = $obj->table;
 	}
 
-	
 	// Setter Methods
 	// --------------------------------------------------------------------
-	
+
 	public function test_set_template()
 	{
 		$this->assertFalse($this->table->set_template('not an array'));
-		
-		$template = array(
-			'a' => 'b'
-		);
-		
+
+		$template = array('a' => 'b');
+
 		$this->table->set_template($template);
 		$this->assertEquals($template, $this->table->template);
 	}
-	
+
 	public function test_set_empty()
 	{
 		$this->table->set_empty('nada');
 		$this->assertEquals('nada', $this->table->empty_cells);
 	}
-	
+
 	public function test_set_caption()
 	{
 		$this->table->set_caption('awesome cap');
 		$this->assertEquals('awesome cap', $this->table->caption);
 	}
-	
-	
+
 	/*
 	 * @depends testPrepArgs
 	 */
@@ -49,9 +45,9 @@
 		// uses _prep_args internally, so we'll just do a quick
 		// check to verify that func_get_args and prep_args are
 		// being called.
-		
+
 		$this->table->set_heading('name', 'color', 'size');
-		
+
 		$this->assertEquals(
 			array(
 				array('data' => 'name'),
@@ -61,8 +57,7 @@
 			$this->table->heading
 		);
 	}
-	
-	
+
 	/*
 	 * @depends testPrepArgs
 	 */
@@ -71,13 +66,13 @@
 		// uses _prep_args internally, so we'll just do a quick
 		// check to verify that func_get_args and prep_args are
 		// being called.
-		
+
 		$this->table->add_row('my', 'pony', 'sings');
 		$this->table->add_row('your', 'pony', 'stinks');
 		$this->table->add_row('my pony', '>', 'your pony');
-		
+
 		$this->assertEquals(count($this->table->rows), 3);
-		
+
 		$this->assertEquals(
 			array(
 				array('data' => 'your'),
@@ -87,11 +82,10 @@
 			$this->table->rows[1]
 		);
 	}
-	
-	
+
 	// Uility Methods
 	// --------------------------------------------------------------------
-	
+
 	public function test_prep_args()
 	{
 		$expected = array(
@@ -99,7 +93,7 @@
 			array('data' => 'color'),
 			array('data' => 'size')
 		);
-		
+
 		$this->assertEquals(
 			$expected,
 			$this->table->prep_args(array('name', 'color', 'size'))
@@ -114,7 +108,7 @@
 			$this->table->prep_args(array('name', 'color', 'size', array('data' => 'weight', 'class' => 'awesome')))
 		);
 	}
-	
+
 	public function test_default_template_keys()
 	{
 		$keys = array(
@@ -126,132 +120,124 @@
 			'row_alt_start', 'row_alt_end', 'cell_alt_start', 'cell_alt_end',
 			'table_close'
 		);
-		
+
 		foreach ($keys as $key)
 		{
 			$this->assertArrayHasKey($key, $this->table->default_template());
 		}
 	}
-	
+
 	public function test_compile_template()
 	{
 		$this->assertFalse($this->table->set_template('invalid_junk'));
-		
+
 		// non default key
 		$this->table->set_template(array('nonsense' => 'foo'));
 		$this->table->compile_template();
-		
+
 		$this->assertArrayHasKey('nonsense', $this->table->template);
 		$this->assertEquals('foo', $this->table->template['nonsense']);
-		
+
 		// override default
 		$this->table->set_template(array('table_close' => '</table junk>'));
 		$this->table->compile_template();
-		
+
 		$this->assertArrayHasKey('table_close', $this->table->template);
 		$this->assertEquals('</table junk>', $this->table->template['table_close']);
 	}
-	
+
 	public function test_make_columns()
 	{
 		// Test bogus parameters
 		$this->assertFalse($this->table->make_columns('invalid_junk'));
 		$this->assertFalse($this->table->make_columns(array()));
 		$this->assertFalse($this->table->make_columns(array('one', 'two'), '2.5'));
-		
-		
+
 		// Now on to the actual column creation
-		
+
 		$five_values = array(
 			'Laura', 'Red', '15',
 			'Katie', 'Blue'
 		);
-		
+
 		// No column count - no changes to the array
 		$this->assertEquals(
 			$five_values,
 			$this->table->make_columns($five_values)
 		);
-		
+
 		// Column count of 3 leaves us with one &nbsp;
 		$this->assertEquals(
 			array(
 				array('Laura', 'Red', '15'),
-				array('Katie', 'Blue', '&nbsp;')				
+				array('Katie', 'Blue', '&nbsp;')
 			),
 			$this->table->make_columns($five_values, 3)
 		);
 	}
-	
+
 	public function test_clear()
 	{
 		$this->table->set_heading('Name', 'Color', 'Size');
-		
+
 		// Make columns changes auto_heading
 		$rows = $this->table->make_columns(array(
 			'Laura', 'Red', '15',
 			'Katie', 'Blue'
 		), 3);
-		
+
 		foreach ($rows as $row)
 		{
 			$this->table->add_row($row);
 		}
-		
+
 		$this->assertFalse($this->table->auto_heading);
 		$this->assertEquals(count($this->table->heading), 3);
 		$this->assertEquals(count($this->table->rows), 2);
-		
+
 		$this->table->clear();
-		
+
 		$this->assertTrue($this->table->auto_heading);
 		$this->assertEmpty($this->table->heading);
 		$this->assertEmpty($this->table->rows);
 	}
-	
-	
+
 	public function test_set_from_array()
 	{
 		$this->assertFalse($this->table->set_from_array('bogus'));
 		$this->assertFalse($this->table->set_from_array(NULL));
-		
+
 		$data = array(
 			array('name', 'color', 'number'),
 			array('Laura', 'Red', '22'),
-			array('Katie', 'Blue')				
+			array('Katie', 'Blue')
 		);
-		
+
 		$this->table->set_from_array($data, FALSE);
 		$this->assertEmpty($this->table->heading);
-		
+
 		$this->table->clear();
-		
-		$expected_heading = array(
+
+		$this->table->set_from_array($data);
+		$this->assertEquals(count($this->table->rows), 2);
+
+		$expected = array(
 			array('data' => 'name'),
 			array('data' => 'color'),
 			array('data' => 'number')
 		);
-		
-		$expected_second = array(
+
+		$this->assertEquals($expected, $this->table->heading);
+
+		$expected = array(
 			array('data' => 'Katie'),
 			array('data' => 'Blue'),
 		);
-		
-		$this->table->set_from_array($data);
-		$this->assertEquals(count($this->table->rows), 2);
-		
-		$this->assertEquals(
-			$expected_heading,
-			$this->table->heading
-		);
-		
-		$this->assertEquals(
-			$expected_second,
-			$this->table->rows[1]
-		);
+
+		$this->assertEquals($expected, $this->table->rows[1]);
 	}
-	
-	function test_set_from_object()
+
+	public function test_set_from_object()
 	{
 		// Make a stub of query instance
 		$query = new CI_TestCase();
@@ -268,37 +254,31 @@
 			return 2;
 		};
 
-		$expected_heading = array(
+		$this->table->set_from_object($query);
+
+		$expected = array(
 			array('data' => 'name'),
 			array('data' => 'email')
 		);
 
-		$expected_second = array(
+		$this->assertEquals($expected, $this->table->heading);
+
+		$expected = array(
 			'name' => array('data' => 'Foo Bar'),
 			'email' => array('data' => 'foo@bar.com'),
 		);
 
-		$this->table->set_from_object($query);
-
-		$this->assertEquals(
-			$expected_heading,
-			$this->table->heading
-		);
-		
-		$this->assertEquals(
-			$expected_second,
-			$this->table->rows[1]
-		);
+		$this->assertEquals($expected, $this->table->rows[1]);
 	}
-	
-	function test_generate()
+
+	public function test_generate()
 	{
 		// Prepare the data
 		$data = array(
 			array('Name', 'Color', 'Size'),
 			array('Fred', 'Blue', 'Small'),
 			array('Mary', 'Red', 'Large'),
-			array('John', 'Green', 'Medium')	
+			array('John', 'Green', 'Medium')
 		);
 
 		$table = $this->table->generate($data);
@@ -313,4 +293,5 @@
 		$this->assertTrue(strpos($table, '<td>Blue</td>') !== FALSE);
 		$this->assertTrue(strpos($table, '<td>Small</td>') !== FALSE);
 	}
+
 }
\ No newline at end of file
diff --git a/tests/codeigniter/libraries/Typography_test.php b/tests/codeigniter/libraries/Typography_test.php
index 250aefb..eb6dacb 100644
--- a/tests/codeigniter/libraries/Typography_test.php
+++ b/tests/codeigniter/libraries/Typography_test.php
@@ -4,11 +4,11 @@
 
 	public function set_up()
 	{
-		$obj = new StdClass;
+		$obj = new stdClass;
 		$obj->type = new Mock_Libraries_Typography();
-		
+
 		$this->ci_instance($obj);
-		
+
 		$this->type = $obj->type;
 	}
 
@@ -33,18 +33,18 @@
 			'foo..'							=> 'foo..',
 			'foo...bar.'					=> 'foo&#8230;bar.',
 			'test.  new'					=> 'test.&nbsp; new',
-		);	
-		
+		);
+
 		foreach ($strs as $str => $expected)
 		{
-			$this->assertEquals($expected, $this->type->format_characters($str));		
+			$this->assertEquals($expected, $this->type->format_characters($str));
 		}
 	}
 
 	// --------------------------------------------------------------------
 
 	public function test_nl2br_except_pre()
-	{	
+	{
 		$str = <<<EOH
 Hello, I'm a happy string with some new lines.  
 
@@ -85,12 +85,11 @@
 The End.
 EOH;
 
-		$this->assertEquals($expected, 
-							$this->type->nl2br_except_pre($str));
+		$this->assertEquals($expected, $this->type->nl2br_except_pre($str));
 	}
 
 	// --------------------------------------------------------------------
-	
+
 	public function test_auto_typography()
 	{
 		$this->_blank_string();
@@ -103,7 +102,7 @@
 	}
 
 	// --------------------------------------------------------------------
-	
+
 	private function _blank_string()
 	{
 		// Test blank string
@@ -131,7 +130,7 @@
 	{
 		$str = "This has way too many linebreaks.\n\n\n\nSee?";
 		$expect = "<p>This has way too many linebreaks.</p>\n\n<p>See?</p>";
-		
+
 		$this->assertEquals($expect, $this->type->auto_typography($str, TRUE));
 	}
 
@@ -141,7 +140,7 @@
 	{
 		$str = '<!-- I can haz comments? -->  But no!';
 		$expect = '<p><!-- I can haz comments? -->&nbsp; But no!</p>';
-		
+
 		$this->assertEquals($expect, $this->type->auto_typography($str));
 	}
 
@@ -151,7 +150,7 @@
 	{
 		$str = '<p>My Sentence</p><pre>var_dump($this);</pre>';
 		$expect = '<p>My Sentence</p><pre>var_dump($this);</pre>';
-		
+
 		$this->assertEquals($expect, $this->type->auto_typography($str));
 	}
 
@@ -161,7 +160,7 @@
 	{
 		$str = 'My Sentence<pre>var_dump($this);</pre>';
 		$expect = '<p>My Sentence</p><pre>var_dump($this);</pre>';
-		
+
 		$this->assertEquals($expect, $this->type->auto_typography($str));
 	}
 
@@ -170,19 +169,18 @@
 	public function _protect_braced_quotes()
 	{
 		$this->type->protect_braced_quotes = TRUE;
-		
+
 		$str = 'Test {parse="foobar"}';
 		$expect = '<p>Test {parse="foobar"}</p>';
-		
+
 		$this->assertEquals($expect, $this->type->auto_typography($str));
 
 		$this->type->protect_braced_quotes = FALSE;
-		
+
 		$str = 'Test {parse="foobar"}';
 		$expect = '<p>Test {parse=&#8220;foobar&#8221;}</p>';
-		
+
 		$this->assertEquals($expect, $this->type->auto_typography($str));
-
-
 	}
+
 }
\ No newline at end of file
diff --git a/tests/codeigniter/libraries/Useragent_test.php b/tests/codeigniter/libraries/Useragent_test.php
index 7dad7ac..89383f8 100644
--- a/tests/codeigniter/libraries/Useragent_test.php
+++ b/tests/codeigniter/libraries/Useragent_test.php
@@ -1,7 +1,7 @@
 <?php
 
 class UserAgent_test extends CI_TestCase {
-	
+
 	protected $_user_agent = 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; en-us) AppleWebKit/533.20.25 (KHTML, like Gecko) Version/5.0.4 Safari/533.20.27';
 	protected $_mobile_ua = 'Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_1 like Mac OS X; en-us) AppleWebKit/532.9 (KHTML, like Gecko) Version/4.0.5 Mobile/8B117 Safari/6531.22.7';
 
@@ -10,7 +10,7 @@
 		// set a baseline user agent
 		$_SERVER['HTTP_USER_AGENT'] = $this->_user_agent;
 
-		$obj = new StdClass;
+		$obj = new stdClass;
 		$obj->agent = new Mock_Libraries_UserAgent();
 
 		$this->ci_instance($obj);
@@ -82,6 +82,4 @@
 		$this->assertFalse($this->agent->accept_charset());
 	}
 
-	// --------------------------------------------------------------------
-
 }
\ No newline at end of file
diff --git a/tests/mocks/autoloader.php b/tests/mocks/autoloader.php
index 90aabcb..e3ff7a8 100644
--- a/tests/mocks/autoloader.php
+++ b/tests/mocks/autoloader.php
@@ -69,7 +69,7 @@
 		}
 	}
 
-	$file = (isset($file)) ? $file : $dir.$class.'.php';
+	$file = isset($file) ? $file : $dir.$class.'.php';
 
 	if ( ! file_exists($file))
 	{
@@ -82,7 +82,7 @@
 			return FALSE;
 		}
 
-	    throw new InvalidArgumentException("Unable to load $class.");
+		throw new InvalidArgumentException("Unable to load {$class}.");
 	}
 
 	include_once($file);
diff --git a/tests/mocks/ci_testcase.php b/tests/mocks/ci_testcase.php
index f327e6b..eda9e1b 100644
--- a/tests/mocks/ci_testcase.php
+++ b/tests/mocks/ci_testcase.php
@@ -1,11 +1,11 @@
 <?php
 
 class CI_TestCase extends PHPUnit_Framework_TestCase {
-	
+
 	protected $ci_config;
 	protected $ci_instance;
 	protected static $ci_test_instance;
-		
+
 	private $global_map = array(
 		'benchmark'	=> 'bm',
 		'config'	=> 'cfg',
@@ -19,18 +19,17 @@
 		'loader'	=> 'load',
 		'model'		=> 'model'
 	);
-	
+
 	// --------------------------------------------------------------------
-	
+
 	public function __construct()
 	{
 		parent::__construct();
-		
 		$this->ci_config = array();
 	}
-	
+
 	// --------------------------------------------------------------------
-	
+
 	public function setUp()
 	{
 		if (method_exists($this, 'set_up'))
@@ -38,10 +37,10 @@
 			$this->set_up();
 		}
 	}
-	
+
 	// --------------------------------------------------------------------
-	
-	public function tearDown() 
+
+	public function tearDown()
 	{
 		if (method_exists($this, 'tear_down'))
 		{
@@ -50,15 +49,15 @@
 	}
 
 	// --------------------------------------------------------------------
-	
+
 	public static function instance()
 	{
 		return self::$ci_test_instance;
 	}
-	
+
 	// --------------------------------------------------------------------
-	
-	function ci_set_config($key, $val = '')
+
+	public function ci_set_config($key, $val = '')
 	{
 		if (is_array($key))
 		{
@@ -71,36 +70,36 @@
 	}
 
 	// --------------------------------------------------------------------
-	
-	function ci_get_config()
+
+	public function ci_get_config()
 	{
 		return $this->ci_config;
 	}
-	
+
 	// --------------------------------------------------------------------
-	
-	function ci_instance($obj = FALSE)
+
+	public function ci_instance($obj = FALSE)
 	{
 		if ( ! is_object($obj))
 		{
 			return $this->ci_instance;
 		}
-		
+
 		$this->ci_instance = $obj;
 	}
-	
+
 	// --------------------------------------------------------------------
-	
-	function ci_instance_var($name, $obj = FALSE)
+
+	public function ci_instance_var($name, $obj = FALSE)
 	{
 		if ( ! is_object($obj))
 		{
 			return $this->ci_instance->$name;
 		}
-		
+
 		$this->ci_instance->$name =& $obj;
 	}
-	
+
 	// --------------------------------------------------------------------
 
 	/**
@@ -112,10 +111,10 @@
 	 * test can modify the variable it assigns to and
 	 * still maintain the global.
 	 */
-	function &ci_core_class($name)
+	public function &ci_core_class($name)
 	{
 		$name = strtolower($name);
-		
+
 		if (isset($this->global_map[$name]))
 		{
 			$class_name = ucfirst($name);
@@ -130,29 +129,29 @@
 		{
 			throw new Exception('Not a valid core class.');
 		}
-		
+
 		if ( ! class_exists('CI_'.$class_name))
 		{
 			require_once BASEPATH.'core/'.$class_name.'.php';
 		}
-		
+
 		$GLOBALS[strtoupper($global_name)] = 'CI_'.$class_name;
 		return $GLOBALS[strtoupper($global_name)];
 	}
-	
+
 	// --------------------------------------------------------------------
-	
+
 	// convenience function for global mocks
-	function ci_set_core_class($name, $obj)
+	public function ci_set_core_class($name, $obj)
 	{
 		$orig =& $this->ci_core_class($name);
 		$orig = $obj;
 	}
-	
+
 	// --------------------------------------------------------------------
 	// Internals
 	// --------------------------------------------------------------------
-	
+
 	/**
 	 * Overwrite runBare
 	 *
@@ -169,28 +168,27 @@
 	}
 
 	// --------------------------------------------------------------------
-	
-	function helper($name)
+
+	public function helper($name)
 	{
 		require_once(BASEPATH.'helpers/'.$name.'_helper.php');
 	}
 
 	// --------------------------------------------------------------------
-	
+
 	/**
 	 * This overload is useful to create a stub, that need to have a specific method.
 	 */
-	function __call($method, $args)
+	public function __call($method, $args)
 	{
-		if ($this->{$method} instanceof Closure) 
+		if ($this->{$method} instanceof Closure)
 		{
 			return call_user_func_array($this->{$method},$args);
-		} 
-		else 
+		}
+		else
 		{
 			return parent::__call($method, $args);
 		}
 	}
-}
 
-// EOF
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/tests/mocks/core/common.php b/tests/mocks/core/common.php
index e1c493a..a655ee1 100644
--- a/tests/mocks/core/common.php
+++ b/tests/mocks/core/common.php
@@ -4,11 +4,11 @@
 
 if ( ! function_exists('get_instance'))
 {
-	function &get_instance() 
+	function &get_instance()
 	{
 		$test = CI_TestCase::instance();
-		$instance = $test->ci_instance();
-		return $instance;
+		$test = $test->ci_instance();
+		return $test;
 	}
 }
 
@@ -16,10 +16,10 @@
 
 if ( ! function_exists('get_config'))
 {
-	function &get_config() {
+	function &get_config()
+	{
 		$test = CI_TestCase::instance();
 		$config = $test->ci_get_config();
-			
 		return $config;
 	}
 }
@@ -29,12 +29,12 @@
 	function config_item($item)
 	{
 		$config =& get_config();
-		
+
 		if ( ! isset($config[$item]))
 		{
 			return FALSE;
 		}
-		
+
 		return $config[$item];
 	}
 }
@@ -49,16 +49,16 @@
 		{
 			throw new Exception('Not Implemented: Non-core load_class()');
 		}
-		
+
 		$test = CI_TestCase::instance();
-		
+
 		$obj =& $test->ci_core_class($class);
-		
+
 		if (is_string($obj))
 		{
-			throw new Exception('Bad Isolation: Use ci_set_core_class to set '.$class.'');
+			throw new Exception('Bad Isolation: Use ci_set_core_class to set '.$class);
 		}
-		
+
 		return $obj;
 	}
 }
@@ -74,16 +74,16 @@
 	function remove_invisible_characters($str, $url_encoded = TRUE)
 	{
 		$non_displayables = array();
-		
+
 		// every control character except newline (dec 10)
 		// carriage return (dec 13), and horizontal tab (dec 09)
-		
+
 		if ($url_encoded)
 		{
 			$non_displayables[] = '/%0[0-8bcef]/';	// url encoded 00-08, 11, 12, 14, 15
 			$non_displayables[] = '/%1[0-9a-f]/';	// url encoded 16-31
 		}
-		
+
 		$non_displayables[] = '/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]+/S';	// 00-08, 11, 12, 14-31, 127
 
 		do
@@ -166,6 +166,4 @@
 	{
 		return TRUE;
 	}
-}
-
-// EOF
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/tests/mocks/core/input.php b/tests/mocks/core/input.php
index 8a337d2..2a4aa49 100644
--- a/tests/mocks/core/input.php
+++ b/tests/mocks/core/input.php
@@ -1,10 +1,10 @@
 <?php
 
 class Mock_Core_Input extends CI_Input {
-	
+
 	/**
-	 * Since we use GLOBAL to fetch Security and Utf8 classes, 
-	 * we need to use inversion of control to mock up 
+	 * Since we use GLOBAL to fetch Security and Utf8 classes,
+	 * we need to use inversion of control to mock up
 	 * the same process within CI_Input class constructor.
 	 *
 	 * @covers CI_Input::__construct()
diff --git a/tests/mocks/core/loader.php b/tests/mocks/core/loader.php
index d4b29bb..53d88d5 100644
--- a/tests/mocks/core/loader.php
+++ b/tests/mocks/core/loader.php
@@ -1,7 +1,7 @@
 <?php
 
 class Mock_Core_Loader extends CI_Loader {
-	
+
 	/**
 	 * Since we use paths to load up models, views, etc, we need the ability to
 	 * mock up the file system so when core tests are run, we aren't mucking
@@ -15,16 +15,17 @@
 	{
 		vfsStreamWrapper::register();
 		vfsStreamWrapper::setRoot(new vfsStreamDirectory('application'));
-		
+
 		$this->models_dir 	= vfsStream::newDirectory('models')->at(vfsStreamWrapper::getRoot());
 		$this->libs_dir 	= vfsStream::newDirectory('libraries')->at(vfsStreamWrapper::getRoot());
 		$this->helpers_dir 	= vfsStream::newDirectory('helpers')->at(vfsStreamWrapper::getRoot());
 		$this->views_dir 	= vfsStream::newDirectory('views')->at(vfsStreamWrapper::getRoot());
-		
+
 		$this->_ci_ob_level  		= ob_get_level();
 		$this->_ci_library_paths	= array(vfsStream::url('application').'/', BASEPATH);
 		$this->_ci_helper_paths 	= array(vfsStream::url('application').'/', BASEPATH);
 		$this->_ci_model_paths 		= array(vfsStream::url('application').'/');
 		$this->_ci_view_paths 		= array(vfsStream::url('application').'/views/' => TRUE);
 	}
+
 }
\ No newline at end of file
diff --git a/tests/mocks/core/security.php b/tests/mocks/core/security.php
index d7ea0e6..e19a8b2 100644
--- a/tests/mocks/core/security.php
+++ b/tests/mocks/core/security.php
@@ -1,7 +1,7 @@
 <?php
 
 class Mock_Core_Security extends CI_Security {
-	
+
 	public function csrf_set_cookie()
 	{
 		// We cannot set cookie in CLI mode, so for csrf test, who rely on $_COOKIE,
diff --git a/tests/mocks/core/uri.php b/tests/mocks/core/uri.php
index b694609..94f75df 100644
--- a/tests/mocks/core/uri.php
+++ b/tests/mocks/core/uri.php
@@ -1,12 +1,12 @@
 <?php
 
 class Mock_Core_URI extends CI_URI {
-	
+
 	public function __construct()
 	{
 		$test = CI_TestCase::instance();
 		$cls =& $test->ci_core_class('cfg');
-		
+
 		// set predictable config values
 		$test->ci_set_config(array(
 			'index_page'		=> 'index.php',
@@ -14,12 +14,13 @@
 			'subclass_prefix'	=> 'MY_'
 		));
 
-		$this->config = new $cls;	
+		$this->config = new $cls;
 
 	}
-	
+
 	protected function _is_cli_request()
 	{
 		return FALSE;
 	}
+
 }
\ No newline at end of file
diff --git a/tests/mocks/core/utf8.php b/tests/mocks/core/utf8.php
index b77d717..068e74a 100644
--- a/tests/mocks/core/utf8.php
+++ b/tests/mocks/core/utf8.php
@@ -1,27 +1,26 @@
 <?php
 
 class Mock_Core_Utf8 extends CI_Utf8 {
-	
+
 	/**
-	 * We need to define several constants as 
+	 * We need to define several constants as
 	 * the same process within CI_Utf8 class constructor.
 	 *
 	 * @covers CI_Utf8::__construct()
 	 */
 	public function __construct()
 	{
-		defined('UTF8_ENABLED') or define('UTF8_ENABLED', TRUE);
+		defined('UTF8_ENABLED') OR define('UTF8_ENABLED', TRUE);
 
 		if (extension_loaded('mbstring'))
 		{
-			defined('MB_ENABLED') or define('MB_ENABLED', TRUE);
+			defined('MB_ENABLED') OR define('MB_ENABLED', TRUE);
 			mb_internal_encoding('UTF-8');
 		}
 		else
 		{
-			defined('MB_ENABLED') or define('MB_ENABLED', FALSE);
+			defined('MB_ENABLED') OR define('MB_ENABLED', FALSE);
 		}
-		
 	}
 
 }
\ No newline at end of file
diff --git a/tests/mocks/database/config/mysql.php b/tests/mocks/database/config/mysql.php
index ace0a31..a590b9f 100644
--- a/tests/mocks/database/config/mysql.php
+++ b/tests/mocks/database/config/mysql.php
@@ -1,7 +1,7 @@
 <?php
 
 return array(
-	
+
 	// Typical Database configuration
 	'mysql' => array(
 		'dsn' => '',
@@ -9,7 +9,7 @@
 		'username' => 'travis',
 		'password' => '',
 		'database' => 'ci_test',
-		'dbdriver' => 'mysql',
+		'dbdriver' => 'mysql'
 	),
 
 	// Database configuration with failover
@@ -28,7 +28,7 @@
 				'password' => '',
 				'database' => 'ci_test',
 				'dbdriver' => 'mysql',
-			),
-		),
-	),
+			)
+		)
+	)
 );
\ No newline at end of file
diff --git a/tests/mocks/database/config/pdo/mysql.php b/tests/mocks/database/config/pdo/mysql.php
index cefb6b0..fefe0d6 100644
--- a/tests/mocks/database/config/pdo/mysql.php
+++ b/tests/mocks/database/config/pdo/mysql.php
@@ -1,7 +1,7 @@
 <?php
 
 return array(
-	
+
 	// Typical Database configuration
 	'pdo/mysql' => array(
 		'dsn' => '',
@@ -10,7 +10,7 @@
 		'password' => '',
 		'database' => 'ci_test',
 		'dbdriver' => 'pdo',
-		'pdodriver' => 'mysql',
+		'pdodriver' => 'mysql'
 	),
 
 	// Database configuration with failover
@@ -30,8 +30,8 @@
 				'password' => '',
 				'database' => 'ci_test',
 				'dbdriver' => 'pdo',
-				'pdodriver' => 'mysql',
-			),
-		),
-	),
+				'pdodriver' => 'mysql'
+			)
+		)
+	)
 );
\ No newline at end of file
diff --git a/tests/mocks/database/config/pdo/pgsql.php b/tests/mocks/database/config/pdo/pgsql.php
index 5196e9a..ddd638c 100644
--- a/tests/mocks/database/config/pdo/pgsql.php
+++ b/tests/mocks/database/config/pdo/pgsql.php
@@ -1,7 +1,7 @@
 <?php
 
 return array(
-	
+
 	// Typical Database configuration
 	'pdo/pgsql' => array(
 		'dsn' => 'pgsql:host=localhost;port=5432;dbname=ci_test;',
@@ -10,7 +10,7 @@
 		'password' => '',
 		'database' => 'ci_test',
 		'dbdriver' => 'pdo',
-		'pdodriver' => 'pgsql',
+		'pdodriver' => 'pgsql'
 	),
 
 	// Database configuration with failover
@@ -30,8 +30,8 @@
 				'password' => '',
 				'database' => 'ci_test',
 				'dbdriver' => 'pdo',
-				'pdodriver' => 'pgsql',
-			),
-		),
-	),
+				'pdodriver' => 'pgsql'
+			)
+		)
+	)
 );
\ No newline at end of file
diff --git a/tests/mocks/database/config/pdo/sqlite.php b/tests/mocks/database/config/pdo/sqlite.php
index c68b4b2..3646184 100644
--- a/tests/mocks/database/config/pdo/sqlite.php
+++ b/tests/mocks/database/config/pdo/sqlite.php
@@ -10,7 +10,7 @@
 		'password' => 'sqlite',
 		'database' => 'sqlite',
 		'dbdriver' => 'pdo',
-		'pdodriver' => 'sqlite',
+		'pdodriver' => 'sqlite'
 	),
 
 	// Database configuration with failover
@@ -29,9 +29,9 @@
 				'username' => 'sqlite',
 				'password' => 'sqlite',
 				'database' => 'sqlite',
-				'dbdriver' => 'pdo', 
-				'pdodriver' => 'sqlite',
-			),
-		),
-	),
+				'dbdriver' => 'pdo',
+				'pdodriver' => 'sqlite'
+			)
+		)
+	)
 );
\ No newline at end of file
diff --git a/tests/mocks/database/config/pgsql.php b/tests/mocks/database/config/pgsql.php
index c06af8c..1444b00 100644
--- a/tests/mocks/database/config/pgsql.php
+++ b/tests/mocks/database/config/pgsql.php
@@ -1,7 +1,7 @@
 <?php
 
 return array(
-	
+
 	// Typical Database configuration
 	'pgsql' => array(
 		'dsn' => '',
@@ -9,7 +9,7 @@
 		'username' => 'postgres',
 		'password' => '',
 		'database' => 'ci_test',
-		'dbdriver' => 'postgre',
+		'dbdriver' => 'postgre'
 	),
 
 	// Database configuration with failover
@@ -28,7 +28,7 @@
 				'password' => '',
 				'database' => 'ci_test',
 				'dbdriver' => 'postgre',
-			),
-		),
-	),
+			)
+		)
+	)
 );
\ No newline at end of file
diff --git a/tests/mocks/database/config/sqlite.php b/tests/mocks/database/config/sqlite.php
index 755ce2a..d37ee48 100644
--- a/tests/mocks/database/config/sqlite.php
+++ b/tests/mocks/database/config/sqlite.php
@@ -9,7 +9,7 @@
 		'username' => 'sqlite',
 		'password' => 'sqlite',
 		'database' => realpath(__DIR__.'/..').'/ci_test.sqlite',
-		'dbdriver' => 'sqlite3',
+		'dbdriver' => 'sqlite3'
 	),
 
 	// Database configuration with failover
@@ -27,8 +27,8 @@
 				'username' => 'sqlite',
 				'password' => 'sqlite',
 				'database' => realpath(__DIR__.'/..').'/ci_test.sqlite',
-				'dbdriver' => 'sqlite3',
-			),
-		),
-	),
+				'dbdriver' => 'sqlite3'
+			)
+		)
+	)
 );
\ No newline at end of file
diff --git a/tests/mocks/database/db.php b/tests/mocks/database/db.php
index 59028ed..30504bb 100644
--- a/tests/mocks/database/db.php
+++ b/tests/mocks/database/db.php
@@ -6,7 +6,7 @@
 	 * @var array DB configuration
 	 */
 	private $config = array();
-	
+
 	/**
 	 * Prepare database configuration skeleton
 	 *
@@ -21,7 +21,7 @@
 	/**
 	 * Build DSN connection string for DB driver instantiate process
 	 *
-	 * @param 	string 	Group name 		
+	 * @param 	string 	Group name
 	 * @return 	string 	DSN Connection string
 	 */
 	public function set_dsn($group = 'default')
@@ -65,28 +65,27 @@
 	 * Return a database config array
 	 *
 	 * @see 	./config
-	 * @param 	string 		Driver based configuration
-	 * @return 	array 		
+	 * @param	string	Driver based configuration
+	 * @return	array
 	 */
 	public static function config($driver)
 	{
 		$dir = realpath(dirname(__FILE__)).DIRECTORY_SEPARATOR;
-
 		return include($dir.'config'.DIRECTORY_SEPARATOR.$driver.'.php');
 	}
 
 	/**
 	 * Main DB method wrapper
 	 *
-	 * @param 	string 		Group or DSN string
-	 * @param 	bool 		
-	 * @return 	object 		
+	 * @param 	string	Group or DSN string
+	 * @param 	bool
+	 * @return 	object
 	 */
 	public static function DB($group, $query_builder = FALSE)
 	{
 		include_once(BASEPATH.'database/DB.php');
 
-		try 
+		try
 		{
 			$db = DB($group, $query_builder);
 		}
@@ -97,4 +96,5 @@
 
 		return $db;
 	}
+
 }
\ No newline at end of file
diff --git a/tests/mocks/database/db/driver.php b/tests/mocks/database/db/driver.php
index cb18202..65ac2c4 100644
--- a/tests/mocks/database/db/driver.php
+++ b/tests/mocks/database/db/driver.php
@@ -1,7 +1,7 @@
 <?php
 
 class Mock_Database_DB_Driver extends CI_DB_driver {
-	
+
 	/**
 	 * @var object The actual Driver
 	 */
@@ -16,7 +16,10 @@
 	 */
 	public function __construct($driver_class, $config = array())
 	{
-		if (is_string($driver_class)) $this->ci_db_driver = new $driver_class($config);
+		if (is_string($driver_class))
+		{
+			$this->ci_db_driver = new $driver_class($config);
+		}
 	}
 
 	/**
diff --git a/tests/mocks/database/db/querybuilder.php b/tests/mocks/database/db/querybuilder.php
index 1b95c92..3f22526 100644
--- a/tests/mocks/database/db/querybuilder.php
+++ b/tests/mocks/database/db/querybuilder.php
@@ -1,10 +1,3 @@
 <?php
 
-if ( ! class_exists('CI_DB_query_builder'))
-{
-	class Mock_Database_DB_QueryBuilder extends CI_DB_active_record {}
-}
-else
-{
-	class Mock_Database_DB_QueryBuilder extends CI_DB_query_builder {}
-}
+class Mock_Database_DB_QueryBuilder extends CI_DB_query_builder {}
\ No newline at end of file
diff --git a/tests/mocks/database/drivers/mysql.php b/tests/mocks/database/drivers/mysql.php
index 34a74e2..e0c1fb0 100644
--- a/tests/mocks/database/drivers/mysql.php
+++ b/tests/mocks/database/drivers/mysql.php
@@ -1,16 +1,17 @@
 <?php
 
 class Mock_Database_Drivers_Mysql extends Mock_Database_DB_Driver {
-	
+
 	/**
 	 * Instantiate the database driver
 	 *
-	 * @param  string 	DB Driver class name
-	 * @param  array 	DB configuration to set
-	 * @return void
+	 * @param	string	DB Driver class name
+	 * @param	array	DB configuration to set
+	 * @return	void
 	 */
 	public function __construct($config = array())
 	{
 		parent::__construct('CI_DB_mysql_driver', $config);
 	}
+
 }
\ No newline at end of file
diff --git a/tests/mocks/database/drivers/pdo.php b/tests/mocks/database/drivers/pdo.php
index 590e195..17768ee 100644
--- a/tests/mocks/database/drivers/pdo.php
+++ b/tests/mocks/database/drivers/pdo.php
@@ -1,13 +1,13 @@
 <?php
 
 class Mock_Database_Drivers_PDO extends Mock_Database_DB_Driver {
-	
+
 	/**
 	 * Instantiate the database driver
 	 *
-	 * @param  string 	DB Driver class name
-	 * @param  array 	DB configuration to set
-	 * @return void
+	 * @param	string	DB Driver class name
+	 * @param	array	DB configuration to set
+	 * @return	void
 	 */
 	public function __construct($config = array())
 	{
diff --git a/tests/mocks/database/drivers/postgre.php b/tests/mocks/database/drivers/postgre.php
index 0df9059..5a45115 100644
--- a/tests/mocks/database/drivers/postgre.php
+++ b/tests/mocks/database/drivers/postgre.php
@@ -1,16 +1,17 @@
 <?php
 
 class Mock_Database_Drivers_Postgre extends Mock_Database_DB_Driver {
-	
+
 	/**
 	 * Instantiate the database driver
 	 *
-	 * @param  string 	DB Driver class name
-	 * @param  array 	DB configuration to set
-	 * @return void
+	 * @param	string	DB Driver class name
+	 * @param	array	DB configuration to set
+	 * @return	void
 	 */
 	public function __construct($config = array())
 	{
 		parent::__construct('CI_DB_postgre_driver', $config);
 	}
+
 }
\ No newline at end of file
diff --git a/tests/mocks/database/drivers/sqlite.php b/tests/mocks/database/drivers/sqlite.php
index 15cefbf..5124675 100644
--- a/tests/mocks/database/drivers/sqlite.php
+++ b/tests/mocks/database/drivers/sqlite.php
@@ -5,12 +5,13 @@
 	/**
 	 * Instantiate the database driver
 	 *
-	 * @param  string 	DB Driver class name
-	 * @param  array 	DB configuration to set
-	 * @return void
+	 * @param	string	DB Driver class name
+	 * @param	array	DB configuration to set
+	 * @return	void
 	 */
 	public function __construct($config = array())
 	{
 		parent::__construct('CI_DB_sqlite3_driver', $config);
 	}
+
 }
\ No newline at end of file
diff --git a/tests/mocks/database/schema/skeleton.php b/tests/mocks/database/schema/skeleton.php
index 05499f8..18e1ddd 100644
--- a/tests/mocks/database/schema/skeleton.php
+++ b/tests/mocks/database/schema/skeleton.php
@@ -41,8 +41,7 @@
 
 		return static::$db;
 	}
-	
-	
+
 	/**
 	 * Create the dummy tables
 	 *
@@ -54,20 +53,20 @@
 		static::$forge->add_field(array(
 			'id' => array(
 				'type' => 'INTEGER',
-				'constraint' => 3,
+				'constraint' => 3
 			),
 			'name' => array(
 				'type' => 'VARCHAR',
-				'constraint' => 40,
+				'constraint' => 40
 			),
 			'email' => array(
 				'type' => 'VARCHAR',
-				'constraint' => 100,
+				'constraint' => 100
 			),
 			'country' => array(
 				'type' => 'VARCHAR',
-				'constraint' => 40,
-			),
+				'constraint' => 40
+			)
 		));
 		static::$forge->add_key('id', TRUE);
 		static::$forge->create_table('user', (strpos(static::$driver, 'pgsql') === FALSE));
@@ -76,15 +75,15 @@
 		static::$forge->add_field(array(
 			'id' => array(
 				'type' => 'INTEGER',
-				'constraint' => 3,
+				'constraint' => 3
 			),
 			'name' => array(
 				'type' => 'VARCHAR',
-				'constraint' => 40,
+				'constraint' => 40
 			),
 			'description' => array(
-				'type' => 'TEXT',
-			),
+				'type' => 'TEXT'
+			)
 		));
 		static::$forge->add_key('id', TRUE);
 		static::$forge->create_table('job', (strpos(static::$driver, 'pgsql') === FALSE));
@@ -93,15 +92,15 @@
 		static::$forge->add_field(array(
 			'id' => array(
 				'type' => 'INTEGER',
-				'constraint' => 3,
+				'constraint' => 3
 			),
 			'key' => array(
 				'type' => 'VARCHAR',
-				'constraint' => 40,
+				'constraint' => 40
 			),
 			'value' => array(
-				'type' => 'TEXT',
-			),
+				'type' => 'TEXT'
+			)
 		));
 		static::$forge->add_key('id', TRUE);
 		static::$forge->create_table('misc', (strpos(static::$driver, 'pgsql') === FALSE));
@@ -120,28 +119,29 @@
 				array('id' => 1, 'name' => 'Derek Jones', 'email' => 'derek@world.com', 'country' => 'US'),
 				array('id' => 2, 'name' => 'Ahmadinejad', 'email' => 'ahmadinejad@world.com', 'country' => 'Iran'),
 				array('id' => 3, 'name' => 'Richard A Causey', 'email' => 'richard@world.com', 'country' => 'US'),
-				array('id' => 4, 'name' => 'Chris Martin', 'email' => 'chris@world.com', 'country' => 'UK'),
+				array('id' => 4, 'name' => 'Chris Martin', 'email' => 'chris@world.com', 'country' => 'UK')
 			),
 			'job' => array(
-				array('id' => 1, 'name' => 'Developer', 'description' => 'Awesome job, but sometimes makes you bored'), 
+				array('id' => 1, 'name' => 'Developer', 'description' => 'Awesome job, but sometimes makes you bored'),
 				array('id' => 2, 'name' => 'Politician', 'description' => 'This is not really a job'),
-    			array('id' => 3, 'name' => 'Accountant', 'description' => 'Boring job, but you will get free snack at lunch'),
-			    array('id' => 4, 'name' => 'Musician', 'description' => 'Only Coldplay can actually called Musician'),
+    				array('id' => 3, 'name' => 'Accountant', 'description' => 'Boring job, but you will get free snack at lunch'),
+				array('id' => 4, 'name' => 'Musician', 'description' => 'Only Coldplay can actually called Musician')
 			),
 			'misc' => array(
-				array('id' => 1, 'key' => '\\xxxfoo456', 'value' => 'Entry with \\xxx'), 
-				array('id' => 2, 'key' => '\\%foo456', 'value' => 'Entry with \\%'),
-			),
+				array('id' => 1, 'key' => '\\xxxfoo456', 'value' => 'Entry with \\xxx'),
+				array('id' => 2, 'key' => '\\%foo456', 'value' => 'Entry with \\%')
+			)
 		);
 
-		foreach ($data as $table => $dummy_data) 
+		foreach ($data as $table => $dummy_data)
 		{
 			static::$db->truncate($table);
 
 			foreach ($dummy_data as $single_dummy_data)
 			{
-				static::$db->insert($table, $single_dummy_data); 
+				static::$db->insert($table, $single_dummy_data);
 			}
 		}
 	}
+
 }
\ No newline at end of file
diff --git a/tests/mocks/libraries/encrypt.php b/tests/mocks/libraries/encrypt.php
new file mode 100644
index 0000000..f185939
--- /dev/null
+++ b/tests/mocks/libraries/encrypt.php
@@ -0,0 +1,16 @@
+<?php
+
+class Mock_Libraries_Encrypt extends CI_Encrypt {
+
+	// Overide inaccesible protected method
+	public function __call($method, $params)
+	{
+		if (is_callable(array($this, '_'.$method)))
+		{
+			return call_user_func_array(array($this, '_'.$method), $params);
+		}
+
+		throw new BadMethodCallException('Method '.$method.' was not found');
+	}
+
+}
\ No newline at end of file
diff --git a/tests/mocks/libraries/table.php b/tests/mocks/libraries/table.php
index 97fbb30..87c278b 100644
--- a/tests/mocks/libraries/table.php
+++ b/tests/mocks/libraries/table.php
@@ -1,7 +1,7 @@
 <?php
 
 class Mock_Libraries_Table extends CI_Table {
-	
+
 	// Overide inaccesible protected method
 	public function __call($method, $params)
 	{
@@ -12,4 +12,5 @@
 
 		throw new BadMethodCallException('Method '.$method.' was not found');
 	}
+
 }
\ No newline at end of file
diff --git a/user_guide_src/source/changelog.rst b/user_guide_src/source/changelog.rst
index 587e56e..7748f9b 100644
--- a/user_guide_src/source/changelog.rst
+++ b/user_guide_src/source/changelog.rst
@@ -23,50 +23,62 @@
    -  Added an optional backtrace to php-error template.
    -  Added Android to the list of user agents.
    -  Added Windows 7, Android, Blackberry and iOS to the list of user platforms.
+   -  Added Fennec (Firefox for mobile) to the list of mobile user agents.
    -  Ability to log certain error types, not all under a threshold.
    -  Added support for pem, p10, p12, p7a, p7c, p7m, p7r, p7s, crt, crl, der, kdb, rsa, cer, sst, csr Certs to mimes.php.
    -  Added support for pgp and gpg to mimes.php.
    -  Added support for 3gp, 3g2, mp4, wmv, f4v, vlc Video files to mimes.php.
    -  Added support for m4a, aac, m4u, xspf, au, ac3, flac, ogg Audio files to mimes.php.
    -  Added support for kmz and kml (Google Earth) files to mimes.php.
-   -  Added Romanian and Greek characters in foreign_characters.php
+   -  Added support for ics Calendar files to mimes.php
+   -  Updated support for xml ('application/xml') and xsl ('application/xml', 'text/xsl') files in mimes.php.
    -  Updated support for doc files in mimes.php.
-   -  Added application/xml for xml and application/xml, text/xsl for xsl in mimes.php.
+   -  Added some more doctypes.
+   -  Added Romanian and Greek characters in foreign_characters.php.
    -  Changed logger to only chmod when file is first created.
    -  Removed previously deprecated SHA1 Library.
    -  Removed previously deprecated use of ``$autoload['core']`` in application/config/autoload.php.
       Only entries in ``$autoload['libraries']`` are auto-loaded now.
-   -  Added some more doctypes.
+   -  Removed previously deprecated EXT constant.
    -  Updated all classes to be written in PHP 5 style, with visibility declarations and no ``var`` usage for properties.
    -  Moved error templates to "application/views/errors"
-   -  Global config files are loaded first, then environment ones. Environment config keys overwrite base ones, allowing to only set the keys we want changed per Env.
+   -  Global config files are loaded first, then environment ones. Environment config keys overwrite base ones, allowing to only set the keys we want changed per environment.
+   -  Changed detection of ``$view_folder`` so that if it's not found in the current path, it will now also be searched for under the application folder.
+   -  Path constants BASEPATH, APPPATH and VIEWPATH are now (internally) defined as absolute paths.
 
 -  Helpers
 
-   -  create_captcha() accepts additional colors parameter, allowing for color customization
-   -  url_title() will now trim extra dashes from beginning and end.
+   -  :doc:`Date Helper <helpers/date_helper>` function now() now works with all timezone strings supported by PHP.
+   -  ``create_captcha()`` accepts additional colors parameter, allowing for color customization.
+   -  ``url_title()`` will now trim extra dashes from beginning and end.
    -  Added XHTML Basic 1.1 doctype to :doc:`HTML Helper <helpers/html_helper>`.
-   -  Changed humanize() to include a second param for the separator.
+   -  Changed ``humanize()`` to include a second param for the separator.
    -  Refactored ``plural()`` and ``singular()`` to avoid double pluralization and support more words.
    -  Added an optional third parameter to ``force_download()`` that enables/disables sending the actual file MIME type in the Content-Type header (disabled by default).
    -  Added an optional third parameter to ``timespan()`` that constrains the number of time units displayed.
-   -  Added a work-around in force_download() for a bug Android <= 2.1, where the filename extension needs to be in uppercase.
-   -  form_dropdown() will now also take an array for unity with other form helpers.
-   -  set_realpath() can now also handle file paths as opposed to just directories.
-   -  do_hash() now uses PHP's native hash() function, supporting more algorithms.
-   -  Added an optional paramater to ``delete_files()`` to enable it to skip deleting files such as .htaccess and index.html.
-   -  Removed deprecated helper function ``js_insert_smiley()`` from smiley helper.
+   -  Added a work-around in ``force_download()`` for a bug Android <= 2.1, where the filename extension needs to be in uppercase.
+   -  ``form_dropdown()`` will now also take an array for unity with other form helpers.
+   -  ``do_hash()`` now uses PHP's native ``hash()`` function (supporting more algorithms) and is deprecated.
+   -  Removed previously deprecated helper function ``js_insert_smiley()`` from smiley helper.
+   -  :doc:`File Helper <helpers/file_helper>` changes include:
+	 - ``set_realpath()`` can now also handle file paths as opposed to just directories.
+	 - Added an optional paramater to ``delete_files()`` to enable it to skip deleting files such as .htaccess and index.html.
+	 - ``read_file()`` is now a deprecated alias of ``file_get_contents()``.
 
 -  Database
 
-   -  Renamed the Active Record class to Query Builder to remove confusion with the Active Record design pattern.
-   -  Added the ability to insert objects with insert_batch() in :doc:`Query Builder <database/query_builder>`.
-   -  Added new :doc:`Query Builder <database/query_builder>` methods that return the SQL string of queries without executing them: get_compiled_select(), get_compiled_insert(), get_compiled_update(), get_compiled_delete().
-   -  Adding $escape parameter to the order_by() method, this enables ordering by custom fields.
+   -  :doc:`Query Builder <database/query_builder>` changes include:
+	 - Renamed the Active Record class to Query Builder to remove confusion with the Active Record design pattern.
+	 - Added the ability to insert objects with insert_batch().
+	 - Added new methods that return the SQL string of queries without executing them: get_compiled_select(), get_compiled_insert(), get_compiled_update(), get_compiled_delete().
+	 - Added an optional order_by() parameter that allows to disable escaping (useful for custom fields).
+	 - Added an optional join() parameter that allows to disable escaping.
+	 - Added support for join() with multiple conditions.
    -  Improved support for the MySQLi driver, including:
-	 -  OOP style of the PHP extension is now used, instead of the procedural aliases.
-	 -  Server version checking is now done via ``mysqli::$server_info`` instead of running an SQL query.
-	 -  Added persistent connections support for PHP >= 5.3.
+	 - OOP style of the PHP extension is now used, instead of the procedural aliases.
+	 - Server version checking is now done via ``mysqli::$server_info`` instead of running an SQL query.
+	 - Added persistent connections support for PHP >= 5.3.
+	 - Added support for backup() in :doc:`Database Utilities <database/utilities>`.
    -  Added 'dsn' configuration setting for drivers that support DSN strings (PDO, PostgreSQL, Oracle, ODBC, CUBRID).
    -  Improved PDO database support.
    -  Added Interbase/Firebird database support via the "interbase" driver.
@@ -74,34 +86,41 @@
    -  Replaced the _error_message() and _error_number() methods with error(), that returns an array containing the last database error code and message.
    -  Improved version() implementation so that drivers that have a native function to get the version number don't have to be defined in the core DB_driver class.
    -  Improved support of the PostgreSQL driver, including:
-	 -  pg_version() is now used to get the database version number, when possible.
-	 -  Added db_set_charset() support.
-	 -  Added _optimize_table() support for the :doc:`Database Utility Class <database/utilities>` (rebuilds table indexes).
-	 -  Added boolean data type support in escape().
-	 -  Added update_batch() support.
+	 - pg_version() is now used to get the database version number, when possible.
+	 - Added db_set_charset() support.
+	 - Added support for optimize_table() in :doc:`Database Utilities <database/utilities>` (rebuilds table indexes).
+	 - Added boolean data type support in escape().
+	 - Added update_batch() support.
+	 - Removed limit() and order_by() support for UPDATE and DELETE queries in as PostgreSQL does not support those features.
    -  Added a constructor to the DB_result class and moved all driver-specific properties and logic out of the base DB_driver class to allow better abstraction.
-   -  Removed limit() and order_by() support for UPDATE and DELETE queries in PostgreSQL driver. Postgres does not support those features.
    -  Removed protect_identifiers() and renamed internal method _protect_identifiers() to it instead - it was just an alias.
+   -  Renamed internal method _escape_identifiers() to escape_identifiers().
+   -  Updated escape_identifiers() to accept an array of fields as well as strings.
    -  MySQL and MySQLi drivers now require at least MySQL version 5.1.
    -  db_set_charset() now only requires one parameter (collation was only needed due to legacy support for MySQL versions prior to 5.1).
-   -  Added DSN string support for CUBRID.
-   -  Added persistent connections support for CUBRID.
-   -  Added random ordering support for MSSQL, SQLSRV.
    -  Added support for SQLite3 database driver.
+   -  Improved support of the CUBRID driver, including:
+	 - Added DSN string support.
+	 - Added persistent connections support.
+	 - Improved list_databases() in :doc:`Database Utility <database/utilities>` (until now only the currently used database was returned).
+   -  Improved support of the MSSQL and SQLSRV drivers, including:
+	 - Added random ordering support.
+	 - Added support for optimize_table() in :doc:`Database Utility <database/utilities>`.
+	 - Added escaping with QUOTE_IDENTIFIER setting detection.
+	 - Added port handling support for UNIX-based systems (MSSQL driver).
+	 - Added OFFSET support for SQL Server 2005 and above.
    -  Improved support of the Oracle (OCI8) driver, including:
-	 -  Added DSN string support (Easy Connect and TNS).
-	 -  Added support for dropping tables to :doc:`Database Forge <database/forge>`.
-	 -  Added support for listing database schemas to :doc:`Database Utilities <database/utilities>`.
-	 -  Generally improved for speed and cleaned up all of its components.
-	 -  *Row* result methods now really only fetch only the needed number of rows, instead of depending entirely on result().
-	 -  num_rows() is now only called explicitly by the developer and no longer re-executes statements.
-   -  Added replace() support for SQLite.
-   -  Renamed internal method _escape_identifiers() to escape_identifiers().
-   -  Added SQLite support for drop_table() in :doc:`Database Forge <database/forge>`.
+	 - Added DSN string support (Easy Connect and TNS).
+	 - Added support for drop_table() in :doc:`Database Forge <database/forge>`.
+	 - Added support for list_databases() in :doc:`Database Utilities <database/utilities>`.
+	 - Generally improved for speed and cleaned up all of its components.
+	 - *Row* result methods now really only fetch only the needed number of rows, instead of depending entirely on result().
+	 - num_rows() is now only called explicitly by the developer and no longer re-executes statements.
+   -  Improved support of the SQLite driver, including:
+	 - Added support for replace() in :doc:`Query Builder <database/query_builder>`.
+	 - Added support for drop_table() in :doc:`Database Forge <database/forge>`.
    -  Added ODBC support for create_database(), drop_database() and drop_table() in :doc:`Database Forge <database/forge>`.
    -  Added PDO support for create_database(), drop_database and drop_table() in :doc:`Database Forge <database/forge>`.
-   -  Added MSSQL, SQLSRV support for optimize_table() in :doc:`Database Utility <database/utilities>`.
-   -  Improved CUBRID support for list_databases() in :doc:`Database Utility <database/utilities>` (until now only the currently used database was returned).
    -  Added unbuffered_row() method for getting a row without prefetching whole result (consume less memory).
 
 -  Libraries
@@ -129,11 +148,16 @@
 	 -  _execute() now considers input data to be invalid if a specified rule is not found.
 	 -  Removed method is_numeric() as it exists as a native PHP function and _execute() will find and use that (the 'is_numeric' rule itself is deprecated since 1.6.1).
 	 -  Native PHP functions used as rules can now accept an additional parameter, other than the data itself.
+	 -  Updated set_rules() to accept an array of rules as well as a string.
    -  Changed the :doc:`Session Library <libraries/sessions>` to select only one row when using database sessions.
    -  Added all_flashdata() method to session class. Returns an associative array of only flashdata.
    -  Allowed for setting table class defaults in a config file.
    -  Added a Wincache driver to the :doc:`Caching Library <libraries/caching>`.
+   -  Added a Redis driver to the :doc:`Caching Library <libraries/caching>`.
    -  Added dsn (delivery status notification) option to the :doc:`Email Library <libraries/email>`.
+   -  Renamed method _set_header() to set_header() and made it public to enable adding custom headers in the :doc:`Email Library <libraries/email>`.
+   -  Added an "index" parameter to the data() method in the :doc:`Upload Library <libraries/file_uploading>`.
+   -  Added support for the anchor "rel" attribute in the :doc:`Pagination Library <libraries/pagination>`.
 
 -  Core
 
@@ -147,6 +171,9 @@
    -  Added support for HTTP-Only cookies with new config option ``cookie_httponly`` (default FALSE).
    -  Renamed method _call_hook() to call_hook() in the :doc:`Hooks Library <general/hooks>`.
    -  Added get_content_type() method to the :doc:`Output Library <libraries/output>`.
+   -  Added get_mimes() function to system/core/Commons.php to return the config/mimes.php array.
+   -  Added a second argument to set_content_type() in the :doc:`Output Library <libraries/output>` that allows setting the document charset as well.
+   -  $config['time_reference'] now supports all timezone strings supported by PHP.
 
 Bug fixes for 3.0
 ------------------
@@ -154,7 +181,7 @@
 -  Fixed a bug where ``unlink()`` raised an error if cache file did not exist when you try to delete it.
 -  Fixed a bug (#181) where a mis-spelling was in the form validation language file.
 -  Fixed a bug (#159, #163) that mishandled Query Builder nested transactions because _trans_depth was not getting incremented.
--  Fixed a bug (#737, #75) where pagination anchor class was not set properly when using initialize method.
+-  Fixed a bug (#737, #75) - :doc:`Pagination <libraries/pagination>` anchor class was not set properly when using initialize method.
 -  Fixed a bug (#419) - auto_link() now recognizes URLs that come after a word boundary.
 -  Fixed a bug (#724) - is_unique in form validation now checks that you are connected to a database.
 -  Fixed a bug (#647) - _get_mod_time() in Zip library no longer generates stat failed errors.
@@ -165,7 +192,7 @@
 -  Fixed a bug (#797) - timespan() was using incorrect seconds for year and month.
 -  Fixed a bug in CI_Cart::contents() where if called without a TRUE (or equal) parameter, it would fail due to a typo.
 -  Fixed a bug (#696) - make oci_execute() calls inside num_rows() non-committing, since they are only there to reset which row is next in line for oci_fetch calls and thus don't need to be committed.
--  Fixed a bug (#406) - sqlsrv DB driver not returning resource on ``db_pconnect()``.
+-  Fixed a bug (#406) - SQLSRV DB driver not returning resource on ``db_pconnect()``.
 -  Fixed a bug in CI_Image_lib::gd_loaded() where it was possible for the script execution to end or a PHP E_WARNING message to be emitted.
 -  Fixed a bug in the :doc:`Pagination library <libraries/pagination>` where when use_page_numbers=TRUE previous link and page 1 link did not have the same url.
 -  Fixed a bug (#561) - Errors in :doc:`XML-RPC Library <libraries/xmlrpc>` were not properly escaped.
@@ -223,19 +250,39 @@
 -  Fixed a bug (#121) - ``CI_DB_result::row()`` returned an array when there's no actual result to be returned.
 -  Fixed a bug (#319) - SQLSRV's affected_rows() method failed due to a scrollable cursor being created for write-type queries.
 -  Fixed a bug (#356) - PostgreSQL driver didn't have an _update_batch() method, which resulted in fatal error being triggered when update_batch() is used with it.
--  Fixed a bug (#862) - create_table() failed on SQLSRV/MSSQL when used with 'IF NOT EXISTS'.
+-  Fixed a bug (#784, #862) - :doc:`Database Forge <database/forge>` method ``create_table()`` failed on SQLSRV/MSSQL when used with 'IF NOT EXISTS'.
 -  Fixed a bug (#1419) - libraries/Driver.php had a static variable that was causing an error.
+-  Fixed a bug (#1411) - the :doc:`Email library <libraries/email>` used its own short list of MIMEs instead the one from config/mimes.php.
+-  Fixed a bug where the magic_quotes_runtime setting wasn't turned off for PHP 5.3 (where it is indeed deprecated, but not non-existent).
+-  Fixed a bug (#666) - :doc:`Output library <libraries/output>`'s set_content_type() method didn't set the document charset.
+-  Fixed a bug (#784, #861) - :doc:`Database Forge <database/forge>` method ``create_table()`` used to accept constraints for MSSQL/SQLSRV integer-type columns.
+-  Fixed a bug (#706) - SQLSRV/MSSSQL didn't escape field names.
+-  Fixed a bug (#1452) - protect_identifiers() didn't properly detect identifiers with spaces in their names.
+-  Fixed a bug where protect_identifiers() ignored it's extra arguments when the value passed to it is an array.
+-  Fixed a bug where _has_operator() didn't detect BETWEEN.
+-  Fixed a bug in :doc:`Query Builder <database/query_builder>`'s join() method where it failed with identifiers containing dashes.
+-  Fixed a bug (#1264) - :doc:`Database Forge <database/forge>` and :doc:`Database Utilities <database/utilities>` didn't update/reset the databases and tables list cache when a table or a database is created, dropped or renamed.
+-  Fixed a bug (#7) - :doc:`Query Builder <database/query_builder>`'s join() method only escaped one set of conditions.
+-  Fixed a bug (#1321) - Core Exceptions class couldn't find the errors/ folder in some cases.
+-  Fixed a bug in the File-based :doc:`Cache Library <libraries/caching>` driver's get_metadata() method where a non-existent array key was accessed for the TTL value.
+-  Fixed a bug (#1202) - :doc:`Encryption Library <libraries/encryption>` encode_from_legacy() didn't set back the encrypt mode on failure.
+-  Fixed a bug (#145) - compile_binds() failed when the bind marker was present in a literal string within the query.
+-  Fixed a bug in protect_identifiers() where if passed along with the field names, operators got escaped as well.
+-  Fixed a bug (#10) - :doc:`URI Library <libraries/uri>` internal method _detect_uri() failed with paths containing a colon.
+-  Fixed a bug (#1387) - :doc:`Query Builder <database/query_builder>`'s from() method didn't escape table aliases.
 
 Version 2.1.1
 =============
 
-Release Date: Not Released
+Release Date: June 13, 2012
 
 -  General Changes
    -  Fixed support for docx, xlsx files in mimes.php.
 
 -  Libraries
    -  Further improved MIME type detection in the :doc:`File Uploading Library <libraries/file_uploading>`.
+   -  Added support for IPv6 to the :doc:`Input Library <libraries/input>`.
+   -  Added support for the IP format parameter to the :doc:`Form Validation Library <libraries/form_validation>`.
 
 -  Helpers
    -  url_title() performance and output improved. You can now use any string as the word delimiter, but 'dash' and 'underscore' are still supported.
@@ -250,6 +297,8 @@
 -  Fixed a bug - When database caching was enabled, $this->db->query() checked the cache before binding variables which resulted in cached queries never being found.
 -  Fixed a bug - CSRF cookie value was allowed to be any (non-empty) string before being written to the output, making code injection a risk.
 -  Fixed a bug (#726) - PDO put a 'dbname' argument in it's connection string regardless of the database platform in use, which made it impossible to use SQLite.
+-  Fixed a bug - CI_DB_pdo_driver::num_rows() was not returning properly value with SELECT queries, cause it was relying on PDOStatement::rowCount().
+-  Fixed a bug (#1059) - CI_Image_lib::clear() was not correctly clearing all necessary object properties, namely width and height.
 
 Version 2.1.0
 =============
diff --git a/user_guide_src/source/general/common_functions.rst b/user_guide_src/source/general/common_functions.rst
index 70563b8..99126f9 100644
--- a/user_guide_src/source/general/common_functions.rst
+++ b/user_guide_src/source/general/common_functions.rst
@@ -79,3 +79,8 @@
 This function provides short cut for htmlspecialchars() function. It
 accepts string and array. To prevent Cross Site Scripting (XSS), it is
 very useful.
+
+get_mimes()
+=============
+
+This function returns the MIMEs array from config/mimes.php.
\ No newline at end of file
diff --git a/user_guide_src/source/general/core_classes.rst b/user_guide_src/source/general/core_classes.rst
index ac41407..4aa6693 100644
--- a/user_guide_src/source/general/core_classes.rst
+++ b/user_guide_src/source/general/core_classes.rst
@@ -31,6 +31,7 @@
 -  Log
 -  Output
 -  Router
+-  Security
 -  URI
 -  Utf8
 
diff --git a/user_guide_src/source/general/requirements.rst b/user_guide_src/source/general/requirements.rst
index d97b7b4..d9edfba 100644
--- a/user_guide_src/source/general/requirements.rst
+++ b/user_guide_src/source/general/requirements.rst
@@ -4,5 +4,6 @@
 
 -  `PHP <http://www.php.net/>`_ version 5.2.4 or newer.
 -  A Database is required for most web application programming. Current
-   supported databases are MySQL (5.1+), MySQLi, MS SQL, SQLSRV, Oracle,
-   PostgreSQL, SQLite, SQLite3, CUBRID, Interbase, ODBC and PDO.
+   supported databases are MySQL (5.1+), MySQLi, Oracle, PostgreSQL,
+   MS SQL, SQLSRV (SQL Server 2005+), SQLite, SQLite3, CUBRID, Interbase,
+   ODBC and PDO.
diff --git a/user_guide_src/source/helpers/date_helper.rst b/user_guide_src/source/helpers/date_helper.rst
index 18216c5..1b7177f 100644
--- a/user_guide_src/source/helpers/date_helper.rst
+++ b/user_guide_src/source/helpers/date_helper.rst
@@ -21,13 +21,21 @@
 =====
 
 Returns the current time as a Unix timestamp, referenced either to your
-server's local time or GMT, based on the "time reference" setting in
-your config file. If you do not intend to set your master time reference
-to GMT (which you'll typically do if you run a site that lets each user
-set their own timezone settings) there is no benefit to using this
+server's local time or any PHP suported timezone, based on the "time reference"
+setting in your config file. If you do not intend to set your master time reference
+to any other PHP suported timezone (which you'll typically do if you run a site that
+lets each user set their own timezone settings) there is no benefit to using this
 function over PHP's time() function.
 
-.. php:method:: now()
+.. php:method:: now($timezone = NULL)
+
+	:param string 	$timezone: The timezone you want to be returned
+	:returns: integer
+
+::
+	echo now("Australia/Victoria");
+
+If a timezone is not provided, it will return time() based on "time_reference" setting.
 
 mdate()
 =======
diff --git a/user_guide_src/source/helpers/file_helper.rst b/user_guide_src/source/helpers/file_helper.rst
index bfc271e..60c5aa9 100644
--- a/user_guide_src/source/helpers/file_helper.rst
+++ b/user_guide_src/source/helpers/file_helper.rst
@@ -32,6 +32,9 @@
 	controller or view files. CodeIgniter uses a front controller so paths
 	are always relative to the main site index.
 
+.. note:: This function is DEPRECATED. Use the native ``file_get_contents()``
+	instead.
+
 If your server is running an `open_basedir` restriction this function might not work if you are trying to access a file above the calling script.
 
 write_file('path', $data)
diff --git a/user_guide_src/source/helpers/security_helper.rst b/user_guide_src/source/helpers/security_helper.rst
index b1bcf2b..ec0be28 100644
--- a/user_guide_src/source/helpers/security_helper.rst
+++ b/user_guide_src/source/helpers/security_helper.rst
@@ -43,8 +43,10 @@
 	$str = do_hash($str); // SHA1
 	$str = do_hash($str, 'md5'); // MD5
 
-.. note:: This function was formerly named dohash(), which has been
-	removed in favor of `do_hash()`.
+.. note:: This function was formerly named ``dohash()``, which has been
+	removed in favor of ``do_hash()``.
+
+.. note:: This function is DEPRECATED. Use the native ``hash()`` instead.
 
 strip_image_tags()
 ==================
diff --git a/user_guide_src/source/helpers/string_helper.rst b/user_guide_src/source/helpers/string_helper.rst
index 2d23fb0..19500aa 100644
--- a/user_guide_src/source/helpers/string_helper.rst
+++ b/user_guide_src/source/helpers/string_helper.rst
@@ -36,8 +36,7 @@
 -  **unique**: Encrypted with MD5 and uniqid(). Note: The length
    parameter is not available for this type. Returns a fixed length 32
    character string.
--  **sha1**: An encrypted random number based on do_hash() from the
-   :doc:`security helper <security_helper>`.
+-  **sha1**: An encrypted random number based on ``sha1()``.
 
 Usage example
 
diff --git a/user_guide_src/source/installation/upgrade_300.rst b/user_guide_src/source/installation/upgrade_300.rst
index 63c4227..c70737c 100644
--- a/user_guide_src/source/installation/upgrade_300.rst
+++ b/user_guide_src/source/installation/upgrade_300.rst
@@ -41,8 +41,8 @@
     $active_group = 'default';
     // $active_record = TRUE;
     $query_builder = TRUE;
-    
+
 Step 5: Move your errors folder
 ===============================
 
-In version 3.0.0, the errors folder has been moved from "application/errors" to "application/views/errors".
\ No newline at end of file
+In version 3.0.0, the errors folder has been moved from _application/errors_ to _application/views/errors_.
\ No newline at end of file
diff --git a/user_guide_src/source/installation/upgrading.rst b/user_guide_src/source/installation/upgrading.rst
index 2badffc..255c6a5 100644
--- a/user_guide_src/source/installation/upgrading.rst
+++ b/user_guide_src/source/installation/upgrading.rst
@@ -5,7 +5,8 @@
 Please read the upgrade notes corresponding to the version you are
 upgrading from.
 
--  :doc:`Upgrading from 2.0.3 to 2.1.0 <upgrade_210>`
+-  :doc:`Upgrading from 2.1.1 to 3.0.0 <upgrade_300>`
+-  :doc:`Upgrading from 2.1.0 to 2.1.1 <upgrade_211>`
 -  :doc:`Upgrading from 2.0.2 to 2.0.3 <upgrade_203>`
 -  :doc:`Upgrading from 2.0.1 to 2.0.2 <upgrade_202>`
 -  :doc:`Upgrading from 2.0 to 2.0.1 <upgrade_201>`
diff --git a/user_guide_src/source/libraries/email.rst b/user_guide_src/source/libraries/email.rst
index daf0009..f99eb91 100644
--- a/user_guide_src/source/libraries/email.rst
+++ b/user_guide_src/source/libraries/email.rst
@@ -182,6 +182,14 @@
 accept HTML email. If you do not set your own message CodeIgniter will
 extract the message from your HTML email and strip the tags.
 
+$this->email->set_header()
+-----------------------
+
+Appends additional headers to the e-mail::
+
+	$this->email->set_header('Header1', 'Value1');
+	$this->email->set_header('Header2', 'Value2');
+
 $this->email->clear()
 ---------------------
 
diff --git a/user_guide_src/source/libraries/file_uploading.rst b/user_guide_src/source/libraries/file_uploading.rst
index d573fc7..414d84f 100644
--- a/user_guide_src/source/libraries/file_uploading.rst
+++ b/user_guide_src/source/libraries/file_uploading.rst
@@ -287,6 +287,10 @@
 	    [image_size_str] => width="800" height="200"
 	)
 
+To return one element from the array::
+
+	$this->upload->data('file_name');	// Returns: mypic.jpg
+
 Explanation
 ***********
 
diff --git a/user_guide_src/source/libraries/form_validation.rst b/user_guide_src/source/libraries/form_validation.rst
index 028b61c..3bcad7b 100644
--- a/user_guide_src/source/libraries/form_validation.rst
+++ b/user_guide_src/source/libraries/form_validation.rst
@@ -304,6 +304,10 @@
 new error messages that correspond to your new rules. There are numerous
 rules available which you can read about in the validation reference.
 
+.. note:: You can also pass an array of rules to set_rules(), instead of a string. Example::
+
+	$this->form_validation->set_rules('username', 'Username', array('required', 'min_length[5]'));
+
 Prepping Data
 =============
 
@@ -884,6 +888,7 @@
 **valid_email**           No         Returns FALSE if the form element does not contain a valid email address.
 **valid_emails**          No         Returns FALSE if any value provided in a comma separated list is not a valid email.
 **valid_ip**              No         Returns FALSE if the supplied IP is not valid.
+                                     Accepts an optional parameter of 'ipv4' or 'ipv6' to specify an IP format.
 **valid_base64**          No         Returns FALSE if the supplied string contains anything other than valid Base64 characters.
 ========================= ========== ============================================================================================= =======================
 
@@ -934,7 +939,7 @@
 
 		:param string $field: The field name
 		:param string $label: The field label
-		:param string $rules: The rules, seperated by a pipe "|"
+		:param mixed $rules: The rules, as a string with rules separated by a pipe "|", or an array or rules.
 		:rtype: Object
 	
 		Permits you to set validation rules, as described in the tutorial
diff --git a/user_guide_src/source/libraries/input.rst b/user_guide_src/source/libraries/input.rst
index 432bac3..c0b9c65 100644
--- a/user_guide_src/source/libraries/input.rst
+++ b/user_guide_src/source/libraries/input.rst
@@ -42,14 +42,14 @@
 Please refer to the :doc:`Security class <security>` documentation for
 information on using XSS Filtering in your application.
 
-Using POST, COOKIE, or SERVER Data
-==================================
+Using POST, GET, COOKIE, or SERVER Data
+=======================================
 
-CodeIgniter comes with three helper functions that let you fetch POST,
+CodeIgniter comes with four helper methods that let you fetch POST, GET,
 COOKIE or SERVER items. The main advantage of using the provided
 functions rather than fetching an item directly ($_POST['something'])
-is that the functions will check to see if the item is set and return
-false (boolean) if not. This lets you conveniently use data without
+is that the methods will check to see if the item is set and return
+NULL if not. This lets you conveniently use data without
 having to test whether an item exists first. In other words, normally
 you might do something like this::
 
@@ -59,9 +59,10 @@
 
 	$something = $this->input->post('something');
 
-The three functions are:
+The four methods are:
 
 -  $this->input->post()
+-  $this->input->get()
 -  $this->input->cookie()
 -  $this->input->server()
 
@@ -73,8 +74,8 @@
 
 	$this->input->post('some_data');
 
-The function returns FALSE (boolean) if the item you are attempting to
-retrieve does not exist.
+The function returns NULL if the item you are attempting to retrieve
+does not exist.
 
 The second optional parameter lets you run the data through the XSS
 filter. It's enabled by setting the second parameter to boolean TRUE;
@@ -130,7 +131,9 @@
 This function is identical to the post function, only it fetches cookie
 data::
 
-	$this->input->cookie('some_data', TRUE);
+	$this->input->cookie('some_cookie');
+	$this->input->cookie('some_cookie, TRUE); // with XSS filter
+
 
 $this->input->server()
 ======================
@@ -195,25 +198,6 @@
 
 	$this->input->set_cookie($name, $value, $expire, $domain, $path, $prefix, $secure);
 
-$this->input->cookie()
-======================
-
-Lets you fetch a cookie. The first parameter will contain the name of
-the cookie you are looking for (including any prefixes)::
-
-	cookie('some_cookie');
-
-The function returns NULL if the item you are attempting to
-retrieve does not exist.
-
-The second optional parameter lets you run the data through the XSS
-filter. It's enabled by setting the second parameter to boolean TRUE;
-
-::
-
-	cookie('some_cookie', TRUE);
-
-
 $this->input->ip_address()
 ===========================
 
@@ -242,6 +226,9 @@
 	     echo 'Valid';
 	}
 
+Accepts an optional second string parameter of 'ipv4' or 'ipv6' to specify
+an IP format. The default checks for both formats.
+
 $this->input->user_agent()
 ===========================
 
diff --git a/user_guide_src/source/libraries/output.rst b/user_guide_src/source/libraries/output.rst
index baceaae..0472d14 100644
--- a/user_guide_src/source/libraries/output.rst
+++ b/user_guide_src/source/libraries/output.rst
@@ -49,6 +49,10 @@
 .. important:: Make sure any non-mime string you pass to this method
 	exists in config/mimes.php or it will have no effect.
 
+You can also set the character set of the document, by passing a second argument::
+
+	$this->output->set_content_type('css', 'utf-8');
+
 $this->output->get_content_type();
 ==========================================
 
diff --git a/user_guide_src/source/libraries/pagination.rst b/user_guide_src/source/libraries/pagination.rst
index f1653c9..560755f 100644
--- a/user_guide_src/source/libraries/pagination.rst
+++ b/user_guide_src/source/libraries/pagination.rst
@@ -254,3 +254,27 @@
 If you want to add a class attribute to every link rendered by the
 pagination class, you can set the config "anchor_class" equal to the
 classname you want.
+
+::
+
+	$config['anchor_class'] = 'myclass'; // class="myclass"
+
+**********************************
+Changing the "rel" attribute value
+**********************************
+
+By default, the rel attribute will be automatically put under the
+following conditions:
+
+- rel="start" for the "first" link
+- rel="prev" for the "previous" link
+- rel="next" for the "next" link
+
+If you want to disable the rel attribute, or change its value, you
+can set the 'attr_rel' config option::
+
+	// Disable
+	$config['attr_rel'] = FALSE;
+
+	// Use a custom value on all anchors
+	$config['attr_rel'] = 'custom_value'; // produces: rel="custom_value"
\ No newline at end of file
diff --git a/user_guide_src/source/libraries/sessions.rst b/user_guide_src/source/libraries/sessions.rst
index e8332ee..5400524 100644
--- a/user_guide_src/source/libraries/sessions.rst
+++ b/user_guide_src/source/libraries/sessions.rst
@@ -245,7 +245,7 @@
 
 	CREATE TABLE IF NOT EXISTS  `ci_sessions` (
 		session_id varchar(40) DEFAULT '0' NOT NULL,
-		ip_address varchar(16) DEFAULT '0' NOT NULL,
+		ip_address varchar(45) DEFAULT '0' NOT NULL,
 		user_agent varchar(120) NOT NULL,
 		last_activity int(10) unsigned DEFAULT 0 NOT NULL,
 		user_data text NOT NULL,
diff --git a/user_guide_src/source/libraries/uri.rst b/user_guide_src/source/libraries/uri.rst
index cdd76e3..bb959b0 100644
--- a/user_guide_src/source/libraries/uri.rst
+++ b/user_guide_src/source/libraries/uri.rst
@@ -146,7 +146,7 @@
 
 The function would return this::
 
-	/news/local/345
+	news/local/345
 
 $this->uri->ruri_string()
 ==========================