Merge branch 'develop' of github.com:EllisLab/CodeIgniter into feature/exit-status
diff --git a/.travis.yml b/.travis.yml
index 070b23c..ab0aa56 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -14,8 +14,7 @@
   - DB=pdo/sqlite
 
 before_script:
-  - curl -s http://getcomposer.org/installer | php
-  - php composer.phar install
+  - composer install --dev --no-progress
   - sh -c "if [ '$DB' = 'pgsql' ] || [ '$DB' = 'pdo/pgsql' ]; then psql -c 'DROP DATABASE IF EXISTS ci_test;' -U postgres; fi"
   - sh -c "if [ '$DB' = 'pgsql' ] || [ '$DB' = 'pdo/pgsql' ]; then psql -c 'create database ci_test;' -U postgres; fi"
   - sh -c "if [ '$DB' = 'mysql' ] || [ '$DB' = 'mysqli' ] || [ '$DB' = 'pdo/mysql' ]; then mysql -e 'create database IF NOT EXISTS ci_test;'; fi"
diff --git a/application/config/config.php b/application/config/config.php
index 415474e..0608348 100644
--- a/application/config/config.php
+++ b/application/config/config.php
@@ -226,6 +226,20 @@
 
 /*
 |--------------------------------------------------------------------------
+| Log File Extension
+|--------------------------------------------------------------------------
+|
+| The default filename extension for log files. The default 'php' allows for
+| protecting the log files via basic scripting, when they are to be stored
+| under a publicly accessible directory.
+|
+| Note: Leaving it blank will default to 'php'.
+|
+*/
+$config['log_file_extension'] = '';
+
+/*
+|--------------------------------------------------------------------------
 | Date Format for Logs
 |--------------------------------------------------------------------------
 |
diff --git a/application/config/mimes.php b/application/config/mimes.php
index 124e4a4..5b8ceff 100644
--- a/application/config/mimes.php
+++ b/application/config/mimes.php
@@ -44,13 +44,13 @@
 	'lzh'	=>	'application/octet-stream',
 	'exe'	=>	array('application/octet-stream', 'application/x-msdownload'),
 	'class'	=>	'application/octet-stream',
-	'psd'	=>	'application/x-photoshop',
+	'psd'	=>	array('application/x-photoshop', 'image/vnd.adobe.photoshop'),
 	'so'	=>	'application/octet-stream',
 	'sea'	=>	'application/octet-stream',
 	'dll'	=>	'application/octet-stream',
 	'oda'	=>	'application/oda',
 	'pdf'	=>	array('application/pdf', 'application/x-download', 'binary/octet-stream'),
-	'ai'	=>	'application/postscript',
+	'ai'	=>	array('application/pdf', 'application/postscript'),
 	'eps'	=>	'application/postscript',
 	'ps'	=>	'application/postscript',
 	'smi'	=>	'application/smil',
@@ -123,7 +123,7 @@
 	'avi'	=>	array('video/x-msvideo', 'video/msvideo', 'video/avi', 'application/x-troff-msvideo'),
 	'movie'	=>	'video/x-sgi-movie',
 	'doc'	=>	array('application/msword', 'application/vnd.ms-office'),
-	'docx'	=>	array('application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/zip', 'application/msword'),
+	'docx'	=>	array('application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/zip', 'application/msword', 'application/x-zip'),
 	'dot'	=>	array('application/msword', 'application/vnd.ms-office'),
 	'dotx'	=>	array('application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/zip', 'application/msword'),
 	'xlsx'	=>	array('application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'application/zip', 'application/vnd.ms-excel', 'application/msword'),
@@ -154,12 +154,13 @@
 	'mp4'   =>	'video/mp4',
 	'm4a'   =>	'audio/x-m4a',
 	'f4v'   =>	'video/mp4',
+	'webm'	=>	'video/webm',
 	'aac'   =>	'audio/x-acc',
 	'm4u'   =>	'application/vnd.mpegurl',
 	'm3u'   =>	'text/plain',
 	'xspf'  =>	'application/xspf+xml',
 	'vlc'   =>	'application/videolan',
-	'wmv'   =>	'video/x-ms-wmv',
+	'wmv'   =>	array('video/x-ms-wmv', 'video/x-ms-asf'),
 	'au'    =>	'audio/x-au',
 	'ac3'   =>	'audio/ac3',
 	'flac'  =>	'audio/x-flac',
diff --git a/composer.json b/composer.json
index 7d60020..e21aaed 100644
--- a/composer.json
+++ b/composer.json
@@ -1,8 +1,9 @@
 {
+    "name" : "ellislab/codeigniter",
     "require": {
-        "mikey179/vfsStream": "*"
+        "php": ">=5.2.4"
     },
     "require-dev": {
-		"phpunit/phpunit": "*"
-	}
+      "mikey179/vfsStream": "*"
+		}
 }
\ No newline at end of file
diff --git a/system/core/CodeIgniter.php b/system/core/CodeIgniter.php
index 13826c3..5a872ef 100644
--- a/system/core/CodeIgniter.php
+++ b/system/core/CodeIgniter.php
@@ -58,7 +58,7 @@
  *  Load the framework constants
  * ------------------------------------------------------
  */
-	if (defined('ENVIRONMENT') && file_exists(APPPATH.'config/'.ENVIRONMENT.'/constants.php'))
+	if (file_exists(APPPATH.'config/'.ENVIRONMENT.'/constants.php'))
 	{
 		require(APPPATH.'config/'.ENVIRONMENT.'/constants.php');
 	}
@@ -263,7 +263,7 @@
 	$class  = $RTR->fetch_class();
 	$method = $RTR->fetch_method();
 
-	if ( ! class_exists($class) OR $method[0] === '_' OR method_exists('CI_Controller', $method))
+	if ( ! class_exists($class, FALSE) OR $method[0] === '_' OR method_exists('CI_Controller', $method))
 	{
 		if ( ! empty($RTR->routes['404_override']))
 		{
@@ -272,7 +272,7 @@
 				$method = 'index';
 			}
 
-			if ( ! class_exists($class))
+			if ( ! class_exists($class, FALSE))
 			{
 				if ( ! file_exists(APPPATH.'controllers/'.$class.'.php'))
 				{
@@ -310,7 +310,7 @@
 				$method = 'index';
 			}
 
-			if ( ! class_exists($class))
+			if ( ! class_exists($class, FALSE))
 			{
 				if ( ! file_exists(APPPATH.'controllers/'.$class.'.php'))
 				{
diff --git a/system/core/Common.php b/system/core/Common.php
index d638720..3cd97dc 100644
--- a/system/core/Common.php
+++ b/system/core/Common.php
@@ -150,7 +150,7 @@
 			{
 				$name = $prefix.$class;
 
-				if (class_exists($name) === FALSE)
+				if (class_exists($name, FALSE) === FALSE)
 				{
 					require_once($path.$directory.'/'.$class.'.php');
 				}
@@ -164,7 +164,7 @@
 		{
 			$name = config_item('subclass_prefix').$class;
 
-			if (class_exists($name) === FALSE)
+			if (class_exists($name, FALSE) === FALSE)
 			{
 				require_once(APPPATH.$directory.'/'.config_item('subclass_prefix').$class.'.php');
 			}
@@ -243,7 +243,7 @@
 		}
 
 		// Is the config file in the environment folder?
-		if (defined('ENVIRONMENT') && file_exists($file_path = APPPATH.'config/'.ENVIRONMENT.'/config.php'))
+		if (file_exists($file_path = APPPATH.'config/'.ENVIRONMENT.'/config.php'))
 		{
 			require($file_path);
 		}
@@ -320,11 +320,11 @@
 	{
 		static $_mimes = array();
 
-		if (defined('ENVIRONMENT') && is_file(APPPATH.'config/'.ENVIRONMENT.'/mimes.php'))
+		if (file_exists(APPPATH.'config/'.ENVIRONMENT.'/mimes.php'))
 		{
 			$_mimes = include(APPPATH.'config/'.ENVIRONMENT.'/mimes.php');
 		}
-		elseif (is_file(APPPATH.'config/mimes.php'))
+		elseif (file_exists(APPPATH.'config/mimes.php'))
 		{
 			$_mimes = include(APPPATH.'config/mimes.php');
 		}
@@ -347,7 +347,7 @@
 	 */
 	function is_https()
 	{
-		return ( ! empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) !== 'off');
+		return (isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) === 'on');
 	}
 }
 
@@ -429,7 +429,7 @@
 	function log_message($level = 'error', $message, $php_error = FALSE)
 	{
 		static $_log, $_log_threshold;
-		
+
 		if ($_log_threshold === NULL)
 		{
 			$_log_threshold = config_item('log_threshold');
@@ -444,7 +444,7 @@
 		{
 			$_log =& load_class('Log', 'core');
 		}
-		
+
 		$_log->write_log($level, $message, $php_error);
 	}
 }
diff --git a/system/core/Config.php b/system/core/Config.php
index 0160d1a..7e64444 100644
--- a/system/core/Config.php
+++ b/system/core/Config.php
@@ -106,13 +106,9 @@
 		$file = ($file === '') ? 'config' : str_replace('.php', '', $file);
 		$found = $loaded = FALSE;
 
-		$check_locations = defined('ENVIRONMENT')
-			? array(ENVIRONMENT.'/'.$file, $file)
-			: array($file);
-
 		foreach ($this->_config_paths as $path)
 		{
-			foreach ($check_locations as $location)
+			foreach (array(ENVIRONMENT.'/'.$file, $file) as $location)
 			{
 				$file_path = $path.'config/'.$location.'.php';
 
diff --git a/system/core/Hooks.php b/system/core/Hooks.php
index 2cb416c..b3b1119 100644
--- a/system/core/Hooks.php
+++ b/system/core/Hooks.php
@@ -81,11 +81,12 @@
 		}
 
 		// Grab the "hooks" definition file.
-		if (defined('ENVIRONMENT') && is_file(APPPATH.'config/'.ENVIRONMENT.'/hooks.php'))
+		if (file_exists(APPPATH.'config/'.ENVIRONMENT.'/hooks.php'))
 		{
 			include(APPPATH.'config/'.ENVIRONMENT.'/hooks.php');
 		}
-		elseif (is_file(APPPATH.'config/hooks.php'))
+
+		if (file_exists(APPPATH.'config/hooks.php'))
 		{
 			include(APPPATH.'config/hooks.php');
 		}
@@ -194,7 +195,7 @@
 		// Call the requested class and/or function
 		if ($class !== FALSE)
 		{
-			if ( ! class_exists($class))
+			if ( ! class_exists($class, FALSE))
 			{
 				require($filepath);
 			}
diff --git a/system/core/Input.php b/system/core/Input.php
index 8f37e44..904f4d6 100644
--- a/system/core/Input.php
+++ b/system/core/Input.php
@@ -720,9 +720,9 @@
 		}
 
 		// Standardize newlines if needed
-		if ($this->_standardize_newlines === TRUE && strpos($str, "\r") !== FALSE)
+		if ($this->_standardize_newlines === TRUE)
 		{
-			return str_replace(array("\r\n", "\r", "\r\n\n"), PHP_EOL, $str);
+			return preg_replace('/(?:\r\n|[\r\n])/', PHP_EOL, $str);
 		}
 
 		return $str;
diff --git a/system/core/Loader.php b/system/core/Loader.php
index 1ad07f1..6e5b58b 100644
--- a/system/core/Loader.php
+++ b/system/core/Loader.php
@@ -97,13 +97,6 @@
 	protected $_ci_classes =	array();
 
 	/**
-	 * List of loaded files
-	 *
-	 * @var	array
-	 */
-	protected $_ci_loaded_files =	array();
-
-	/**
 	 * List of loaded models
 	 *
 	 * @var	array
@@ -277,7 +270,7 @@
 				continue;
 			}
 
-			if ($db_conn !== FALSE && ! class_exists('CI_DB'))
+			if ($db_conn !== FALSE && ! class_exists('CI_DB', FALSE))
 			{
 				if ($db_conn === TRUE)
 				{
@@ -287,7 +280,7 @@
 				$CI->load->database($db_conn, FALSE, TRUE);
 			}
 
-			if ( ! class_exists('CI_Model'))
+			if ( ! class_exists('CI_Model', FALSE))
 			{
 				load_class('Model', 'core');
 			}
@@ -943,7 +936,6 @@
 
 		// Was the path included with the class name?
 		// We look for a slash to determine this
-		$subdir = '';
 		if (($last_slash = strrpos($class, '/')) !== FALSE)
 		{
 			// Extract the path
@@ -952,108 +944,92 @@
 			// Get the filename from the path
 			$class = substr($class, $last_slash);
 		}
-
-		// We'll test for both lowercase and capitalized versions of the file name
-		foreach (array(ucfirst($class), strtolower($class)) as $class)
+		else
 		{
-			$subclass = APPPATH.'libraries/'.$subdir.config_item('subclass_prefix').$class.'.php';
+			$subdir = '';
+		}
 
-			// Is this a class extension request?
-			if (file_exists($subclass))
+		$class = ucfirst($class);
+		$subclass = APPPATH.'libraries/'.$subdir.config_item('subclass_prefix').$class.'.php';
+
+		// Is this a class extension request?
+		if (file_exists($subclass))
+		{
+			$baseclass = BASEPATH.'libraries/'.$class.'.php';
+
+			if ( ! file_exists($baseclass))
 			{
-				$baseclass = BASEPATH.'libraries/'.ucfirst($class).'.php';
-
-				if ( ! file_exists($baseclass))
-				{
-					log_message('error', 'Unable to load the requested class: '.$class);
-					show_error('Unable to load the requested class: '.$class);
-				}
-
-				// Safety: Was the class already loaded by a previous call?
-				if (in_array($subclass, $this->_ci_loaded_files))
-				{
-					// Before we deem this to be a duplicate request, let's see
-					// if a custom object name is being supplied. If so, we'll
-					// return a new instance of the object
-					if ($object_name !== NULL)
-					{
-						$CI =& get_instance();
-						if ( ! isset($CI->$object_name))
-						{
-							return $this->_ci_init_class($class, config_item('subclass_prefix'), $params, $object_name);
-						}
-					}
-
-					$is_duplicate = TRUE;
-					log_message('debug', $class.' class already loaded. Second attempt ignored.');
-					return;
-				}
-
-				include_once($baseclass);
-				include_once($subclass);
-				$this->_ci_loaded_files[] = $subclass;
-
-				return $this->_ci_init_class($class, config_item('subclass_prefix'), $params, $object_name);
+				log_message('error', 'Unable to load the requested class: '.$class);
+				show_error('Unable to load the requested class: '.$class);
 			}
 
-			// Lets search for the requested library file and load it.
-			$is_duplicate = FALSE;
-			foreach ($this->_ci_library_paths as $path)
+			// Safety: Was the class already loaded by a previous call?
+			if (class_exists(config_item('subclass_prefix').$class, FALSE))
 			{
-				$filepath = $path.'libraries/'.$subdir.$class.'.php';
-
-				// Does the file exist? No? Bummer...
-				if ( ! file_exists($filepath))
+				// Before we deem this to be a duplicate request, let's see
+				// if a custom object name is being supplied. If so, we'll
+				// return a new instance of the object
+				if ($object_name !== NULL)
 				{
-					continue;
-				}
-
-				// Safety: Was the class already loaded by a previous call?
-				if (in_array($filepath, $this->_ci_loaded_files))
-				{
-					// Before we deem this to be a duplicate request, let's see
-					// if a custom object name is being supplied. If so, we'll
-					// return a new instance of the object
-					if ($object_name !== NULL)
+					$CI =& get_instance();
+					if ( ! isset($CI->$object_name))
 					{
-						$CI =& get_instance();
-						if ( ! isset($CI->$object_name))
-						{
-							return $this->_ci_init_class($class, '', $params, $object_name);
-						}
+						return $this->_ci_init_class($class, config_item('subclass_prefix'), $params, $object_name);
 					}
-
-					$is_duplicate = TRUE;
-					log_message('debug', $class.' class already loaded. Second attempt ignored.');
-					return;
 				}
 
-				include_once($filepath);
-				$this->_ci_loaded_files[] = $filepath;
-				return $this->_ci_init_class($class, '', $params, $object_name);
+				log_message('debug', $class.' class already loaded. Second attempt ignored.');
+				return;
 			}
-		} // END FOREACH
+
+			include_once($baseclass);
+			include_once($subclass);
+
+			return $this->_ci_init_class($class, config_item('subclass_prefix'), $params, $object_name);
+		}
+
+		// Let's search for the requested library file and load it.
+		foreach ($this->_ci_library_paths as $path)
+		{
+			$filepath = $path.'libraries/'.$subdir.$class.'.php';
+
+			// Safety: Was the class already loaded by a previous call?
+			if (class_exists($class, FALSE))
+			{
+				// Before we deem this to be a duplicate request, let's see
+				// if a custom object name is being supplied. If so, we'll
+				// return a new instance of the object
+				if ($object_name !== NULL)
+				{
+					$CI =& get_instance();
+					if ( ! isset($CI->$object_name))
+					{
+						return $this->_ci_init_class($class, '', $params, $object_name);
+					}
+				}
+
+				log_message('debug', $class.' class already loaded. Second attempt ignored.');
+				return;
+			}
+			// Does the file exist? No? Bummer...
+			elseif ( ! file_exists($filepath))
+			{
+				continue;
+			}
+
+			include_once($filepath);
+			return $this->_ci_init_class($class, '', $params, $object_name);
+		}
 
 		// One last attempt. Maybe the library is in a subdirectory, but it wasn't specified?
 		if ($subdir === '')
 		{
-			$path = strtolower($class).'/'.$class;
-			return $this->_ci_load_class($path, $params, $object_name);
-		}
-		elseif (ucfirst($subdir) != $subdir)
-		{
-			// Lowercase subdir failed - retry capitalized
-			$path = ucfirst($subdir).$class;
-			return $this->_ci_load_class($path, $params, $object_name);
+			return $this->_ci_load_class($class.'/'.$class, $params, $object_name);
 		}
 
 		// If we got this far we were unable to find the requested class.
-		// We do not issue errors if the load call failed due to a duplicate request
-		if ($is_duplicate === FALSE)
-		{
-			log_message('error', 'Unable to load the requested class: '.$class);
-			show_error('Unable to load the requested class: '.$class);
-		}
+		log_message('error', 'Unable to load the requested class: '.$class);
+		show_error('Unable to load the requested class: '.$class);
 	}
 
 	// --------------------------------------------------------------------
@@ -1089,12 +1065,12 @@
 					// We test for both uppercase and lowercase, for servers that
 					// are case-sensitive with regard to file names. Check for environment
 					// first, global next
-					if (defined('ENVIRONMENT') && file_exists($path.'config/'.ENVIRONMENT.'/'.strtolower($class).'.php'))
+					if (file_exists($path.'config/'.ENVIRONMENT.'/'.strtolower($class).'.php'))
 					{
 						include($path.'config/'.ENVIRONMENT.'/'.strtolower($class).'.php');
 						break;
 					}
-					elseif (defined('ENVIRONMENT') && file_exists($path.'config/'.ENVIRONMENT.'/'.ucfirst(strtolower($class)).'.php'))
+					elseif (file_exists($path.'config/'.ENVIRONMENT.'/'.ucfirst(strtolower($class)).'.php'))
 					{
 						include($path.'config/'.ENVIRONMENT.'/'.ucfirst(strtolower($class)).'.php');
 						break;
@@ -1115,11 +1091,11 @@
 
 		if ($prefix === '')
 		{
-			if (class_exists('CI_'.$class))
+			if (class_exists('CI_'.$class, FALSE))
 			{
 				$name = 'CI_'.$class;
 			}
-			elseif (class_exists(config_item('subclass_prefix').$class))
+			elseif (class_exists(config_item('subclass_prefix').$class, FALSE))
 			{
 				$name = config_item('subclass_prefix').$class;
 			}
@@ -1134,7 +1110,7 @@
 		}
 
 		// Is the class name valid?
-		if ( ! class_exists($name))
+		if ( ! class_exists($name, FALSE))
 		{
 			log_message('error', 'Non-existent class: '.$name);
 			show_error('Non-existent class: '.$name);
@@ -1180,7 +1156,7 @@
 	 */
 	protected function _ci_autoloader()
 	{
-		if (defined('ENVIRONMENT') && file_exists(APPPATH.'config/'.ENVIRONMENT.'/autoload.php'))
+		if (file_exists(APPPATH.'config/'.ENVIRONMENT.'/autoload.php'))
 		{
 			include(APPPATH.'config/'.ENVIRONMENT.'/autoload.php');
 		}
diff --git a/system/core/Log.php b/system/core/Log.php
index cd3c17e..a84d3dc 100644
--- a/system/core/Log.php
+++ b/system/core/Log.php
@@ -73,6 +73,13 @@
 	protected $_date_fmt		= 'Y-m-d H:i:s';
 
 	/**
+	 * Filename extension
+	 *
+	 * @var	string
+	 */
+	protected $_file_ext;
+
+	/**
 	 * Whether or not the logger can write to the log files
 	 *
 	 * @var bool
@@ -86,8 +93,10 @@
 	 */
 	protected $_levels		= array('ERROR' => 1, 'DEBUG' => 2, 'INFO' => 3, 'ALL' => 4);
 
+	// --------------------------------------------------------------------
+
 	/**
-	 * Initialize Logging class
+	 * Class constructor
 	 *
 	 * @return	void
 	 */
@@ -96,6 +105,8 @@
 		$config =& get_config();
 
 		$this->_log_path = ($config['log_path'] !== '') ? $config['log_path'] : APPPATH.'logs/';
+		$this->_file_ext = (isset($config['log_file_extension']) && $config['log_file_extension'] !== '')
+			? ltrim($config['log_file_extension'], '.') : 'php';
 
 		file_exists($this->_log_path) OR mkdir($this->_log_path, DIR_WRITE_MODE, TRUE);
 
@@ -147,13 +158,17 @@
 			return FALSE;
 		}
 
-		$filepath = $this->_log_path.'log-'.date('Y-m-d').'.php';
-		$message  = '';
+		$filepath = $this->_log_path.'log-'.date('Y-m-d').'.'.$this->_file_ext;
+		$message = '';
 
 		if ( ! file_exists($filepath))
 		{
 			$newfile = TRUE;
-			$message .= '<'."?php defined('BASEPATH') OR exit('No direct script access allowed'); ?".">\n\n";
+			// Only add protection to php files
+			if ($this->_file_ext === 'php')
+			{
+				$message .= "<?php defined('BASEPATH') OR exit('No direct script access allowed'); ?>\n\n";
+			}
 		}
 
 		if ( ! $fp = @fopen($filepath, FOPEN_WRITE_CREATE))
@@ -179,4 +194,4 @@
 }
 
 /* End of file Log.php */
-/* Location: ./system/libraries/Log.php */
\ No newline at end of file
+/* Location: ./system/core/Log.php */
\ No newline at end of file
diff --git a/system/core/Output.php b/system/core/Output.php
index 7898d19..d4abe87 100644
--- a/system/core/Output.php
+++ b/system/core/Output.php
@@ -395,7 +395,7 @@
 		global $BM, $CFG;
 
 		// Grab the super object if we can.
-		if (class_exists('CI_Controller'))
+		if (class_exists('CI_Controller', FALSE))
 		{
 			$CI =& get_instance();
 		}
diff --git a/system/core/Router.php b/system/core/Router.php
index f284e29..bb0ce16 100644
--- a/system/core/Router.php
+++ b/system/core/Router.php
@@ -133,15 +133,16 @@
 		}
 
 		// Load the routes.php file.
-		if (defined('ENVIRONMENT') && is_file(APPPATH.'config/'.ENVIRONMENT.'/routes.php'))
-		{
-			include(APPPATH.'config/'.ENVIRONMENT.'/routes.php');
-		}
-		elseif (is_file(APPPATH.'config/routes.php'))
+		if (file_exists(APPPATH.'config/routes.php'))
 		{
 			include(APPPATH.'config/routes.php');
 		}
 
+		if (file_exists(APPPATH.'config/'.ENVIRONMENT.'/routes.php'))
+		{
+			include(APPPATH.'config/'.ENVIRONMENT.'/routes.php');
+		}
+
 		$this->routes = (empty($route) OR ! is_array($route)) ? array() : $route;
 		unset($route);
 
diff --git a/system/core/Security.php b/system/core/Security.php
index a6cd14a..7aae54e 100644
--- a/system/core/Security.php
+++ b/system/core/Security.php
@@ -576,7 +576,15 @@
 		}
 
 		$str = remove_invisible_characters($str, FALSE);
-		return stripslashes(str_replace($bad, '', $str));
+
+		do
+		{
+			$old = $str;
+			$str = str_replace($bad, '', $str);
+		}
+		while ($old !== $str);
+
+		return stripslashes($str);
 	}
 
 	// ----------------------------------------------------------------
diff --git a/system/core/URI.php b/system/core/URI.php
index 9b31a64..b2286f0 100644
--- a/system/core/URI.php
+++ b/system/core/URI.php
@@ -126,7 +126,7 @@
 				return;
 			}
 
-			// As a last ditch effort lets try using the $_GET array
+			// As a last ditch effort let's try using the $_GET array
 			if (is_array($_GET) && count($_GET) === 1 && trim(key($_GET), '/') !== '')
 			{
 				$this->_set_uri_string(key($_GET));
diff --git a/system/database/DB.php b/system/database/DB.php
index f94685c..83d9733 100644
--- a/system/database/DB.php
+++ b/system/database/DB.php
@@ -43,7 +43,7 @@
 	if (is_string($params) && strpos($params, '://') === FALSE)
 	{
 		// Is the config file in the environment folder?
-		if (( ! defined('ENVIRONMENT') OR ! file_exists($file_path = APPPATH.'config/'.ENVIRONMENT.'/database.php'))
+		if ( ! file_exists($file_path = APPPATH.'config/'.ENVIRONMENT.'/database.php')
 			&& ! file_exists($file_path = APPPATH.'config/database.php'))
 		{
 			show_error('The configuration file database.php does not exist.');
@@ -149,7 +149,7 @@
 	if ( ! isset($query_builder) OR $query_builder === TRUE)
 	{
 		require_once(BASEPATH.'database/DB_query_builder.php');
-		if ( ! class_exists('CI_DB'))
+		if ( ! class_exists('CI_DB', FALSE))
 		{
 			/**
 			 * CI_DB
@@ -162,7 +162,7 @@
 			class CI_DB extends CI_DB_query_builder { }
 		}
 	}
-	elseif ( ! class_exists('CI_DB'))
+	elseif ( ! class_exists('CI_DB', FALSE))
 	{
 		/**
 	 	 * @ignore
diff --git a/system/database/DB_driver.php b/system/database/DB_driver.php
index cb2ef4a..6ae1d52 100644
--- a/system/database/DB_driver.php
+++ b/system/database/DB_driver.php
@@ -625,7 +625,7 @@
 				// if transactions are enabled. If we don't call this here
 				// the error message will trigger an exit, causing the
 				// transactions to remain in limbo.
-				$this->trans_complete();
+				$this->_trans_depth > 0 && $this->trans_complete();
 
 				// Display errors
 				return $this->display_error(array('Error Number: '.$error['code'], $error['message'], $sql));
@@ -1560,7 +1560,7 @@
 	 */
 	protected function _cache_init()
 	{
-		if (class_exists('CI_DB_Cache'))
+		if (class_exists('CI_DB_Cache', FALSE))
 		{
 			if (is_object($this->CACHE))
 			{
diff --git a/system/database/DB_query_builder.php b/system/database/DB_query_builder.php
index ac377d9..85a233b 100644
--- a/system/database/DB_query_builder.php
+++ b/system/database/DB_query_builder.php
@@ -937,7 +937,7 @@
 			$this->qb_where[] = array('condition' => $like_statement, 'escape' => $escape);
 			if ($this->qb_caching === TRUE)
 			{
-				$this->qb_cache_where[] = $like_statement;
+				$this->qb_cache_where[] = array('condition' => $like_statement, 'escape' => $escape);
 				$this->qb_cache_exists[] = 'where';
 			}
 		}
@@ -2627,6 +2627,7 @@
 		$this->_reset_run(array(
 			'qb_set'	=> array(),
 			'qb_from'	=> array(),
+			'qb_join'	=> array(),
 			'qb_where'	=> array(),
 			'qb_orderby'	=> array(),
 			'qb_keys'	=> array(),
diff --git a/system/database/drivers/mssql/mssql_result.php b/system/database/drivers/mssql/mssql_result.php
index ea3f8e4..b6e5f2b 100644
--- a/system/database/drivers/mssql/mssql_result.php
+++ b/system/database/drivers/mssql/mssql_result.php
@@ -74,6 +74,7 @@
 	public function list_fields()
 	{
 		$field_names = array();
+		mssql_field_seek($this->result_id, 0);
 		while ($field = mssql_fetch_field($this->result_id))
 		{
 			$field_names[] = $field->name;
diff --git a/system/database/drivers/mysql/mysql_result.php b/system/database/drivers/mysql/mysql_result.php
index 1ed2759..a2affcb 100644
--- a/system/database/drivers/mysql/mysql_result.php
+++ b/system/database/drivers/mysql/mysql_result.php
@@ -89,6 +89,7 @@
 	public function list_fields()
 	{
 		$field_names = array();
+		mysql_field_seek($this->result_id, 0);
 		while ($field = mysql_fetch_field($this->result_id))
 		{
 			$field_names[] = $field->name;
diff --git a/system/database/drivers/mysqli/mysqli_result.php b/system/database/drivers/mysqli/mysqli_result.php
index 4105f99..3fe05f9 100644
--- a/system/database/drivers/mysqli/mysqli_result.php
+++ b/system/database/drivers/mysqli/mysqli_result.php
@@ -74,6 +74,7 @@
 	public function list_fields()
 	{
 		$field_names = array();
+		$this->result_id->field_seek(0);
 		while ($field = $this->result_id->fetch_field())
 		{
 			$field_names[] = $field->name;
diff --git a/system/database/drivers/pdo/pdo_driver.php b/system/database/drivers/pdo/pdo_driver.php
index 34adf0f..fa89661 100644
--- a/system/database/drivers/pdo/pdo_driver.php
+++ b/system/database/drivers/pdo/pdo_driver.php
@@ -49,13 +49,6 @@
 	public $dbdriver = 'pdo';
 
 	/**
-	 * Transaction enabled flag
-	 *
-	 * @var	bool
-	 */
-	public $trans_enabled = FALSE;
-
-	/**
 	 * PDO Options
 	 *
 	 * @var	array
diff --git a/system/helpers/captcha_helper.php b/system/helpers/captcha_helper.php
index 8378332..78e255a 100644
--- a/system/helpers/captcha_helper.php
+++ b/system/helpers/captcha_helper.php
@@ -93,7 +93,7 @@
 		// Do we have a "word" yet?
 		// -----------------------------------
 
-		if ($word === '')
+		if (empty($word))
 		{
 			$pool = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
 			$word = '';
@@ -102,6 +102,10 @@
 				$word .= $pool[mt_rand(0, $mt_rand_max)];
 			}
 		}
+		elseif ( ! is_string($word))
+		{
+			$word = (string) $word;
+		}
 
 		// -----------------------------------
 		// Determine angle and position
diff --git a/system/helpers/download_helper.php b/system/helpers/download_helper.php
index d7691cb..daf59f5 100644
--- a/system/helpers/download_helper.php
+++ b/system/helpers/download_helper.php
@@ -58,7 +58,7 @@
 		}
 		elseif ($data === NULL)
 		{
-			if (@is_file($filename) && @file_exists($filename) && ($filesize = @filesize($filename)) !== FALSE)
+			if (@is_file($filename) && ($filesize = @filesize($filename)) !== FALSE)
 			{
 				$filepath = $filename;
 				$filename = explode('/', str_replace(DIRECTORY_SEPARATOR, '/', $filename));
diff --git a/system/helpers/form_helper.php b/system/helpers/form_helper.php
index f343b6c..692909c 100644
--- a/system/helpers/form_helper.php
+++ b/system/helpers/form_helper.php
@@ -228,13 +228,10 @@
 	 */
 	function form_upload($data = '', $value = '', $extra = '')
 	{
-		if ( ! is_array($data))
-		{
-			$data = array('name' => $data);
-		}
-
+		$defaults = array('type' => 'file', 'name' => '');
+		is_array($data) OR $data = array('name' => $data);
 		$data['type'] = 'file';
-		return form_input($data, $value, $extra);
+		return '<input '._parse_form_attributes($data, $defaults).$extra." />\n";
 	}
 }
 
diff --git a/system/helpers/html_helper.php b/system/helpers/html_helper.php
index 2d47416..80a2787 100644
--- a/system/helpers/html_helper.php
+++ b/system/helpers/html_helper.php
@@ -238,26 +238,30 @@
 	 */
 	function doctype($type = 'xhtml1-strict')
 	{
-		global $_doctypes;
+		static $doctypes;
 
-		if ( ! is_array($_doctypes))
+		if ( ! is_array($doctypes))
 		{
-			if (defined('ENVIRONMENT') && is_file(APPPATH.'config/'.ENVIRONMENT.'/doctypes.php'))
-			{
-				include(APPPATH.'config/'.ENVIRONMENT.'/doctypes.php');
-			}
-			elseif (is_file(APPPATH.'config/doctypes.php'))
+			if (file_exists(APPPATH.'config/doctypes.php'))
 			{
 				include(APPPATH.'config/doctypes.php');
 			}
 
-			if ( ! is_array($_doctypes))
+			if (file_exists(APPPATH.'config/'.ENVIRONMENT.'/doctypes.php'))
 			{
+				include(APPPATH.'config/'.ENVIRONMENT.'/doctypes.php');
+			}
+
+			if (empty($_doctypes) OR ! is_array($_doctypes))
+			{
+				$doctypes = array();
 				return FALSE;
 			}
+
+			$doctypes = $_doctypes;
 		}
 
-		return isset($_doctypes[$type]) ? $_doctypes[$type] : FALSE;
+		return isset($doctypes[$type]) ? $doctypes[$type] : FALSE;
 	}
 }
 
diff --git a/system/helpers/smiley_helper.php b/system/helpers/smiley_helper.php
index 186b24c..d9a6934 100644
--- a/system/helpers/smiley_helper.php
+++ b/system/helpers/smiley_helper.php
@@ -213,16 +213,30 @@
 	 */
 	function _get_smiley_array()
 	{
-		if (defined('ENVIRONMENT') && file_exists(APPPATH.'config/'.ENVIRONMENT.'/smileys.php'))
+		static $_smileys;
+
+		if ( ! is_array($smileys))
 		{
-			include(APPPATH.'config/'.ENVIRONMENT.'/smileys.php');
-		}
-		elseif (file_exists(APPPATH.'config/smileys.php'))
-		{
-			include(APPPATH.'config/smileys.php');
+			if (file_exists(APPPATH.'config/smileys.php'))
+			{
+				include(APPPATH.'config/smileys.php');
+			}
+
+			if (file_exists(APPPATH.'config/'.ENVIRONMENT.'/smileys.php'))
+			{
+				include(APPPATH.'config/'.ENVIRONMENT.'/smileys.php');
+			}
+
+			if (empty($smileys) OR ! is_array($smileys))
+			{
+				$_smileys = array();
+				return FALSE;
+			}
+
+			$_smileys = $smileys;
 		}
 
-		return (isset($smileys) && is_array($smileys)) ? $smileys : FALSE;
+		return $_smileys;
 	}
 }
 
diff --git a/system/helpers/text_helper.php b/system/helpers/text_helper.php
index 1c7eeaf..54db14f 100644
--- a/system/helpers/text_helper.php
+++ b/system/helpers/text_helper.php
@@ -358,31 +358,35 @@
 	/**
 	 * Convert Accented Foreign Characters to ASCII
 	 *
-	 * @param	string	the text string
+	 * @param	string	$str	Input string
 	 * @return	string
 	 */
 	function convert_accented_characters($str)
 	{
-		global $foreign_characters;
+		static $_foreign_characters;
 
-		if ( ! isset($foreign_characters) OR ! is_array($foreign_characters))
+		if ( ! is_array($_foreign_characters))
 		{
-			if (defined('ENVIRONMENT') && is_file(APPPATH.'config/'.ENVIRONMENT.'/foreign_chars.php'))
-			{
-				include(APPPATH.'config/'.ENVIRONMENT.'/foreign_chars.php');
-			}
-			elseif (is_file(APPPATH.'config/foreign_chars.php'))
+			if (file_exists(APPPATH.'config/foreign_chars.php'))
 			{
 				include(APPPATH.'config/foreign_chars.php');
 			}
 
-			if ( ! isset($foreign_characters) OR ! is_array($foreign_characters))
+			if (file_exists(APPPATH.'config/'.ENVIRONMENT.'/foreign_chars.php'))
 			{
+				include(APPPATH.'config/'.ENVIRONMENT.'/foreign_chars.php');
+			}
+
+			if (empty($foreign_characters) OR ! is_array($foreign_characters))
+			{
+				$_foreign_characters = array();
 				return $str;
 			}
+
+			$_foreign_characters = $foreign_characters;
 		}
 
-		return preg_replace(array_keys($foreign_characters), array_values($foreign_characters), $str);
+		return preg_replace(array_keys($_foreign_characters), array_values($_foreign_characters), $str);
 	}
 }
 
diff --git a/system/helpers/url_helper.php b/system/helpers/url_helper.php
index 9a01535..d6bf7e2 100644
--- a/system/helpers/url_helper.php
+++ b/system/helpers/url_helper.php
@@ -384,22 +384,23 @@
 	function auto_link($str, $type = 'both', $popup = FALSE)
 	{
 		// Find and replace any URLs.
-		if ($type !== 'email' && preg_match_all('#\b(([\w-]+://?|www\.)[^\s()<>]+(?:\([\w\d]+\)|([^[:punct:]\s]|/)))#', $str, $matches, PREG_OFFSET_CAPTURE))
+		if ($type !== 'email' && preg_match_all('#(\w*://|www\.)[^\s()<>;]+\w#i', $str, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER))
 		{
 			// Set our target HTML if using popup links.
-			$target = ($popup) ? 'target="_blank"' : '';
+			$target = ($popup) ? ' target="_blank"' : '';
 
 			// We process the links in reverse order (last -> first) so that
 			// the returned string offsets from preg_match_all() are not
 			// moved as we add more HTML.
-			foreach (array_reverse($matches[0]) as $match)
+			foreach (array_reverse($matches) as $match)
 			{
-				// $match is an array generated by the PREG_OFFSET_CAPTURE flag.
-				// $match[0] is the matched string, $match[1] is the string offset.
-
-				$anchor = anchor($match[0], '', $target);
-
-				$str = substr_replace($str, $anchor, $match[1], strlen($match[0]));
+				// $match[0] is the matched string/link
+				// $match[1] is either a protocol prefix or 'www.'
+				//
+				// With PREG_OFFSET_CAPTURE, both of the above is an array,
+				// where the actual value is held in [0] and its offset at the [1] index.
+				$a = '<a href="'.(strpos($match[1][0], '/') ? '' : 'http://').$match[0][0].'"'.$target.'>'.$match[0][0].'</a>';
+				$str = substr_replace($str, $a, $match[0][1], strlen($match[0][0]));
 			}
 		}
 
diff --git a/system/language/english/form_validation_lang.php b/system/language/english/form_validation_lang.php
index 3fb007d..7c0277c 100644
--- a/system/language/english/form_validation_lang.php
+++ b/system/language/english/form_validation_lang.php
@@ -37,6 +37,7 @@
 $lang['form_validation_exact_length']		= 'The {field} field must be exactly {param} characters in length.';
 $lang['form_validation_alpha']			= 'The {field} field may only contain alphabetical characters.';
 $lang['form_validation_alpha_numeric']		= 'The {field} field may only contain alpha-numeric characters.';
+$lang['form_validation_alpha_numeric_spaces']	= 'The {field} field may only contain alpha-numeric characters and spaces.';
 $lang['form_validation_alpha_dash']		= 'The {field} field may only contain alpha-numeric characters, underscores, and dashes.';
 $lang['form_validation_numeric']		= 'The {field} field must contain only numbers.';
 $lang['form_validation_is_numeric']		= 'The {field} field must contain only numeric characters.';
diff --git a/system/language/english/profiler_lang.php b/system/language/english/profiler_lang.php
index dfe034e..0ed5f4c 100644
--- a/system/language/english/profiler_lang.php
+++ b/system/language/english/profiler_lang.php
@@ -46,6 +46,7 @@
 $lang['profiler_no_profiles']	= 'No Profile data - all Profiler sections have been disabled.';
 $lang['profiler_section_hide']	= 'Hide';
 $lang['profiler_section_show']	= 'Show';
+$lang['profiler_seconds']		= 'seconds';
 
 /* End of file profiler_lang.php */
 /* Location: ./system/language/english/profiler_lang.php */
\ No newline at end of file
diff --git a/system/libraries/Cache/drivers/Cache_memcached.php b/system/libraries/Cache/drivers/Cache_memcached.php
index 8096b26..246a7a2 100644
--- a/system/libraries/Cache/drivers/Cache_memcached.php
+++ b/system/libraries/Cache/drivers/Cache_memcached.php
@@ -182,11 +182,11 @@
 			}
 		}
 
-		if (class_exists('Memcached'))
+		if (class_exists('Memcached', FALSE))
 		{
 			$this->_memcached = new Memcached();
 		}
-		elseif (class_exists('Memcache'))
+		elseif (class_exists('Memcache', FALSE))
 		{
 			$this->_memcached = new Memcache();
 		}
diff --git a/system/libraries/Cart.php b/system/libraries/Cart.php
index 8734d77..b7b0697 100644
--- a/system/libraries/Cart.php
+++ b/system/libraries/Cart.php
@@ -95,7 +95,7 @@
 		$config = is_array($params) ? $params : array();
 
 		// Load the Sessions class
-		$this->CI->load->library('session', $config);
+		$this->CI->load->driver('session', $config);
 
 		// Grab the shopping cart array from the session table
 		$this->_cart_contents = $this->CI->session->userdata('cart_contents');
@@ -365,7 +365,7 @@
 	 */
 	protected function _save_cart()
 	{
-		// Lets add up the individual prices and set the cart sub-total
+		// Let's add up the individual prices and set the cart sub-total
 		$this->_cart_contents['total_items'] = $this->_cart_contents['cart_total'] = 0;
 		foreach ($this->_cart_contents as $key => $val)
 		{
diff --git a/system/libraries/Driver.php b/system/libraries/Driver.php
index bb73189..ba15f81 100644
--- a/system/libraries/Driver.php
+++ b/system/libraries/Driver.php
@@ -80,8 +80,7 @@
 	public function load_driver($child)
 	{
 		// Get CodeIgniter instance and subclass prefix
-		$CI = get_instance();
-		$prefix = (string) $CI->config->item('subclass_prefix');
+		$prefix = config_item('subclass_prefix');
 
 		if ( ! isset($this->lib_name))
 		{
@@ -102,11 +101,12 @@
 		}
 
 		// Get package paths and filename case variations to search
+		$CI = get_instance();
 		$paths = $CI->load->get_package_paths(TRUE);
 
 		// Is there an extension?
 		$class_name = $prefix.$child_name;
-		$found = class_exists($class_name);
+		$found = class_exists($class_name, FALSE);
 		if ( ! $found)
 		{
 			// Check for subclass file
@@ -126,8 +126,8 @@
 					}
 
 					// Include both sources and mark found
-					include($basepath);
-					include($file);
+					include_once($basepath);
+					include_once($file);
 					$found = TRUE;
 					break;
 				}
@@ -139,8 +139,7 @@
 		{
 			// Use standard class name
 			$class_name = 'CI_'.$child_name;
-			$found = class_exists($class_name);
-			if ( ! $found)
+			if ( ! class_exists($class_name, FALSE))
 			{
 				// Check package paths
 				foreach ($paths as $path)
@@ -150,7 +149,7 @@
 					if (file_exists($file))
 					{
 						// Include source
-						include($file);
+						include_once($file);
 						break;
 					}
 				}
@@ -158,9 +157,9 @@
 		}
 
 		// Did we finally find the class?
-		if ( ! class_exists($class_name))
+		if ( ! class_exists($class_name, FALSE))
 		{
-			if (class_exists($child_name))
+			if (class_exists($child_name, FALSE))
 			{
 				$class_name = $child_name;
 			}
diff --git a/system/libraries/Email.php b/system/libraries/Email.php
index 997757b..daa3848 100644
--- a/system/libraries/Email.php
+++ b/system/libraries/Email.php
@@ -96,6 +96,13 @@
 	public $smtp_timeout	= 5;
 
 	/**
+	 * SMTP persistent connection
+	 *
+	 * @var	bool
+	 */
+	public $smtp_keepalive	= FALSE;
+
+	/**
 	 * SMTP Encryption
 	 *
 	 * @var	string	NULL, 'tls' or 'ssl'
@@ -403,6 +410,21 @@
 	// --------------------------------------------------------------------
 
 	/**
+	 * Destructor - Releases Resources
+	 *
+	 * @return	void
+	 */
+	public function __destruct()
+	{
+		if (is_resource($this->_smtp_connect))
+		{
+			$this->_send_command('quit');
+		}
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
 	 * Initialize preferences
 	 *
 	 * @param	array
@@ -1183,8 +1205,11 @@
 	{
 		if ($this->protocol === 'mail')
 		{
-			$this->_subject = $this->_headers['Subject'];
-			unset($this->_headers['Subject']);
+			if (isset($this->_headers['Subject']))
+			{
+				$this->_subject = $this->_headers['Subject'];
+				unset($this->_headers['Subject']);
+			}
 		}
 
 		reset($this->_headers);
@@ -1824,7 +1849,15 @@
 			return FALSE;
 		}
 
-		$this->_send_command('quit');
+		if ($this->smtp_keepalive)
+		{
+			$this->_send_command('reset');
+		}
+		else
+		{
+			$this->_send_command('quit');
+		}
+
 		return TRUE;
 	}
 
@@ -1837,6 +1870,11 @@
 	 */
 	protected function _smtp_connect()
 	{
+		if (is_resource($this->_smtp_connect))
+		{
+			return TRUE;
+		}
+
 		$ssl = ($this->smtp_crypto === 'ssl') ? 'ssl://' : NULL;
 
 		$this->_smtp_connect = fsockopen($ssl.$this->smtp_host,
@@ -1851,6 +1889,7 @@
 			return FALSE;
 		}
 
+		stream_set_timeout($this->_smtp_connect, $this->smtp_timeout);
 		$this->_set_error_message($this->_get_smtp_data());
 
 		if ($this->smtp_crypto === 'tls')
@@ -1924,6 +1963,11 @@
 						$this->_send_data('DATA');
 						$resp = 354;
 			break;
+			case 'reset':
+
+						$this->_send_data('RSET');
+						$resp = 250;
+			break;
 			case 'quit'	:
 
 						$this->_send_data('QUIT');
@@ -1973,6 +2017,11 @@
 
 		$reply = $this->_get_smtp_data();
 
+		if (strpos($reply, '503') !== 0)	// Already authenticated
+		{
+			return TRUE;
+		}
+
 		if (strpos($reply, '334') !== 0)
 		{
 			$this->_set_error_message('lang:email_failed_smtp_login', $reply);
diff --git a/system/libraries/Form_validation.php b/system/libraries/Form_validation.php
index bbd0b52..172e799 100644
--- a/system/libraries/Form_validation.php
+++ b/system/libraries/Form_validation.php
@@ -356,7 +356,7 @@
 	 */
 	public function error_string($prefix = '', $suffix = '')
 	{
-		// No errrors, validation passes!
+		// No errors, validation passes!
 		if (count($this->_error_array) === 0)
 		{
 			return '';
@@ -517,7 +517,7 @@
 				{
 					if (isset($_POST[$row['field']]))
 					{
-						$_POST[$row['field']] = $this->prep_for_form($row['postdata']);
+						$_POST[$row['field']] = $row['postdata'];
 					}
 				}
 				else
@@ -543,14 +543,14 @@
 						$array = array();
 						foreach ($row['postdata'] as $k => $v)
 						{
-							$array[$k] = $this->prep_for_form($v);
+							$array[$k] = $v;
 						}
 
 						$post_ref = $array;
 					}
 					else
 					{
-						$post_ref = $this->prep_for_form($row['postdata']);
+						$post_ref = $row['postdata'];
 					}
 				}
 			}
@@ -1232,6 +1232,19 @@
 	// --------------------------------------------------------------------
 
 	/**
+	 * Alpha-numeric w/ spaces
+	 *
+	 * @param	string
+	 * @return	bool
+	 */
+	public function alpha_numeric_spaces($str)
+	{
+		return (bool) preg_match('/^[A-Z0-9 ]+$/i', $str);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
 	 * Alpha-numeric with underscores and dashes
 	 *
 	 * @param	string
diff --git a/system/libraries/Image_lib.php b/system/libraries/Image_lib.php
index 6d54936..0cec43f 100644
--- a/system/libraries/Image_lib.php
+++ b/system/libraries/Image_lib.php
@@ -810,7 +810,7 @@
 		imagedestroy($dst_img);
 		imagedestroy($src_img);
 
-		// Set the file to 777
+		// Set the file to 666
 		@chmod($this->full_dst_path, FILE_WRITE_MODE);
 
 		return TRUE;
diff --git a/system/libraries/Javascript.php b/system/libraries/Javascript.php
index 7f1d855..773a583 100644
--- a/system/libraries/Javascript.php
+++ b/system/libraries/Javascript.php
@@ -69,7 +69,7 @@
 		$this->CI =& get_instance();
 
 		// load the requested js library
-		$this->CI->load->library('javascript/'.$js_library_driver, array('autoload' => $autoload));
+		$this->CI->load->library('Javascript/'.$js_library_driver, array('autoload' => $autoload));
 		// make js to refer to current library
 		$this->js =& $this->CI->$js_library_driver;
 
diff --git a/system/libraries/javascript/Jquery.php b/system/libraries/Javascript/Jquery.php
similarity index 100%
rename from system/libraries/javascript/Jquery.php
rename to system/libraries/Javascript/Jquery.php
diff --git a/system/libraries/javascript/index.html b/system/libraries/Javascript/index.html
similarity index 100%
rename from system/libraries/javascript/index.html
rename to system/libraries/Javascript/index.html
diff --git a/system/libraries/Migration.php b/system/libraries/Migration.php
index fd915c3..cc6fe48 100644
--- a/system/libraries/Migration.php
+++ b/system/libraries/Migration.php
@@ -104,8 +104,8 @@
 	 */
 	public function __construct($config = array())
 	{
-		# Only run this constructor on main library load
-		if (get_parent_class($this) !== FALSE)
+		// Only run this constructor on main library load
+		if ( ! in_array(get_class($this), array('CI_Migration', config_item('subclass_prefix').'Migration'), TRUE))
 		{
 			return;
 		}
@@ -228,7 +228,7 @@
 			$class = 'Migration_'.ucfirst(strtolower($this->_get_migration_name(basename($file, '.php'))));
 
 			// Validate the migration file structure
-			if ( ! class_exists($class))
+			if ( ! class_exists($class, FALSE))
 			{
 				$this->_error_string = sprintf($this->lang->line('migration_class_doesnt_exist'), $class);
 				return FALSE;
diff --git a/system/libraries/Pagination.php b/system/libraries/Pagination.php
index d139980..10fb29d 100644
--- a/system/libraries/Pagination.php
+++ b/system/libraries/Pagination.php
@@ -133,7 +133,7 @@
 	 *
 	 * @var	int
 	 */
-	protected $uri_segment		= 3;
+	protected $uri_segment		= 0;
 
 	/**
 	 * Full tag open
@@ -318,11 +318,9 @@
 	 */
 	public function initialize($params = array())
 	{
-		$attributes = array();
-
 		if (isset($params['attributes']) && is_array($params['attributes']))
 		{
-			$attributes = $params['attributes'];
+			$this->_parse_attributes($params['attributes']);
 			unset($params['attributes']);
 		}
 
@@ -334,8 +332,6 @@
 			unset($params['anchor_class']);
 		}
 
-		$this->_parse_attributes($attributes);
-
 		if (count($params) > 0)
 		{
 			foreach ($params as $key => $val)
@@ -372,36 +368,7 @@
 			return '';
 		}
 
-		// Set the base page index for starting page number
-		$base_page = ($this->use_page_numbers) ? 1 : 0;
-
-		// Determine the current page number.
-		$CI =& get_instance();
-
-		// See if we are using a prefix or suffix on links
-		if ($this->prefix !== '' OR $this->suffix !== '')
-		{
-			$this->cur_page = (int) str_replace(array($this->prefix, $this->suffix), '', $CI->uri->rsegment($this->uri_segment));
-		}
-
-		if ($CI->config->item('enable_query_strings') === TRUE OR $this->page_query_string === TRUE)
-		{
-			if ($CI->input->get($this->query_string_segment) != $base_page)
-			{
-				$this->cur_page = (int) $CI->input->get($this->query_string_segment);
-			}
-		}
-		elseif ( ! $this->cur_page && $CI->uri->segment($this->uri_segment) !== $base_page)
-		{
-			$this->cur_page = (int) $CI->uri->rsegment($this->uri_segment);
-		}
-
-		// Set current page to 1 if it's not valid or if using page numbers instead of offset
-		if ( ! is_numeric($this->cur_page) OR ($this->use_page_numbers && $this->cur_page === 0))
-		{
-			$this->cur_page = $base_page;
-		}
-
+		// Check the user defined number of links.
 		$this->num_links = (int) $this->num_links;
 
 		if ($this->num_links < 1)
@@ -409,8 +376,111 @@
 			show_error('Your number of links must be a positive number.');
 		}
 
+		$CI =& get_instance();
+
+		// Keep any existing query string items.
+		// Note: Has nothing to do with any other query string option.
+		if ($this->reuse_query_string === TRUE)
+		{
+			$get = $CI->input->get();
+
+			// Unset the controll, method, old-school routing options
+			unset($get['c'], $get['m'], $get[$this->query_string_segment]);
+		}
+		else
+		{
+			$get = array();
+		}
+
+		// Put together our base and first URLs.
+		$this->base_url = trim($this->base_url);
+
+		$query_string = '';
+		$query_string_sep = (strpos($this->base_url, '?') === FALSE) ? '?' : '&amp;';
+
+		// Are we using query strings?
+		if ($CI->config->item('enable_query_strings') === TRUE OR $this->page_query_string === TRUE)
+		{
+			// If a custom first_url hasn't been specified, we'll create one from
+			// the base_url, but without the page item.
+			if ($this->first_url === '')
+			{
+				$this->first_url = $this->base_url;
+
+				// If we saved any GET items earlier, make sure they're appended.
+				if ( ! empty($get))
+				{
+					$this->first_url .= $query_string_sep.http_build_query($get);
+				}
+			}
+
+			// Add the page segment to the end of the query string, where the
+			// page number will be appended.
+			$this->base_url .= $query_string_sep.http_build_query(array_merge($get, array($this->query_string_segment => '')));
+		}
+		else
+		{
+			// Standard segment mode.
+			// Generate our saved query string to append later after the page number.
+			if ( ! empty($get))
+			{
+				$query_string = $query_string_sep.http_build_query($get);
+				$this->suffix .= $query_string;
+			}
+
+			// Does the base_url have the query string in it?
+			// If we're supposed to save it, remove it so we can append it later.
+			if ($this->reuse_query_string === TRUE && ($base_query_pos = strpos($this->base_url, '?')) !== FALSE)
+			{
+				$this->base_url = substr($this->base_url, 0, $base_query_pos);
+			}
+
+			if ($this->first_url === '')
+			{
+				$this->first_url = $this->base_url.$query_string;
+			}
+
+			$this->base_url = rtrim($this->base_url, '/').'/';
+		}
+
+		// Determine the current page number.
+		$base_page = ($this->use_page_numbers) ? 1 : 0;
+
+		// Are we using query strings?
+		if ($CI->config->item('enable_query_strings') === TRUE OR $this->page_query_string === TRUE)
+		{
+			$this->cur_page = $CI->input->get($this->query_string_segment);
+		}
+		else
+		{
+			// Default to the last segment number if one hasn't been defined.
+			if ($this->uri_segment === 0)
+			{
+				$this->uri_segment = count($CI->uri->segment_array());
+			}
+
+			$this->cur_page = $CI->uri->segment($this->uri_segment);
+
+			// Remove any specified prefix/suffix from the segment.
+			if ($this->prefix !== '' OR $this->suffix !== '')
+			{
+				$this->cur_page = str_replace(array($this->prefix, $this->suffix), '', $this->cur_page);
+			}
+		}
+
+		// If something isn't quite right, back to the default base page.
+		if ( ! ctype_digit($this->cur_page) OR ($this->use_page_numbers && (int) $this->cur_page === 0))
+		{
+			$this->cur_page = $base_page;
+		}
+		else
+		{
+			// Make sure we're using integers for comparisons later.
+			$this->cur_page = (int) $this->cur_page;
+		}
+
 		// Is the page number beyond the result range?
-		// If so we show the last page
+		// If so, we show the last page.
 		if ($this->use_page_numbers)
 		{
 			if ($this->cur_page > $num_pages)
@@ -425,80 +495,47 @@
 
 		$uri_page_number = $this->cur_page;
 
+		// If we're using offset instead of page numbers, convert it
+		// to a page number, so we can generate the surrounding number links.
 		if ( ! $this->use_page_numbers)
 		{
 			$this->cur_page = (int) floor(($this->cur_page/$this->per_page) + 1);
 		}
 
 		// Calculate the start and end numbers. These determine
-		// which number to start and end the digit links with
+		// which number to start and end the digit links with.
 		$start	= (($this->cur_page - $this->num_links) > 0) ? $this->cur_page - ($this->num_links - 1) : 1;
 		$end	= (($this->cur_page + $this->num_links) < $num_pages) ? $this->cur_page + $this->num_links : $num_pages;
 
-		// Is pagination being used over GET or POST? If get, add a per_page query
-		// string. If post, add a trailing slash to the base URL if needed
-		if ($CI->config->item('enable_query_strings') === TRUE OR $this->page_query_string === TRUE)
-		{
-			$segment = (strpos($this->base_url, '?')) ? '&amp;' : '?';
-			$this->base_url = rtrim($this->base_url).$segment.$this->query_string_segment.'=';
-		}
-		else
-		{
-			$this->base_url = rtrim($this->base_url, '/') .'/';
-		}
-
 		// And here we go...
 		$output = '';
-		$query_string = '';
 
-		// Add anything in the query string back to the links
-		// Note: Nothing to do with query_string_segment or any other query string options
-		if ($this->reuse_query_string === TRUE)
-		{
-			$get = $CI->input->get();
-
-			// Unset the controll, method, old-school routing options
-			unset($get['c'], $get['m'], $get[$this->query_string_segment]);
-
-			if ( ! empty($get))
-			{
-				// Put everything else onto the end
-				$query_string = (strpos($this->base_url, '?') !== FALSE ? '&amp;' : '?')
-						.http_build_query($get, '', '&amp;');
-
-				// Add this after the suffix to put it into more links easily
-				$this->suffix .= $query_string;
-			}
-		}
-
-		// Render the "First" link
+		// Render the "First" link.
 		if ($this->first_link !== FALSE && $this->cur_page > ($this->num_links + 1))
 		{
-			$first_url = ($this->first_url === '') ? $this->base_url : $this->first_url;
-
-			// Take the general parameters, and squeeze this pagination-page attr in there for JS fw's
+			// Take the general parameters, and squeeze this pagination-page attr in for JS frameworks.
 			$attributes = sprintf('%s %s="%d"', $this->_attributes, $this->data_page_attr, 1);
 
-			$output .= $this->first_tag_open.'<a href="'.$first_url.'"'.$attributes.$this->_attr_rel('start').'>'
+			$output .= $this->first_tag_open.'<a href="'.$this->first_url.'"'.$attributes.$this->_attr_rel('start').'>'
 				.$this->first_link.'</a>'.$this->first_tag_close;
 		}
 
-		// Render the "previous" link
+		// Render the "Previous" link.
 		if ($this->prev_link !== FALSE && $this->cur_page !== 1)
 		{
 			$i = ($this->use_page_numbers) ? $uri_page_number - 1 : $uri_page_number - $this->per_page;
 
-			// Take the general parameters, and squeeze this pagination-page attr in there for JS fw's
 			$attributes = sprintf('%s %s="%d"', $this->_attributes, $this->data_page_attr, (int) $i);
 
-			if ($i === $base_page && $this->first_url !== '')
+			if ($i === $base_page)
 			{
-				$output .= $this->prev_tag_open.'<a href="'.$this->first_url.$query_string.'"'.$attributes.$this->_attr_rel('prev').'>'
+				// First page
+				$output .= $this->prev_tag_open.'<a href="'.$this->first_url.'"'.$attributes.$this->_attr_rel('prev').'>'
 					.$this->prev_link.'</a>'.$this->prev_tag_close;
 			}
 			else
 			{
-				$append = ($i === $base_page) ? $query_string : $this->prefix.$i.$this->suffix;
+				$append = $this->prefix.$i.$this->suffix;
 				$output .= $this->prev_tag_open.'<a href="'.$this->base_url.$append.'"'.$attributes.$this->_attr_rel('prev').'>'
 					.$this->prev_link.'</a>'.$this->prev_tag_close;
 			}
@@ -513,29 +550,26 @@
 			{
 				$i = ($this->use_page_numbers) ? $loop : ($loop * $this->per_page) - $this->per_page;
 
-				// Take the general parameters, and squeeze this pagination-page attr in there for JS fw's
 				$attributes = sprintf('%s %s="%d"', $this->_attributes, $this->data_page_attr, (int) $i);
 
 				if ($i >= $base_page)
 				{
 					if ($this->cur_page === $loop)
 					{
-						$output .= $this->cur_tag_open.$loop.$this->cur_tag_close; // Current page
+						// Current page
+						$output .= $this->cur_tag_open.$loop.$this->cur_tag_close;
+					}
+					elseif ($i === $base_page)
+					{
+						// First page
+						$output .= $this->num_tag_open.'<a href="'.$this->first_url.'"'.$attributes.$this->_attr_rel('start').'>'
+							.$loop.'</a>'.$this->num_tag_close;
 					}
 					else
 					{
-						$n = ($i === $base_page) ? '' : $i;
-						if ($n === '' && ! empty($this->first_url))
-						{
-							$output .= $this->num_tag_open.'<a href="'.$this->first_url.$query_string.'"'.$attributes.$this->_attr_rel('start').'>'
-								.$loop.'</a>'.$this->num_tag_close;
-						}
-						else
-						{
-							$append = ($n === '') ? $query_string : $this->prefix.$n.$this->suffix;
-							$output .= $this->num_tag_open.'<a href="'.$this->base_url.$append.'"'.$attributes.$this->_attr_rel('start').'>'
-								.$loop.'</a>'.$this->num_tag_close;
-						}
+						$append = $this->prefix.$i.$this->suffix;
+						$output .= $this->num_tag_open.'<a href="'.$this->base_url.$append.'"'.$attributes.$this->_attr_rel('start').'>'
+							.$loop.'</a>'.$this->num_tag_close;
 					}
 				}
 			}
@@ -546,7 +580,6 @@
 		{
 			$i = ($this->use_page_numbers) ? $this->cur_page + 1 : $this->cur_page * $this->per_page;
 
-			// Take the general parameters, and squeeze this pagination-page attr in there for JS fw's
 			$attributes = sprintf('%s %s="%d"', $this->_attributes, $this->data_page_attr, (int) $i);
 
 			$output .= $this->next_tag_open.'<a href="'.$this->base_url.$this->prefix.$i.$this->suffix.'"'.$attributes
@@ -558,7 +591,6 @@
 		{
 			$i = ($this->use_page_numbers) ? $num_pages : ($num_pages * $this->per_page) - $this->per_page;
 
-			// Take the general parameters, and squeeze this pagination-page attr in there for JS fw's
 			$attributes = sprintf('%s %s="%d"', $this->_attributes, $this->data_page_attr, (int) $i);
 
 			$output .= $this->last_tag_open.'<a href="'.$this->base_url.$this->prefix.$i.$this->suffix.'"'.$attributes.'>'
diff --git a/system/libraries/Profiler.php b/system/libraries/Profiler.php
index e932399..470688f 100644
--- a/system/libraries/Profiler.php
+++ b/system/libraries/Profiler.php
@@ -238,6 +238,7 @@
 		foreach ($dbs as $name => $db)
 		{
 			$hide_queries = (count($db->queries) > $this->_query_toggle_count) ? ' display:none' : '';
+			$total_time = number_format(array_sum($db->query_times), 4).' '.$this->CI->lang->line('profiler_seconds');
 
 			$show_hide_js = '(<span style="cursor: pointer;" onclick="var s=document.getElementById(\'ci_profiler_queries_db_'.$count.'\').style;s.display=s.display==\'none\'?\'\':\'none\';this.innerHTML=this.innerHTML==\''.$this->CI->lang->line('profiler_section_hide').'\'?\''.$this->CI->lang->line('profiler_section_show').'\':\''.$this->CI->lang->line('profiler_section_hide').'\';">'.$this->CI->lang->line('profiler_section_hide').'</span>)';
 
@@ -250,7 +251,7 @@
 				."\n"
 				.'<legend style="color:#0000FF;">&nbsp;&nbsp;'.$this->CI->lang->line('profiler_database')
 				.':&nbsp; '.$db->database.' ('.$name.')&nbsp;&nbsp;&nbsp;'.$this->CI->lang->line('profiler_queries')
-				.': '.count($db->queries).'&nbsp;&nbsp;'.$show_hide_js."</legend>\n\n\n"
+				.': '.count($db->queries).' ('.$total_time.')&nbsp;&nbsp;'.$show_hide_js."</legend>\n\n\n"
 				.'<table style="width:100%;'.$hide_queries.'" id="ci_profiler_queries_db_'.$count."\">\n";
 
 			if (count($db->queries) === 0)
diff --git a/system/libraries/Session/drivers/Session_cookie.php b/system/libraries/Session/drivers/Session_cookie.php
index 4746416..057e5a1 100644
--- a/system/libraries/Session/drivers/Session_cookie.php
+++ b/system/libraries/Session/drivers/Session_cookie.php
@@ -602,6 +602,9 @@
 				$set['user_data'] = $this->_serialize($userdata);
 			}
 
+			// Reset query builder values.
+			$this->CI->db->reset_query();
+
 			// Run the update query
 			// Any time we change the session id, it gets updated immediately,
 			// so our where clause below is always safe
@@ -805,7 +808,7 @@
 	{
 		if (is_string($val))
 		{
-	 		$val= str_replace('{{slash}}', '\\', $val);
+	 		$val = str_replace('{{slash}}', '\\', $val);
 		}
 	}
 
diff --git a/system/libraries/Upload.php b/system/libraries/Upload.php
index 96bb17e..1c14f99 100644
--- a/system/libraries/Upload.php
+++ b/system/libraries/Upload.php
@@ -430,7 +430,7 @@
 			}
 			else
 			{
-				// An extension was provided, lets have it!
+				// An extension was provided, let's have it!
 				$this->file_ext	= $this->get_extension($this->_file_name_override);
 			}
 
@@ -463,7 +463,8 @@
 		}
 
 		// Sanitize the file name for security
-		$this->file_name = $this->clean_file_name($this->file_name);
+		$CI =& get_instance();
+		$this->file_name = $CI->security->sanitize_filename($this->file_name);
 
 		// Truncate the file name if it's too long
 		if ($this->max_filename > 0)
@@ -971,46 +972,6 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 * Clean the file name for security
-	 *
-	 * @param	string	$filename
-	 * @return	string
-	 */
-	public function clean_file_name($filename)
-	{
-		$bad = array(
-				'<!--', '-->',
-				"'", '"',
-				'<', '>',
-				'&', '$',
-				'=',
-				';',
-				'?',
-				'/',
-				'!',
-				'#',
-				'%20',
-				'%22',
-				'%3c',		// <
-				'%253c',	// <
-				'%3e',		// >
-				'%0e',		// >
-				'%28',		// (
-				'%29',		// )
-				'%2528',	// (
-				'%26',		// &
-				'%24',		// $
-				'%3f',		// ?
-				'%3b',		// ;
-				'%3d'		// =
-			);
-
-		return stripslashes(str_replace($bad, '', $filename));
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
 	 * Limit the File Name Length
 	 *
 	 * @param	string	$filename
@@ -1089,7 +1050,7 @@
 			// <a, <body, <head, <html, <img, <plaintext, <pre, <script, <table, <title
 			// title is basically just in SVG, but we filter it anyhow
 
-			// if its an image or no "triggers" detected in the first 256 bytes - we're good
+			// if it's 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);
 		}
 
@@ -1251,7 +1212,7 @@
 		 * Notes:
 		 *	- the DIRECTORY_SEPARATOR comparison ensures that we're not on a Windows system
 		 *	- many system admins would disable the exec(), shell_exec(), popen() and similar functions
-		 *	  due to security concerns, hence the function_exists() checks
+		 *	  due to security concerns, hence the function_usable() checks
 		 */
 		if (DIRECTORY_SEPARATOR !== '\\')
 		{
@@ -1262,7 +1223,7 @@
 			if (function_usable('exec'))
 			{
 				/* This might look confusing, as $mime is being populated with all of the output when set in the second parameter.
-				 * However, we only neeed the last line, which is the actual return value of exec(), and as such - it overwrites
+				 * However, we only need the last line, which is the actual return value of exec(), and as such - it overwrites
 				 * anything that could already be set for $mime previously. This effectively makes the second parameter a dummy
 				 * value, which is only put to allow us to get the return status code.
 				 */
diff --git a/system/libraries/User_agent.php b/system/libraries/User_agent.php
index 1f4b2fa..2f6f819 100644
--- a/system/libraries/User_agent.php
+++ b/system/libraries/User_agent.php
@@ -175,15 +175,18 @@
 	 */
 	protected function _load_agent_file()
 	{
-		if (defined('ENVIRONMENT') && is_file(APPPATH.'config/'.ENVIRONMENT.'/user_agents.php'))
-		{
-			include(APPPATH.'config/'.ENVIRONMENT.'/user_agents.php');
-		}
-		elseif (is_file(APPPATH.'config/user_agents.php'))
+		if (($found = file_exists(APPPATH.'config/user_agents.php')))
 		{
 			include(APPPATH.'config/user_agents.php');
 		}
-		else
+
+		if (file_exists(APPPATH.'config/'.ENVIRONMENT.'/user_agents.php'))
+		{
+			include(APPPATH.'config/'.ENVIRONMENT.'/user_agents.php');
+			$found = TRUE;
+		}
+
+		if ($found !== TRUE)
 		{
 			return FALSE;
 		}
diff --git a/system/libraries/Xmlrpcs.php b/system/libraries/Xmlrpcs.php
index 465a196..2d2e7f1 100644
--- a/system/libraries/Xmlrpcs.php
+++ b/system/libraries/Xmlrpcs.php
@@ -31,7 +31,7 @@
 	show_error('Your PHP installation does not support XML');
 }
 
-if ( ! class_exists('CI_Xmlrpc'))
+if ( ! class_exists('CI_Xmlrpc', FALSE))
 {
 	show_error('You must load the Xmlrpc class before loading the Xmlrpcs class in order to create a server.');
 }
diff --git a/tests/Bootstrap.php b/tests/Bootstrap.php
index 8ce80b3..c98d885 100644
--- a/tests/Bootstrap.php
+++ b/tests/Bootstrap.php
@@ -32,6 +32,7 @@
 defined('BASEPATH') OR define('BASEPATH', vfsStream::url('system/'));
 defined('APPPATH') OR define('APPPATH', vfsStream::url('application/'));
 defined('VIEWPATH') OR define('VIEWPATH', APPPATH.'views/');
+defined('ENVIRONMENT') OR define('ENVIRONMENT', 'development');
 
 // Set localhost "remote" IP
 isset($_SERVER['REMOTE_ADDR']) OR $_SERVER['REMOTE_ADDR'] = '127.0.0.1';
diff --git a/tests/codeigniter/core/Input_test.php b/tests/codeigniter/core/Input_test.php
index ca1c6df..5cf25fe 100644
--- a/tests/codeigniter/core/Input_test.php
+++ b/tests/codeigniter/core/Input_test.php
@@ -95,8 +95,8 @@
 	public function test_cookie()
 	{
 		$_COOKIE['foo'] = 'bar';
-
 		$this->assertEquals('bar', $this->input->cookie('foo'));
+		$this->assertNull($this->input->cookie('bar'));
 	}
 
 	// --------------------------------------------------------------------
@@ -138,4 +138,27 @@
 		}
 	}
 
+	// --------------------------------------------------------------------
+
+	public function test_method()
+	{
+		$_SERVER['REQUEST_METHOD'] = 'GET';
+		$this->assertEquals('get', $this->input->method());
+		$this->assertEquals('GET', $this->input->method(TRUE));
+		$_SERVER['REQUEST_METHOD'] = 'POST';
+		$this->assertEquals('post', $this->input->method());
+		$this->assertEquals('POST', $this->input->method(TRUE));
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_is_ajax_request()
+	{
+		$this->assertFalse($this->input->is_ajax_request());
+		$_SERVER['HTTP_X_REQUESTED_WITH'] = 'test';
+		$this->assertFalse($this->input->is_ajax_request());
+		$_SERVER['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest';
+		$this->assertTrue($this->input->is_ajax_request());
+	}
+
 }
\ No newline at end of file
diff --git a/tests/codeigniter/core/Loader_test.php b/tests/codeigniter/core/Loader_test.php
index ecc5ca9..dea01a5 100644
--- a/tests/codeigniter/core/Loader_test.php
+++ b/tests/codeigniter/core/Loader_test.php
@@ -25,7 +25,7 @@
 		// Create library in VFS
 		$lib = 'unit_test_lib';
 		$class = 'CI_'.ucfirst($lib);
-		$this->ci_vfs_create($lib, '<?php class '.$class.' { }', $this->ci_base_root, 'libraries');
+		$this->ci_vfs_create(ucfirst($lib), '<?php class '.$class.' { }', $this->ci_base_root, 'libraries');
 
 		// Test is_loaded fail
 		$this->assertFalse($this->load->is_loaded($lib));
@@ -48,7 +48,7 @@
 		// Test non-existent class
 		$this->setExpectedException(
 			'RuntimeException',
-			'CI Error: Non-existent class: '.$lib
+			'CI Error: Unable to load the requested class: '.ucfirst($lib)
 		);
 		$this->assertNull($this->load->library($lib));
 	}
@@ -105,7 +105,7 @@
 		$lib = 'unit_test_config_lib';
 		$class = 'CI_'.ucfirst($lib);
 		$content = '<?php class '.$class.' { public function __construct($params) { $this->config = $params; } }';
-		$this->ci_vfs_create($lib, $content, $this->ci_base_root, 'libraries');
+		$this->ci_vfs_create(ucfirst($lib), $content, $this->ci_base_root, 'libraries');
 
 		// Create config file
 		$cfg = array(
@@ -133,7 +133,7 @@
 		// Create library in VFS
 		$lib = 'super_test_library';
 		$class = ucfirst($lib);
-		$this->ci_vfs_create($lib, '<?php class '.$class.' { }', $this->ci_app_root, 'libraries');
+		$this->ci_vfs_create(ucfirst($lib), '<?php class '.$class.' { }', $this->ci_app_root, 'libraries');
 
 		// Load library
 		$this->assertNull($this->load->library($lib));
@@ -152,7 +152,7 @@
 		$dir = ucfirst($driver);
 		$class = 'CI_'.$dir;
 		$content = '<?php class '.$class.' { } ';
-		$this->ci_vfs_create($driver, $content, $this->ci_base_root, 'libraries/'.$dir);
+		$this->ci_vfs_create(ucfirst($driver), $content, $this->ci_base_root, 'libraries/'.$dir);
 
 		// Test loading as an array.
 		$this->assertNull($this->load->driver(array($driver)));
@@ -410,7 +410,7 @@
 		$dir = 'third-party';
 		$lib = 'unit_test_package';
 		$class = 'CI_'.ucfirst($lib);
-		$this->ci_vfs_create($lib, '<?php class '.$class.' { }', $this->ci_app_root, array($dir, 'libraries'));
+		$this->ci_vfs_create(ucfirst($lib), '<?php class '.$class.' { }', $this->ci_app_root, array($dir, 'libraries'));
 
 		// Get paths
 		$paths = $this->load->get_package_paths(TRUE);
@@ -440,7 +440,7 @@
 		// Test failed load without path
 		$this->setExpectedException(
 			'RuntimeException',
-			'CI Error: Unable to load the requested class: '.$lib
+			'CI Error: Unable to load the requested class: '.ucfirst($lib)
 		);
 		$this->load->library($lib);
 	}
@@ -467,13 +467,13 @@
 		// Create library in VFS
 		$lib = 'autolib';
 		$lib_class = 'CI_'.ucfirst($lib);
-		$this->ci_vfs_create($lib, '<?php class '.$lib_class.' { }', $this->ci_base_root, 'libraries');
+		$this->ci_vfs_create(ucfirst($lib), '<?php class '.$lib_class.' { }', $this->ci_base_root, 'libraries');
 
 		// Create driver in VFS
 		$drv = 'autodrv';
 		$subdir = ucfirst($drv);
 		$drv_class = 'CI_'.$subdir;
-		$this->ci_vfs_create($drv, '<?php class '.$drv_class.' { }', $this->ci_base_root, array('libraries', $subdir));
+		$this->ci_vfs_create(ucfirst($drv), '<?php class '.$drv_class.' { }', $this->ci_base_root, array('libraries', $subdir));
 
 		// Create model in VFS package path
 		$dir = 'testdir';
diff --git a/tests/codeigniter/core/Output_test.php b/tests/codeigniter/core/Output_test.php
index 728df3b..0eeb93f 100644
--- a/tests/codeigniter/core/Output_test.php
+++ b/tests/codeigniter/core/Output_test.php
@@ -3,6 +3,16 @@
 class Output_test extends CI_TestCase {
 
 	public $output;
+	protected $_output_data = <<<HTML
+<html>
+	<head>
+		<title>Basic HTML</title>
+	</head>
+	<body>
+		Test
+	</body>
+</html>
+HTML;
 
 	public function set_up()
 	{
@@ -13,6 +23,31 @@
 
 	// --------------------------------------------------------------------
 
+	public function test_set_get_append_output()
+	{
+		$append = "<!-- comment /-->\n";
+
+		$this->assertEquals(
+			$this->_output_data.$append,
+			$this->output
+				->set_output($this->_output_data)
+				->append_output("<!-- comment /-->\n")
+				->get_output()
+		);
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_minify()
+	{
+		$this->assertEquals(
+			str_replace(array("\t", "\n"), '', $this->_output_data),
+			$this->output->minify($this->_output_data)
+		);
+	}
+
+	// --------------------------------------------------------------------
+
 	public function test_get_content_type()
 	{
 		$this->assertEquals('text/html', $this->output->get_content_type());
diff --git a/tests/codeigniter/core/URI_test.php b/tests/codeigniter/core/URI_test.php
index e2deabe..7fa0e62 100644
--- a/tests/codeigniter/core/URI_test.php
+++ b/tests/codeigniter/core/URI_test.php
@@ -91,7 +91,7 @@
 
 	public function test_explode_segments()
 	{
-		// Lets test the function's ability to clean up this mess
+		// Let's test the function's ability to clean up this mess
 		$uris = array(
 			'test/uri' => array('test', 'uri'),
 			'/test2/uri2' => array('test2', 'uri2'),
diff --git a/tests/codeigniter/core/Utf8_test.php b/tests/codeigniter/core/Utf8_test.php
new file mode 100644
index 0000000..caa7b69
--- /dev/null
+++ b/tests/codeigniter/core/Utf8_test.php
@@ -0,0 +1,20 @@
+<?php
+
+class Utf8_test extends CI_TestCase {
+
+	public function set_up()
+	{
+		$this->utf8 = new Mock_Core_Utf8();
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_convert_to_utf8()
+	{
+		$this->assertEquals(
+			$this->utf8->convert_to_utf8('òåñò', 'WINDOWS-1251'),
+			'тест'
+		);
+	}
+
+}
\ 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 8916527..e234f9c 100644
--- a/tests/codeigniter/helpers/form_helper_test.php
+++ b/tests/codeigniter/helpers/form_helper_test.php
@@ -58,7 +58,7 @@
 	public function test_form_upload()
 	{
 		$expected = <<<EOH
-<input type="file" name="attachment" value=""  />
+<input type="file" name="attachment"  />
 
 EOH;
 
diff --git a/tests/codeigniter/helpers/url_helper_test.php b/tests/codeigniter/helpers/url_helper_test.php
index 5fc3642..24823a6 100644
--- a/tests/codeigniter/helpers/url_helper_test.php
+++ b/tests/codeigniter/helpers/url_helper_test.php
@@ -48,11 +48,12 @@
 	public function test_auto_link_url()
 	{
 		$strings = array(
-			'www.codeigniter.com test' => '<a href="http://www.codeigniter.com">http://www.codeigniter.com</a> test',
+			'www.codeigniter.com test' => '<a href="http://www.codeigniter.com">www.codeigniter.com</a> test',
 			'This is my noreply@codeigniter.com test' => 'This is my noreply@codeigniter.com test',
-			'<br />www.google.com' => '<br /><a href="http://www.google.com">http://www.google.com</a>',
-			'Download CodeIgniter at www.codeigniter.com. Period test.' => 'Download CodeIgniter at <a href="http://www.codeigniter.com">http://www.codeigniter.com</a>. Period test.',
-			'Download CodeIgniter at www.codeigniter.com, comma test' => 'Download CodeIgniter at <a href="http://www.codeigniter.com">http://www.codeigniter.com</a>, comma test'
+			'<br />www.google.com' => '<br /><a href="http://www.google.com">www.google.com</a>',
+			'Download CodeIgniter at www.codeigniter.com. Period test.' => 'Download CodeIgniter at <a href="http://www.codeigniter.com">www.codeigniter.com</a>. Period test.',
+			'Download CodeIgniter at www.codeigniter.com, comma test' => 'Download CodeIgniter at <a href="http://www.codeigniter.com">www.codeigniter.com</a>, comma test',
+			'This one: ://codeigniter.com must not break this one: http://codeigniter.com' => 'This one: <a href="://codeigniter.com">://codeigniter.com</a> must not break this one: <a href="http://codeigniter.com">http://codeigniter.com</a>'
 		);
 
 		foreach ($strings as $in => $out)
@@ -66,7 +67,7 @@
 	public function test_pull_675()
 	{
 		$strings = array(
-			'<br />www.google.com' => '<br /><a href="http://www.google.com">http://www.google.com</a>',
+			'<br />www.google.com' => '<br /><a href="http://www.google.com">www.google.com</a>',
 		);
 
 		foreach ($strings as $in => $out)
diff --git a/tests/codeigniter/libraries/Upload_test.php b/tests/codeigniter/libraries/Upload_test.php
index 1bd8f14..4d9e4a4 100644
--- a/tests/codeigniter/libraries/Upload_test.php
+++ b/tests/codeigniter/libraries/Upload_test.php
@@ -208,12 +208,6 @@
 		$this->assertEquals('', $this->upload->get_extension('hello'));
 	}
 
-	function test_clean_file_name()
-	{
-		$this->assertEquals('hello.txt', $this->upload->clean_file_name('hello.txt'));
-		$this->assertEquals('hello.txt', $this->upload->clean_file_name('%253chell>o.txt'));
-	}
-
 	function test_limit_filename_length()
 	{
 		$this->assertEquals('hello.txt', $this->upload->limit_filename_length('hello.txt', 10));
diff --git a/tests/mocks/database/ci_test.sqlite b/tests/mocks/database/ci_test.sqlite
index 44dcef9..574d3ae 100755
--- a/tests/mocks/database/ci_test.sqlite
+++ b/tests/mocks/database/ci_test.sqlite
Binary files differ
diff --git a/tests/mocks/libraries/session.php b/tests/mocks/libraries/session.php
index 562033b..adbecb3 100644
--- a/tests/mocks/libraries/session.php
+++ b/tests/mocks/libraries/session.php
@@ -33,4 +33,6 @@
 			$_COOKIE[$name] = $value;
 		}
 	}
-}
\ No newline at end of file
+}
+
+class Mock_Libraries_Session_native extends CI_Session_native {}
\ No newline at end of file
diff --git a/user_guide_src/source/changelog.rst b/user_guide_src/source/changelog.rst
index 8b9ec25..216bf80 100644
--- a/user_guide_src/source/changelog.rst
+++ b/user_guide_src/source/changelog.rst
@@ -38,7 +38,6 @@
    -  Updated support for php files in mimes.php.
    -  Updated support for zip files in mimes.php.
    -  Updated support for csv files in mimes.php.
-   -  Added some more doctypes.
    -  Added Romanian, Greek, Vietnamese and Cyrilic characters in *application/config/foreign_characters.php*.
    -  Changed logger to only chmod when file is first created.
    -  Removed previously deprecated SHA1 Library.
@@ -56,16 +55,16 @@
    -  Updated *ip_address* database field lengths from 16 to 45 for supporting IPv6 address on :doc:`Trackback Library <libraries/trackback>` and :doc:`Captcha Helper <helpers/captcha_helper>`.
    -  Removed *cheatsheets* and *quick_reference* PDFs from the documentation.
    -  Added availability checks where usage of dangerous functions like ``eval()`` and ``exec()`` is required.
+   -  Added support for changing the file extension of log files using ``$config['log_file_extension']``.
 
 -  Helpers
 
    -  :doc:`Date Helper <helpers/date_helper>` changes include:
-	 - ``now()`` now works with all timezone strings supported by PHP.
-	 - Added an optional third parameter to ``timespan()`` that constrains the number of time units displayed.
-	 - Added an optional parameter to ``timezone_menu()`` that allows more attributes to be added to the generated select tag.
+	 - :php:func:`now()` now works with all timezone strings supported by PHP.
+	 - Added an optional third parameter to :php:func:`timespan()` that constrains the number of time units displayed.
+	 - Added an optional parameter to :php:func:`timezone_menu()` that allows more attributes to be added to the generated select tag.
 	 - Deprecated ``standard_date()``, which now just uses the native ``date()`` with `DateTime constants <http://www.php.net/manual/en/class.datetime.php#datetime.constants.types>`_.
-	 - Added function ``date_range()`` that generates a list of dates between a specified period.
-   -  ``create_captcha()`` accepts additional colors parameter, allowing for color customization.
+	 - Added function :php:func:`date_range()` that generates a list of dates between a specified period.
    -  :doc:`URL Helper <helpers/url_helper>` changes include:
 	 - Deprecated *separator* options **dash** and **underscore** for function :php:func:`url_title()` (they are only aliases for '-' and '_' respectively).
 	 - :php:func:`url_title()` will now trim extra dashes from beginning and end.
@@ -74,7 +73,10 @@
 	 - Added support (auto-detection) for HTTP/1.1 response code 303 in :php:func:`redirect()`.
 	 - Changed :php:func:`redirect()` to only choose the **refresh** method only on IIS servers, instead of all servers on Windows (when **auto** is used).
 	 - Changed :php:func:`anchor()`, :php:func:`anchor_popup()`, and :php:func:`redirect()` to support protocol-relative URLs (e.g. *//ellislab.com/codeigniter*).
-   -  Added XHTML Basic 1.1 doctype to :doc:`HTML Helper <helpers/html_helper>`.
+   -  :doc:`HTML Helper <helpers/html_helper>` changes include:
+	 - Added more doctypes.
+	 - Changed application and environment config files to be loaded in a cascade-like manner.
+	 - The doctypes array is now cached and loaded only once.
    -  :doc:`Inflector Helper <helpers/inflector_helper>` changes include:
 	 - Changed :php:func:`humanize()` to allow passing an input separator as its second parameter.
 	 - Refactored :php:func:`plural()` and :php:func:`singular()` to avoid double pluralization and support more words.
@@ -88,7 +90,10 @@
    -  :doc:`Security Helper <helpers/security_helper>` changes include:
 	 - :php:func:`do_hash()` now uses PHP's native ``hash()`` function (supporting more algorithms) and is deprecated.
 	 - :php:func:`strip_image_tags()` is now an alias for the same method in the :doc:`Security Library <libraries/security>`.
-   -  Removed previously deprecated helper function ``js_insert_smiley()`` from :doc:`Smiley Helper <helpers/smiley_helper>`.
+   -  :doc:`Smiley Helper <helpers/smiley_helper>` changes include:
+	 - Removed previously deprecated function ``js_insert_smiley()``.
+	 - Changed application and environment config files to be loaded in a cascade-like manner.
+	 - The smileys array is now cached and loaded only once.
    -  :doc:`File Helper <helpers/file_helper>` changes include:
 	 - :php:func:`set_realpath()` can now also handle file paths as opposed to just directories.
 	 - Added an optional paramater to :php:func:`delete_files()` to enable it to skip deleting files such as *.htaccess* and *index.html*.
@@ -210,6 +215,7 @@
 	 -  Added **max_filename_increment** config setting.
 	 -  Added an **index** parameter to the ``data()`` method.
 	 -  Added the **min_width** and **min_height** options for images.
+	 -  Removed method ``clean_file_name()`` and its usage in favor of :doc:`Security Library <libraries/security>`'s ``sanitize_filename()``.
    -  :doc:`Cart library <libraries/cart>` changes include:
 	 -  ``insert()`` now auto-increments quantity for an item when inserted twice instead of resetting it, this is the default behaviour of large e-commerce sites.
 	 -  *Product Name* strictness can be disabled by switching the ``$product_name_safe`` property to FALSE.
@@ -236,6 +242,7 @@
 	 -  Added rule **valid_url**.
 	 -  Added support for named parameters in error messages.
 	 -  :doc:`Language <libraries/language>` line keys must now be prefixed with **form_validation_**.
+	 -  Added rule **alpha_numeric_spaces**.
    -  Added support for setting :doc:`Table <libraries/table>` class defaults in a config file.
    -  :doc:`Caching Library <libraries/caching>` changes include:
 	 -  Added Wincache driver.
@@ -254,6 +261,7 @@
 	 -  Removed unused protected method ``_get_ip()`` (:doc:`Input Library <libraries/input>`'s ``ip_address()`` should be used anyway).
 	 -  Internal method ``_prep_q_encoding()`` now utilizes PHP's *mbstring* and *iconv* extensions (when available) and no longer has a second (``$from``) argument.
 	 -  Added an optional parameter to ``print_debugger()`` to allow specifying which parts of the message should be printed ('headers', 'subject', 'body').
+	 -  Added SMTP keepalive option to avoid opening the connection for each ``Email::send()``. Accessible as ``$smtp_keepalive``.
    -  :doc:`Pagination Library <libraries/pagination>` changes include:
 	 -  Added support for the anchor "rel" attribute.
 	 -  Added support for setting custom attributes.
@@ -264,7 +272,9 @@
    -  :doc:`Encryption Library <libraries/encryption>` changes include:
 	 -  Added support for hashing algorithms other than SHA1 and MD5.
 	 -  Removed previously deprecated ``sha1()`` method.
-   -  :doc:`Profiler Library <general/profiling>` now also displays database object names.
+   -  :doc:`Profiler Library <general/profiling>` changes include:
+	 -  Database object names are now being displayed.
+	 -  The sum of all queries running times in seconds is now being displayed.
    -  :doc:`Migration Library <libraries/migration>` changes include:
 	 -  Added support for timestamp-based migrations (enabled by default).
 	 -  Added ``$config['migration_type']`` to allow switching between *sequential* and *timestamp* migrations.
@@ -329,16 +339,15 @@
 
 -  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 (#159, #163) - :doc:`Query Builder <database/query_builder>` nested transactions didn't work properly due to ``_trans_depth`` not being incremented.
 -  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 (#419) - :php:func:`auto_link()` didn't recognize URLs that come after a word boundary.
 -  Fixed a bug (#724) - :doc:`Form Validation Library <libraries/form_validation>` rule **is_unique** didn't check if a database connection exists.
 -  Fixed a bug (#647) - :doc:`Zip Library <libraries/zip>` internal method ``_get_mod_time()`` didn't suppress possible "stat failed" errors generated by ``filemtime()``.
--  Fixed a bug (#608) - Fixes an issue with the Image_lib class not clearing properties completely.
--  Fixed a bug (#157, #174) - the Image_lib clear() function now resets all variables to their default values.
--  Fixed a bug where using $this->dbforge->create_table() with PostgreSQL database could lead to fetching whole table.
--  Fixed a bug (#795) - Fixed form method and accept-charset when passing an empty array.
--  Fixed a bug (#797) - timespan() was using incorrect seconds for year and month.
+-  Fixed a bug (#157, #174) - :doc:`Image Manipulation Library <libraries/image_lib>` method ``clear()`` didn't completely clear properties.
+-  Fixed a bug where :doc:`Database Forge <database/forge>` method ``create_table()`` with PostgreSQL database could lead to fetching the whole table.
+-  Fixed a bug (#795) - :doc:`Form Helper <helpers/form_helper>` :php:func:`form_open()` didn't add the default form *method* and *accept-charset* when an empty array is passed to it.
+-  Fixed a bug (#797) - :php:func:`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()``.
@@ -472,6 +481,12 @@
 -  Fixed a bug (#113) - :doc:`Form Validation Library <libraries/form_validation>` didn't properly handle empty fields that were specified as an array.
 -  Fixed a bug (#2061) - :doc:`Routing Class <general/routing>` didn't properly sanitize directory, controller and function triggers with **enable_query_strings** set to TRUE.
 -  Fixed a bug - SQLSRV didn't support ``escape_like_str()`` or escaping an array of values.
+-  Fixed a bug - :doc:`DB result <database/results>` method ``list_fields()`` didn't reset its field pointer for the *mysql*, *mysqli* and *mssql* drivers.
+-  Fixed a bug (#73) - :doc:`Security Library <libraries/security>` method ``sanitize_filename()`` could be tricked by an XSS attack.
+-  Fixed a bug (#2211) - :doc:`Migration Library <libraries/migration>` extensions couldn't execute ``CI_Migration::__construct()``.
+-  Fixed a bug (#2255) - :doc:`Email Library <libraries/email>` didn't apply ``smtp_timeout``to socket reads and writes.
+-  Fixed a bug (#2239) - :doc:`Email Library <libraries/email>` improperly handled the Subject when used with ``bcc_batch_mode`` resulting in E_WARNING messages and an empty Subject.
+-  Fixed a bug (#2234) - :doc:`Query Builder <database/query_builder>` didn't reset JOIN cache for write-type queries.
 
 Version 2.1.3
 =============
diff --git a/user_guide_src/source/database/call_function.rst b/user_guide_src/source/database/call_function.rst
index 9890fc4..83fc870 100644
--- a/user_guide_src/source/database/call_function.rst
+++ b/user_guide_src/source/database/call_function.rst
@@ -7,7 +7,7 @@
 
 This function enables you to call PHP database functions that are not
 natively included in CodeIgniter, in a platform independent manner. For
-example, lets say you want to call the mysql_get_client_info()
+example, let's say you want to call the mysql_get_client_info()
 function, which is **not** natively supported by CodeIgniter. You could
 do so like this::
 
diff --git a/user_guide_src/source/general/controllers.rst b/user_guide_src/source/general/controllers.rst
index 729b084..8cfb012 100644
--- a/user_guide_src/source/general/controllers.rst
+++ b/user_guide_src/source/general/controllers.rst
@@ -108,7 +108,7 @@
 If your URI contains more then two segments they will be passed to your
 method as parameters.
 
-For example, lets say you have a URI like this::
+For example, let's say you have a URI like this::
 
 	example.com/index.php/products/shoes/sandals/123
 
@@ -267,7 +267,7 @@
 and place your controller classes within them.
 
 .. note:: When using this feature the first segment of your URI must
-	specify the folder. For example, lets say you have a controller located
+	specify the folder. For example, let's say you have a controller located
 	here::
 
 		application/controllers/products/shoes.php
diff --git a/user_guide_src/source/general/routing.rst b/user_guide_src/source/general/routing.rst
index 2a03320..0c6dfe8 100644
--- a/user_guide_src/source/general/routing.rst
+++ b/user_guide_src/source/general/routing.rst
@@ -12,7 +12,7 @@
 that a different class/method can be called instead of the one
 corresponding to the URL.
 
-For example, lets say you want your URLs to have this prototype::
+For example, let's say you want your URLs to have this prototype::
 
 	example.com/product/1/
 	example.com/product/2/
@@ -129,7 +129,7 @@
 more about them, `regular-expressions.info <http://www.regular-expressions.info/>`
 might be a good starting point.
 
-..note:: You can also mix and match wildcards with regular expressions.
+.. note:: You can also mix and match wildcards with regular expressions.
 
 Callbacks
 =========
@@ -137,7 +137,7 @@
 If you are using PHP >= 5.3 you can use callbacks in place of the normal
 routing rules to process the back-references. Example::
 
-	$route['products/([a-z]+)/edit/(\d+)'] = function ($product_type, $id)
+	$route['products/([a-zA-Z]+)/edit/(\d+)'] = function ($product_type, $id)
 	{
 		return 'catalog/product_edit/' . strtolower($product_type) . '/' . $id;
 	};
diff --git a/user_guide_src/source/installation/upgrade_300.rst b/user_guide_src/source/installation/upgrade_300.rst
index 94f6321..02841ab 100644
--- a/user_guide_src/source/installation/upgrade_300.rst
+++ b/user_guide_src/source/installation/upgrade_300.rst
@@ -1,5 +1,5 @@
 #############################
-Upgrading from 2.1.2 to 3.0.0
+Upgrading from 2.1.3 to 3.0.0
 #############################
 
 .. note:: These upgrade notes are for a version that is yet to be released.
@@ -104,16 +104,47 @@
 	(.+)	// matches ANYTHING
 	(:any)	// matches any character, except for '/'
 
+*****************************************
+Step 9: Update your libraries' file names
+*****************************************
 
-****************************************************************************
-Step 9: Check the calls to Array Helper's element() and elements() functions
-****************************************************************************
+CodeIgniter 3.0 only allows library file names to be named in a *ucfirst* manner
+(meaning that the first letter of the class name must be a capital). For example,
+if you have the following library file:
+
+	application/libraries/mylibrary.php
+
+... then you'll have to rename it to:
+
+	application/libraries/Mylibrary.php
+
+The same goes for driver libraries and extensions and/or overrides of CodeIgniter's
+own libraries and core classes.
+
+	application/libraries/MY_email.php
+	application/core/MY_log.php
+
+The above files should respectively be renamed to the following:
+
+	application/libraries/MY_Email.php
+	application/core/MY_Log.php
+
+*****************************************************************************
+Step 10: Check the calls to Array Helper's element() and elements() functions
+*****************************************************************************
 
 The default return value of these functions, when the required elements
 don't exist, has been changed from FALSE to NULL.
 
+***********************************************************************
+Step 11: Check the calls to Directory Helper's directory_map() function
+***********************************************************************
+
+In the resulting array, directories now end with a trailing directory
+separator (i.e. a slash, usually).
+
 *************************************************************
-Step 10: Update usage of Database Forge's drop_table() method
+Step 12: Update usage of Database Forge's drop_table() method
 *************************************************************
 
 Up until now, ``drop_table()`` added an IF EXISTS clause by default or it didn't work
@@ -135,7 +166,7 @@
 	all drivers with the exception of ODBC.
 
 ***********************************************************
-Step 11: Change usage of Email library with multiple emails
+Step 13: Change usage of Email library with multiple emails
 ***********************************************************
 
 The :doc:`Email Library <../libraries/email>` will automatically clear the
@@ -150,7 +181,7 @@
  	}
 
 ***************************************************
-Step 12: Update your Form_validation language lines
+Step 14: Update your Form_validation language lines
 ***************************************************
 
 Two improvements have been made to the :doc:`Form Validation Library
@@ -181,7 +212,7 @@
 	later.
 
 ****************************************************************
-Step 13: Remove usage of (previously) deprecated functionalities
+Step 15: Remove usage of (previously) deprecated functionalities
 ****************************************************************
 
 In addition to the ``$autoload['core']`` configuration setting, there's a
@@ -214,7 +245,7 @@
 :doc:`Security Helper <../helpers/security_helper>` function ``do_hash()`` is now just an alias for
 PHP's native ``hash()`` function. It is deprecated and scheduled for removal in CodeIgniter 3.1+.
 
-.. note:: This function is still available, but you're strongly encouraged to remove it's usage sooner
+.. note:: This function is still available, but you're strongly encouraged to remove its usage sooner
 	rather than later.
 
 File helper read_file()
@@ -224,7 +255,7 @@
 PHP's native ``file_get_contents()`` function. It is deprecated and scheduled for removal in
 CodeIgniter 3.1+.
 
-.. note:: This function is still available, but you're strongly encouraged to remove it's usage sooner
+.. note:: This function is still available, but you're strongly encouraged to remove its usage sooner
 	rather than later.
 
 String helper repeater()
@@ -233,7 +264,7 @@
 :doc:`String Helper <../helpers/string_helper>` function :php:func:`repeater()` is now just an alias for
 PHP's native ``str_repeat()`` function. It is deprecated and scheduled for removal in CodeIgniter 3.1+.
 
-.. note:: This function is still available, but you're strongly encouraged to remove it's usage sooner
+.. note:: This function is still available, but you're strongly encouraged to remove its usage sooner
 	rather than later.
 
 String helper trim_slashes()
@@ -243,7 +274,7 @@
 for PHP's native ``trim()`` function (with a slash passed as its second argument). It is deprecated and
 scheduled for removal in CodeIgniter 3.1+.
 
-.. note:: This function is still available, but you're strongly encouraged to remove it's usage sooner
+.. note:: This function is still available, but you're strongly encouraged to remove its usage sooner
 	rather than later.
 
 Email helper functions
@@ -268,7 +299,7 @@
 to the availability of native PHP `constants <http://www.php.net/manual/en/class.datetime.php#datetime.constants.types>`_,
 which when combined with ``date()`` provide the same functionality. Furthermore, they have the
 exact same names as the ones supported by ``standard_date()``. Here are examples of how to replace
-it's usage:
+its usage:
 
 ::
 
@@ -284,7 +315,7 @@
 	// Replacement
 	date(DATE_ATOM, $time);
 
-.. note:: This function is still available, but you're strongly encouraged to remove its' usage sooner
+.. note:: This function is still available, but you're strongly encouraged to remove its usage sooner
 	rather than later as it is scheduled for removal in CodeIgniter 3.1+.
 
 Pagination library 'anchor_class' setting
@@ -296,7 +327,7 @@
 As a result of that, the 'anchor_class' setting is now deprecated and scheduled for removal in
 CodeIgniter 3.1+.
 
-.. note:: This setting is still available, but you're strongly encouraged to remove its' usage sooner
+.. note:: This setting is still available, but you're strongly encouraged to remove its usage sooner
 	rather than later.
 
 String helper random_string() types 'unique' and 'encrypt'
diff --git a/user_guide_src/source/libraries/email.rst b/user_guide_src/source/libraries/email.rst
index 7d46825..a55f189 100644
--- a/user_guide_src/source/libraries/email.rst
+++ b/user_guide_src/source/libraries/email.rst
@@ -89,6 +89,7 @@
 **smtp_pass**       No Default             None                         SMTP Password.
 **smtp_port**       25                     None                         SMTP Port.
 **smtp_timeout**    5                      None                         SMTP Timeout (in seconds).
+**smtp_keepalive**  FALSE                  TRUE or FALSE (boolean)      Enable persistent SMTP connections.
 **smtp_crypto**     No Default             tls or ssl                   SMTP Encryption
 **wordwrap**        TRUE                   TRUE or FALSE (boolean)      Enable word-wrap.
 **wrapchars**       76                                                  Character count to wrap at.
diff --git a/user_guide_src/source/libraries/form_validation.rst b/user_guide_src/source/libraries/form_validation.rst
index ae7859a..8b35fdc 100644
--- a/user_guide_src/source/libraries/form_validation.rst
+++ b/user_guide_src/source/libraries/form_validation.rst
@@ -877,7 +877,9 @@
 **less_than_equal_to**    Yes        Returns FALSE if the form element is greater than the parameter value,                        less_than_equal_to[8]
                                      or not numeric.
 **alpha**                 No         Returns FALSE if the form element contains anything other than alphabetical characters.                              
-**alpha_numeric**         No         Returns FALSE if the form element contains anything other than alpha-numeric characters.                             
+**alpha_numeric**         No         Returns FALSE if the form element contains anything other than alpha-numeric characters.
+**alpha_numeric_spaces**  No         Returns FALSE if the form element contains anything other than alpha-numeric characters
+                                     or spaces.  Should be used after trim to avoid spaces at the beginning or end.                             
 **alpha_dash**            No         Returns FALSE if the form element contains anything other than alpha-numeric characters,                             
                                      underscores or dashes.                                                                                               
 **numeric**               No         Returns FALSE if the form element contains anything other than numeric characters.                                   
diff --git a/user_guide_src/source/libraries/loader.rst b/user_guide_src/source/libraries/loader.rst
index 615aba1..b048f48 100644
--- a/user_guide_src/source/libraries/loader.rst
+++ b/user_guide_src/source/libraries/loader.rst
@@ -11,14 +11,15 @@
 .. note:: This class is initialized automatically by the system so there
 	is no need to do it manually.
 
-The following functions are available in this class:
+The following methods are available in this class:
 
 $this->load->library('class_name', $config, 'object name')
-===========================================================
+==========================================================
 
-This function is used to load core classes. Where class_name is the
-name of the class you want to load. Note: We use the terms "class" and
-"library" interchangeably.
+This method is used to load core classes. Where class_name is the
+name of the class you want to load.
+
+.. note:: We use the terms "class" and "library" interchangeably.
 
 For example, if you would like to send email with CodeIgniter, the first
 step is to load the email class within your controller::
@@ -26,15 +27,15 @@
 	$this->load->library('email');
 
 Once loaded, the library will be ready for use, using
-$this->email->*some_function*().
+$this->email->*some_method*().
 
 Library files can be stored in subdirectories within the main
-"libraries" folder, or within your personal application/libraries
-folder. To load a file located in a subdirectory, simply include the
-path, relative to the "libraries" folder. For example, if you have file
-located at::
+"libraries" directory, or within your personal application/libraries
+directory. To load a file located in a subdirectory, simply include the
+path, relative to the "libraries" directory. For example, if you have
+file located at::
 
-	libraries/flavors/chocolate.php
+	libraries/flavors/Chocolate.php
 
 You will load it using::
 
@@ -43,7 +44,7 @@
 You may nest the file in as many subdirectories as you want.
 
 Additionally, multiple libraries can be loaded at the same time by
-passing an array of libraries to the load function.
+passing an array of libraries to the load method.
 
 ::
 
@@ -56,10 +57,10 @@
 configuration setting. You will typically pass these as an array::
 
 	$config = array (
-	                  'mailtype' => 'html',
-	                  'charset'  => 'utf-8,
-	                  'priority' => '1'
-	               );
+		'mailtype' => 'html',
+		'charset'  => 'utf-8,
+		'priority' => '1'
+	);
 
 	$this->load->library('email', $config);
 
@@ -84,16 +85,15 @@
 	$this->load->library('calendar', '', 'my_calendar');
 
 	// Calendar class is now accessed using:
-
 	$this->my_calendar
 
 Please take note, when multiple libraries are supplied in an array for
 the first parameter, this parameter is discarded.
 
 $this->load->driver('parent_name', $config, 'object name')
-===========================================================
+==========================================================
 
-This function is used to load driver libraries. Where parent_name is the
+This method is used to load driver libraries. Where parent_name is the
 name of the parent class you want to load.
 
 As an example, if you would like to use sessions with CodeIgniter, the first
@@ -102,15 +102,15 @@
 	$this->load->driver('session');
 
 Once loaded, the library will be ready for use, using
-$this->session->*some_function*().
+$this->session->*some_method*().
 
 Driver files must be stored in a subdirectory within the main
-"libraries" folder, or within your personal application/libraries
-folder. The subdirectory must match the parent class name. Read the
+"libraries" directory, or within your personal application/libraries
+directory. The subdirectory must match the parent class name. Read the
 :doc:`Drivers <../general/drivers>` description for details.
 
 Additionally, multiple driver libraries can be loaded at the same time by
-passing an array of drivers to the load function.
+passing an array of drivers to the load method.
 
 ::
 
@@ -122,11 +122,11 @@
 The second (optional) parameter allows you to optionally pass
 configuration settings. You will typically pass these as an array::
 
-	$config = array (
-	                  'sess_driver' => 'cookie',
-	                  'sess_encrypt_cookie'  => true,
-	                  'encryption_key' => 'mysecretkey'
-	               );
+	$config = array(
+		'sess_driver' => 'cookie',
+		'sess_encrypt_cookie'  => true,
+		'encryption_key' => 'mysecretkey'
+	);
 
 	$this->load->driver('session', $config);
 
@@ -135,12 +135,12 @@
 regarding each one you would like to use.
 
 Assigning a Driver to a different object name
-----------------------------------------------
+---------------------------------------------
 
 If the third (optional) parameter is blank, the library will be assigned
 to an object with the same name as the parent class. For example, if
 the library is named Session, it will be assigned to a variable named
-$this->session.
+``$this->session``.
 
 If you prefer to set your own class names you can pass its value to the
 third parameter::
@@ -148,32 +148,33 @@
 	$this->load->library('session', '', 'my_session');
 
 	// Session class is now accessed using:
-
 	$this->my_session
 
-.. note:: Driver libraries may also be loaded with the library() method,
-	but it is faster to use driver()
+.. note:: Driver libraries may also be loaded with the ``library()`` method,
+	but it is faster to use ``driver()``.
 
-$this->load->view('file_name', $data, true/false)
-==================================================
+$this->load->view('file_name', $data, TRUE/FALSE)
+=================================================
 
-This function is used to load your View files. If you haven't read the
+This method is used to load your View files. If you haven't read the
 :doc:`Views <../general/views>` section of the user guide it is
-recommended that you do since it shows you how this function is
+recommended that you do since it shows you how this method is
 typically used.
 
 The first parameter is required. It is the name of the view file you
-would like to load. Note: The .php file extension does not need to be
-specified unless you use something other than .php.
+would like to load.
+
+.. note:: The .php file extension does not need to be specified unless
+	you use something other than .php.
 
 The second **optional** parameter can take an associative array or an
 object as input, which it runs through the PHP
-`extract <http://www.php.net/extract>`_ function to convert to variables
+`extract() <http://www.php.net/extract>`_ function to convert to variables
 that can be used in your view files. Again, read the
 :doc:`Views <../general/views>` page to learn how this might be useful.
 
 The third **optional** parameter lets you change the behavior of the
-function so that it returns data as a string rather than sending it to
+method so that it returns data as a string rather than sending it to
 your browser. This can be useful if you want to process the data in some
 way. If you set the parameter to true (boolean) it will return data. The
 default behavior is false, which sends it to your browser. Remember to
@@ -189,79 +190,76 @@
 	$this->load->model('model_name');
 
 
-If your model is located in a sub-folder, include the relative path from
-your models folder. For example, if you have a model located at
+If your model is located in a subdirectory, include the relative path
+from your models directory. For example, if you have a model located at
 application/models/blog/queries.php you'll load it using::
 
 	$this->load->model('blog/queries');
 
-
 If you would like your model assigned to a different object name you can
-specify it via the second parameter of the loading function::
+specify it via the second parameter of the loading method::
 
 	$this->load->model('model_name', 'fubar');
+	$this->fubar->method();
 
-	$this->fubar->function();
-
-$this->load->database('options', true/false)
+$this->load->database('options', TRUE/FALSE)
 ============================================
 
-This function lets you load the database class. The two parameters are
+This method lets you load the database class. The two parameters are
 **optional**. Please see the :doc:`database <../database/index>`
 section for more info.
 
 $this->load->vars($array)
 =========================
 
-This function takes an associative array as input and generates
+This method takes an associative array as input and generates
 variables using the PHP `extract <http://www.php.net/extract>`_
-function. This function produces the same result as using the second
-parameter of the $this->load->view() function above. The reason you
-might want to use this function independently is if you would like to
+method. This method produces the same result as using the second
+parameter of the ``$this->load->view()`` method above. The reason you
+might want to use this method independently is if you would like to
 set some global variables in the constructor of your controller and have
-them become available in any view file loaded from any function. You can
-have multiple calls to this function. The data get cached and merged
+them become available in any view file loaded from any method. You can
+have multiple calls to this method. The data get cached and merged
 into one array for conversion to variables.
 
 $this->load->get_var($key)
-===========================
+==========================
 
-This function checks the associative array of variables available to
+This method checks the associative array of variables available to
 your views. This is useful if for any reason a var is set in a library
-or another controller method using $this->load->vars().
+or another controller method using ``$this->load->vars()``.
 
 $this->load->get_vars()
-===========================
+=======================
 
-This function retrieves all variables available to
-your views.
+This method retrieves all variables available to your views.
 
 $this->load->helper('file_name')
-=================================
+================================
 
-This function loads helper files, where file_name is the name of the
+This method loads helper files, where file_name is the name of the
 file, without the _helper.php extension.
 
-$this->load->file('filepath/filename', true/false)
+$this->load->file('filepath/filename', TRUE/FALSE)
 ==================================================
 
-This is a generic file loading function. Supply the filepath and name in
+This is a generic file loading method. Supply the filepath and name in
 the first parameter and it will open and read the file. By default the
 data is sent to your browser, just like a View file, but if you set the
 second parameter to true (boolean) it will instead return the data as a
 string.
 
 $this->load->language('file_name')
-===================================
+==================================
 
-This function is an alias of the :doc:`language loading
-function <language>`: $this->lang->load()
+This method is an alias of the :doc:`language loading
+method <language>`: ``$this->lang->load()``
 
 $this->load->config('file_name')
-=================================
+================================
 
-This function is an alias of the :doc:`config file loading
-function <config>`: $this->config->load()
+This method is an alias of the :doc:`config file loading
+method <config>`: ``$this->config->load()``
 
 Application "Packages"
 ======================
@@ -269,7 +267,7 @@
 An application package allows for the easy distribution of complete sets
 of resources in a single directory, complete with its own libraries,
 models, helpers, config, and language files. It is recommended that
-these packages be placed in the application/third_party folder. Below
+these packages be placed in the application/third_party directory. Below
 is a sample map of an package directory
 
 Sample Package "Foo Bar" Directory Map
@@ -311,7 +309,7 @@
 When your controller is finished using resources from an application
 package, and particularly if you have other application packages you
 want to work with, you may wish to remove the package path so the Loader
-no longer looks in that folder for resources. To remove the last path
+no longer looks in that directory for resources. To remove the last path
 added, simply call the method with no parameters.
 
 $this->load->remove_package_path()
@@ -346,4 +344,4 @@
 	// Again without the second parameter:
 	$this->load->add_package_path(APPPATH.'my_app');
 	$this->load->view('my_app_index'); // Loads
-	$this->load->view('welcome_message'); // Loads
+	$this->load->view('welcome_message'); // Loads
\ No newline at end of file
diff --git a/user_guide_src/source/libraries/migration.rst b/user_guide_src/source/libraries/migration.rst
index 9a7b10d..b734f5c 100644
--- a/user_guide_src/source/libraries/migration.rst
+++ b/user_guide_src/source/libraries/migration.rst
@@ -10,7 +10,7 @@
 
 The database table **migration** tracks which migrations have already been 
 run so all you have to do is update your application files and 
-call **$this->migrate->current()** to work out which migrations should be run. 
+call **$this->migration->current()** to work out which migrations should be run. 
 The current version is found in **config/migration.php**.
 
 ********************
diff --git a/user_guide_src/source/tutorial/news_section.rst b/user_guide_src/source/tutorial/news_section.rst
index b64ea2a..d7754e9 100644
--- a/user_guide_src/source/tutorial/news_section.rst
+++ b/user_guide_src/source/tutorial/news_section.rst
@@ -68,7 +68,7 @@
 			$query = $this->db->get('news');
 			return $query->result_array();
 		}
-        
+
 		$query = $this->db->get_where('news', array('slug' => $slug));
 		return $query->row_array();
 	}
@@ -146,7 +146,7 @@
 	<?php foreach ($news as $news_item): ?>
 
 		<h2><?php echo $news_item['title'] ?></h2>
-		<div id="main">
+		<div class="main">
 			<?php echo $news_item['text'] ?>
 		</div>
 		<p><a href="<?php echo $news_item['slug'] ?>">View article</a></p>
@@ -162,7 +162,7 @@
 news items is still absent. The model created earlier is made in such
 way that it can easily be used for this functionality. You only need to
 add some code to the controller and create a new view. Go back to the
-news controller and add the following lines to the file.
+news controller and update ``view()`` with the following:
 
 ::
 
@@ -211,4 +211,4 @@
 	$route['default_controller'] = 'pages/view';
 
 Point your browser to your document root, followed by index.php/news and
-watch your news page.
\ No newline at end of file
+watch your news page.