Merge branch 'develop' into feature/unit-tests
diff --git a/application/config/config.php b/application/config/config.php
index 1ec6543..880393c 100644
--- a/application/config/config.php
+++ b/application/config/config.php
@@ -176,6 +176,10 @@
 |	3 = Informational Messages
 |	4 = All Messages
 |
+| You can also pass in a array with threshold levels to show individual error types
+| 
+| 	array(2) = Debug Messages, without Error Messages
+|
 | For a live site you'll usually only enable Errors (1) to be logged otherwise
 | your log files will fill up very fast.
 |
@@ -292,11 +296,13 @@
 | 'csrf_token_name' = The token name
 | 'csrf_cookie_name' = The cookie name
 | 'csrf_expire' = The number in seconds the token should expire.
+| 'csrf_exclude_uris' = Array of URIs which ignore CSRF checks
 */
 $config['csrf_protection'] = FALSE;
 $config['csrf_token_name'] = 'csrf_test_name';
 $config['csrf_cookie_name'] = 'csrf_cookie_name';
 $config['csrf_expire'] = 7200;
+$config['csrf_exclude_uris'] = array();
 
 /*
 |--------------------------------------------------------------------------
diff --git a/application/config/mimes.php b/application/config/mimes.php
index 82767d7..90a1d18 100644
--- a/application/config/mimes.php
+++ b/application/config/mimes.php
@@ -8,10 +8,10 @@
 |
 */
 
-$mimes = array(	'hqx'	=>	'application/mac-binhex40',
+$mimes = array('hqx'   =>      array('application/mac-binhex40', 'application/mac-binhex', 'application/x-binhex40', 'application/x-mac-binhex40'),
 				'cpt'	=>	'application/mac-compactpro',
 				'csv'	=>	array('text/x-comma-separated-values', 'text/comma-separated-values', 'application/octet-stream', 'application/vnd.ms-excel', 'application/x-csv', 'text/x-csv', 'text/csv', 'application/csv', 'application/excel', 'application/vnd.msexcel'),
-				'bin'	=>	'application/macbinary',
+				'bin'	=>	array('application/macbinary', 'application/mac-binary', 'application/octet-stream', 'application/x-binary', 'application/x-macbinary'),
 				'dms'	=>	'application/octet-stream',
 				'lha'	=>	'application/octet-stream',
 				'lzh'	=>	'application/octet-stream',
@@ -39,6 +39,7 @@
 				'dvi'	=>	'application/x-dvi',
 				'gtar'	=>	'application/x-gtar',
 				'gz'	=>	'application/x-gzip',
+				'gzip'  =>	'application/x-gzip',
 				'php'	=>	'application/x-httpd-php',
 				'php4'	=>	'application/x-httpd-php',
 				'php3'	=>	'application/x-httpd-php',
@@ -51,14 +52,14 @@
 				'tgz'	=>	array('application/x-tar', 'application/x-gzip-compressed'),
 				'xhtml'	=>	'application/xhtml+xml',
 				'xht'	=>	'application/xhtml+xml',
-				'zip'	=>  array('application/x-zip', 'application/zip', 'application/x-zip-compressed'),
+				'zip'	=>	array('application/x-zip', 'application/zip', 'application/x-zip-compressed'),
 				'mid'	=>	'audio/midi',
 				'midi'	=>	'audio/midi',
 				'mpga'	=>	'audio/mpeg',
 				'mp2'	=>	'audio/mpeg',
 				'mp3'	=>	array('audio/mpeg', 'audio/mpg', 'audio/mpeg3', 'audio/mp3'),
-				'aif'	=>	'audio/x-aiff',
-				'aiff'	=>	'audio/x-aiff',
+				'aif'	=>	array('audio/x-aiff', 'audio/aiff'),
+				'aiff'	=>	array('audio/x-aiff', 'audio/aiff'),
 				'aifc'	=>	'audio/x-aiff',
 				'ram'	=>	'audio/x-pn-realaudio',
 				'rm'	=>	'audio/x-pn-realaudio',
@@ -66,7 +67,7 @@
 				'ra'	=>	'audio/x-realaudio',
 				'rv'	=>	'video/vnd.rn-realvideo',
 				'wav'	=>	'audio/x-wav',
-				'bmp'	=>	'image/bmp',
+				'bmp'	=>	array('image/bmp', 'image/x-windows-bmp'),
 				'gif'	=>	'image/gif',
 				'jpeg'	=>	array('image/jpeg', 'image/pjpeg'),
 				'jpg'	=>	array('image/jpeg', 'image/pjpeg'),
@@ -90,7 +91,7 @@
 				'mpe'	=>	'video/mpeg',
 				'qt'	=>	'video/quicktime',
 				'mov'	=>	'video/quicktime',
-				'avi'	=>	'video/x-msvideo',
+				'avi'	=>	array('video/x-msvideo', 'video/msvideo', 'video/avi', 'application/x-troff-msvideo'),
 				'movie'	=>	'video/x-sgi-movie',
 				'doc'	=>	'application/msword',
 				'docx'	=>	'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
@@ -98,7 +99,40 @@
 				'word'	=>	array('application/msword', 'application/octet-stream'),
 				'xl'	=>	'application/excel',
 				'eml'	=>	'message/rfc822',
-				'json' => array('application/json', 'text/json')
+				'json'  =>	array('application/json', 'text/json'),
+				'pem'   =>	array('application/x-x509-user-cert', 'application/x-pem-file', 'application/octet-stream'),
+				'p10'   =>	array('application/x-pkcs10', 'application/pkcs10'),
+				'p12'   =>	'application/x-pkcs12',
+				'p7a'   =>	'application/x-pkcs7-signature',
+				'p7c'   =>	array('application/pkcs7-mime', 'application/x-pkcs7-mime'),
+				'p7m'   =>	array('application/pkcs7-mime', 'application/x-pkcs7-mime'),
+				'p7r'   =>	'application/x-pkcs7-certreqresp',
+				'p7s'   =>	'application/pkcs7-signature',
+				'crt'   =>	array('application/x-x509-ca-cert', 'application/x-x509-user-cert', 'application/pkix-cert'),
+				'crl'   =>	array('application/pkix-crl', 'application/pkcs-crl'),
+				'der'   =>	'application/x-x509-ca-cert',
+				'kdb'   =>	'application/octet-stream',
+				'pgp'   =>	'application/pgp',
+				'gpg'   =>	'application/gpg-keys',
+				'sst'   =>	'application/octet-stream',
+				'csr'   =>	'application/octet-stream',
+				'rsa'   =>	'application/x-pkcs7',
+				'cer'   =>	array('application/pkix-cert', 'application/x-x509-ca-cert'),
+				'3g2'   =>	'video/3gpp2',
+				'3gp'   =>	'video/3gp',
+				'mp4'   =>	'video/mp4',
+				'm4a'   =>	'audio/x-m4a',
+				'f4v'   =>	'video/mp4',
+				'aac'   =>	'audio/x-acc',
+				'm4u'   =>	'application/vnd.mpegurl',
+				'm3u'   =>	'text/plain',
+				'xspf'  =>	'application/xspf+xml',
+				'vlc'   =>	'application/videolan',
+				'wmv'   =>	'video/x-ms-wmv',
+				'au'    =>	'audio/x-au',
+				'ac3'   =>	'audio/ac3',
+				'flac'  =>	'audio/x-flac',
+				'ogg'   =>	'audio/ogg',
 			);
 
 
diff --git a/application/config/user_agents.php b/application/config/user_agents.php
index e2d3c3a..4746f2f 100644
--- a/application/config/user_agents.php
+++ b/application/config/user_agents.php
@@ -126,6 +126,7 @@
 					'sendo'				=> "Sendo",
 
 					// Operating Systems
+					'android'				=> "Android",
 					'symbian'				=> "Symbian",
 					'SymbianOS'				=> "SymbianOS",
 					'elaine'				=> "Palm",
diff --git a/index.php b/index.php
index 899f4ce..c50cfed 100644
--- a/index.php
+++ b/index.php
@@ -73,6 +73,23 @@
  *
  */
 	$application_folder = 'application';
+		
+/*
+ *---------------------------------------------------------------
+ * VIEW FOLDER NAME
+ *---------------------------------------------------------------
+ * 
+ * If you want to move the view folder out of the application 
+ * folder set the path to the folder here. The folder can be renamed
+ * and relocated anywhere on your server. If blank, it will default 
+ * to the standard location inside your application folder.  If you 
+ * do move this, use the full server path to this folder 
+ *
+ * NO TRAILING SLASH!
+ *
+ */
+	$view_folder = '';	
+
 
 /*
  * --------------------------------------------------------------------
@@ -190,6 +207,22 @@
 
 		define('APPPATH', BASEPATH.$application_folder.'/');
 	}
+	
+	// The path to the "views" folder
+	if (is_dir($view_folder)) 
+	{
+		define ('VIEWPATH', $view_folder .'/');
+	}
+	else 
+	{
+		if ( ! is_dir(APPPATH.'views/'))
+		{
+			exit("Your view folder path does not appear to be set correctly. Please open the following file and correct this: ".SELF);
+		}
+				
+		define ('VIEWPATH', APPPATH.'views/' );	
+	}
+	
 
 /*
  * --------------------------------------------------------------------
diff --git a/readme.md b/readme.md
new file mode 100644
index 0000000..be807db
--- /dev/null
+++ b/readme.md
@@ -0,0 +1,11 @@
+# What is CodeIgniter
+
+CodeIgniter is an Application Development Framework - a toolkit - for people who build web sites using PHP. Its goal is to enable you to develop projects much faster than you could if you were writing code from scratch, by providing a rich set of libraries for commonly needed tasks, as well as a simple interface and logical structure to access these libraries. CodeIgniter lets you creatively focus on your project by minimizing the amount of code needed for a given task.
+
+# Resources
+
+ * [User Guide](http://codeigniter.com/user_guide/)
+ * [Community Forums](http://codeigniter.com/forums/)
+ * [User Voice](http://codeigniter.uservoice.com/forums/40508-codeigniter-reactor)
+ * [Community Wiki](http://codeigniter.com/wiki/)
+ * [Community IRC](http://webchat.freenode.net/?channels=codeigniter&uio=d4)
\ No newline at end of file
diff --git a/system/core/CodeIgniter.php b/system/core/CodeIgniter.php
index 0a1391d..aca4fb2 100755
--- a/system/core/CodeIgniter.php
+++ b/system/core/CodeIgniter.php
@@ -39,7 +39,7 @@
 	 * @var string
 	 *
 	 */
-	define('CI_VERSION', '2.0.2');
+	define('CI_VERSION', '2.1.0-dev');
 
 /**
  * CodeIgniter Branch (Core = TRUE, Reactor = FALSE)
diff --git a/system/core/Common.php b/system/core/Common.php
index db9fbeb..d793754 100644
--- a/system/core/Common.php
+++ b/system/core/Common.php
@@ -132,9 +132,9 @@
 
 		$name = FALSE;
 
-		// Look for the class first in the native system/libraries folder
-		// thenin the local application/libraries folder
-		foreach (array(BASEPATH, APPPATH) as $path)
+		// Look for the class first in the local application/libraries folder
+		// then in the native system/libraries folder
+		foreach (array(APPPATH, BASEPATH) as $path)
 		{
 			if (file_exists($path.$directory.'/'.$class.'.php'))
 			{
@@ -536,5 +536,29 @@
 	}
 }
 
+// ------------------------------------------------------------------------
+
+/**
+* Returns HTML escaped variable
+*
+* @access	public
+* @param	mixed
+* @return	mixed
+*/
+if ( ! function_exists('html_escape'))
+{
+	function html_escape($var)
+	{
+		if (is_array($var))
+		{
+			return array_map('html_escape', $var);
+		}
+		else
+		{
+			return htmlspecialchars($var, ENT_QUOTES, config_item('charset'));
+		}
+	}
+}
+
 /* End of file Common.php */
 /* Location: ./system/core/Common.php */
\ No newline at end of file
diff --git a/system/core/Input.php b/system/core/Input.php
index 5a033e7..0dc2c45 100755
--- a/system/core/Input.php
+++ b/system/core/Input.php
@@ -323,14 +323,14 @@
 
 			$this->ip_address = in_array($_SERVER['REMOTE_ADDR'], $proxies) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : $_SERVER['REMOTE_ADDR'];
 		}
+		elseif (! $this->server('HTTP_CLIENT_IP') AND $this->server('REMOTE_ADDR'))
+		{
+			$this->ip_address = $_SERVER['REMOTE_ADDR'];
+		}
 		elseif ($this->server('REMOTE_ADDR') AND $this->server('HTTP_CLIENT_IP'))
 		{
 			$this->ip_address = $_SERVER['HTTP_CLIENT_IP'];
 		}
-		elseif ($this->server('REMOTE_ADDR'))
-		{
-			$this->ip_address = $_SERVER['REMOTE_ADDR'];
-		}
 		elseif ($this->server('HTTP_CLIENT_IP'))
 		{
 			$this->ip_address = $_SERVER['HTTP_CLIENT_IP'];
diff --git a/system/core/Lang.php b/system/core/Lang.php
index 5ac6718..d61d102 100755
--- a/system/core/Lang.php
+++ b/system/core/Lang.php
@@ -112,7 +112,7 @@
 		}
 
 
-		if ( ! isset($lang))
+		if ( ! isset($lang) OR ! is_array($lang))
 		{
 			log_message('error', 'Language file contains no data: language/'.$idiom.'/'.$langfile);
 			return;
@@ -124,7 +124,7 @@
 		}
 
 		$this->is_loaded[] = $langfile;
-		$this->language = array_merge($this->language, $lang);
+		$this->language = $this->language + $lang;
 		unset($lang);
 
 		log_message('debug', 'Language file loaded: language/'.$idiom.'/'.$langfile);
diff --git a/system/core/Loader.php b/system/core/Loader.php
index e7fa3d3..de0fc06 100755
--- a/system/core/Loader.php
+++ b/system/core/Loader.php
@@ -127,7 +127,7 @@
 		$this->_ci_library_paths = array(APPPATH, BASEPATH);
 		$this->_ci_helper_paths = array(APPPATH, BASEPATH);
 		$this->_ci_model_paths = array(APPPATH);
-		$this->_ci_view_paths = array(APPPATH.'views/'	=> TRUE);
+		$this->_ci_view_paths = array(VIEWPATH	=> TRUE);
 
 		log_message('debug', "Loader Class Initialized");
 	}
@@ -1106,7 +1106,7 @@
 	 * @param	array
 	 * @return	void
 	 */
-	private function _ci_autoloader()
+	protected function _ci_autoloader()
 	{
 		if (defined('ENVIRONMENT') AND file_exists(APPPATH.'config/'.ENVIRONMENT.'/autoload.php'))
 		{
diff --git a/system/core/Security.php b/system/core/Security.php
index dcc680a..342455f 100755
--- a/system/core/Security.php
+++ b/system/core/Security.php
@@ -33,6 +33,7 @@
 	 * @access protected
 	 */
 	protected $_xss_hash			= '';
+	
 	/**
 	 * Random Hash for Cross Site Request Forgery Protection Cookie
 	 *
@@ -40,6 +41,7 @@
 	 * @access protected
 	 */
 	protected $_csrf_hash			= '';
+	
 	/**
 	 * Expiration time for Cross Site Request Forgery Protection Cookie
 	 * Defaults to two hours (in seconds)
@@ -48,6 +50,7 @@
 	 * @access protected
 	 */
 	protected $_csrf_expire			= 7200;
+	
 	/**
 	 * Token name for Cross Site Request Forgery Protection Cookie
 	 *
@@ -55,6 +58,7 @@
 	 * @access protected
 	 */
 	protected $_csrf_token_name		= 'ci_csrf_token';
+	
 	/**
 	 * Cookie name for Cross Site Request Forgery Protection Cookie
 	 *
@@ -62,12 +66,14 @@
 	 * @access protected
 	 */
 	protected $_csrf_cookie_name	= 'ci_csrf_token';
+	
 	/**
 	 * List of never allowed strings
 	 *
 	 * @var array
 	 * @access protected
 	 */
+	
 	protected $_never_allowed_str = array(
 					'document.cookie'	=> '[removed]',
 					'document.write'	=> '[removed]',
@@ -80,7 +86,6 @@
 					'<![CDATA['			=> '&lt;![CDATA['
 	);
 
-	/* never allowed, regex replacement */
 	/**
 	 * List of never allowed regex replacement
 	 *
@@ -134,6 +139,16 @@
 		{
 			return $this->csrf_set_cookie();
 		}
+		
+		// Check if URI has been whitelisted from CSRF checks
+		if ($exclude_uris = config_item('csrf_exclude_uris'))
+		{
+			$uri = load_class('URI', 'core');
+			if (in_array($uri->uri_string(), $exclude_uris))
+			{
+				return $this;
+			}
+		}
 
 		// Do the tokens exist in both the _POST and _COOKIE arrays?
 		if ( ! isset($_POST[$this->_csrf_token_name]) OR
@@ -156,9 +171,9 @@
 		unset($_COOKIE[$this->_csrf_cookie_name]);
 		$this->_csrf_set_hash();
 		$this->csrf_set_cookie();
-
-		log_message('debug', "CSRF token verified ");
-
+		
+		log_message('debug', "CSRF token verified");
+		
 		return $this;
 	}
 
@@ -869,7 +884,6 @@
 	}
 
 }
-// END Security Class
 
 /* End of file Security.php */
-/* Location: ./system/libraries/Security.php */
+/* Location: ./system/libraries/Security.php */
\ No newline at end of file
diff --git a/system/core/URI.php b/system/core/URI.php
index 51c2191..e58bdf7 100755
--- a/system/core/URI.php
+++ b/system/core/URI.php
@@ -175,7 +175,7 @@
 	 * @access	private
 	 * @return	string
 	 */
-	private function _detect_uri()
+	protected function _detect_uri()
 	{
 		if ( ! isset($_SERVER['REQUEST_URI']) OR ! isset($_SERVER['SCRIPT_NAME']))
 		{
@@ -247,7 +247,7 @@
 	 * @access	private
 	 * @return	string
 	 */
-	private function _parse_cli_args()
+	protected function _parse_cli_args()
 	{
 		$args = array_slice($_SERVER['argv'], 1);
 
diff --git a/system/database/drivers/oci8/oci8_driver.php b/system/database/drivers/oci8/oci8_driver.php
index 42cfaae..d4adfd5 100644
--- a/system/database/drivers/oci8/oci8_driver.php
+++ b/system/database/drivers/oci8/oci8_driver.php
@@ -404,6 +404,7 @@
 		}
 
 		$str = remove_invisible_characters($str);
+		$str = str_replace("'", "''", $str);
 
 		// escape LIKE condition wildcards
 		if ($like === TRUE)
diff --git a/system/database/drivers/odbc/odbc_driver.php b/system/database/drivers/odbc/odbc_driver.php
index 5e764e0..08cd27b 100644
--- a/system/database/drivers/odbc/odbc_driver.php
+++ b/system/database/drivers/odbc/odbc_driver.php
@@ -50,7 +50,7 @@
 
 	function CI_DB_odbc_driver($params)
 	{
-		parent::CI_DB($params);
+		parent::CI_DB_driver($params);
 
 		$this->_random_keyword = ' RND('.time().')'; // database specific random keyword
 	}
diff --git a/system/helpers/date_helper.php b/system/helpers/date_helper.php
index ce37ad9..f1febfa 100644
--- a/system/helpers/date_helper.php
+++ b/system/helpers/date_helper.php
@@ -492,6 +492,72 @@
 // ------------------------------------------------------------------------
 
 /**
+ * Turns many "reasonably-date-like" strings into something
+ * that is actually useful. This only works for dates after unix epoch.
+ * 
+ * @access  public
+ * @param   string  The terribly formatted date-like string
+ * @param   string  Date format to return (same as php date function)
+ * @return  string
+ */
+if ( ! function_exists('nice_date'))
+{
+	function nice_date($bad_date='', $format=false) 
+	{
+		if (empty($bad_date))
+		{
+			return 'Unknown';
+		}
+		// Date like: YYYYMM
+		if (preg_match('/^\d{6}$/',$bad_date)) 
+		{
+			//echo $bad_date." ";
+			if (in_array(substr($bad_date, 0, 2),array('19', '20'))) 
+			{
+				$year  = substr($bad_date, 0, 4);
+				$month = substr($bad_date, 4, 2);
+			} 
+			else 
+			{
+				$month  = substr($bad_date, 0, 2);
+				$year   = substr($bad_date, 2, 4);
+			}
+			return date($format, strtotime($year . '-' . $month . '-01'));
+		    
+		}
+		
+		// Date Like: YYYYMMDD
+		if (preg_match('/^\d{8}$/',$bad_date)) 
+		{
+			$month = substr($bad_date, 0, 2);
+			$day   = substr($bad_date, 2, 2);
+			$year  = substr($bad_date, 4, 4);
+			return date($format, strtotime($month . '/01/' . $year));
+		}
+		
+		// Date Like: MM-DD-YYYY __or__ M-D-YYYY (or anything in between)
+		if (preg_match('/^\d{1,2}-\d{1,2}-\d{4}$/',$bad_date))
+		{ 
+			list($m, $d, $y) = explode('-', $bad_date);
+			return date($format, strtotime("{$y}-{$m}-{$d}"));
+		}
+		
+		// Any other kind of string, when converted into UNIX time,
+		// produces "0 seconds after epoc..." is probably bad...
+		// return "Invalid Date".
+		if (date('U', strtotime($bad_date)) == '0')
+		{ 
+			return "Invalid Date";
+		}
+		
+		// It's probably a valid-ish date format already
+		return date($format, strtotime($bad_date));
+	}
+}
+
+// ------------------------------------------------------------------------
+
+/**
  * Timezone Menu
  *
  * Generates a drop-down menu of timezones.
diff --git a/system/helpers/url_helper.php b/system/helpers/url_helper.php
old mode 100644
new mode 100755
index 9f4b852..c524ddd
--- a/system/helpers/url_helper.php
+++ b/system/helpers/url_helper.php
@@ -512,7 +512,7 @@
 			$str = strtolower($str);
 		}
 
-		return trim(stripslashes($str));
+		return trim(trim(stripslashes($str)), $replace);
 	}
 }
 
@@ -527,7 +527,7 @@
  *
  * @access	public
  * @param	string	the URL
- * @param	string	the method: location or redirect
+ * @param	string	the method: location or refresh
  * @return	string
  */
 if ( ! function_exists('redirect'))
diff --git a/system/libraries/Image_lib.php b/system/libraries/Image_lib.php
index 8902f52..a8a0387 100644
--- a/system/libraries/Image_lib.php
+++ b/system/libraries/Image_lib.php
@@ -1334,7 +1334,7 @@
 			return FALSE;
 		}
 
-		$vals = @getimagesize($path);
+		$vals = getimagesize($path);
 
 		$types = array(1 => 'gif', 2 => 'jpeg', 3 => 'png');
 
diff --git a/system/libraries/Log.php b/system/libraries/Log.php
index 9f1db76..bf10d47 100644
--- a/system/libraries/Log.php
+++ b/system/libraries/Log.php
@@ -27,10 +27,12 @@
 class CI_Log {
 
 	protected $_log_path;
-	protected $_threshold	= 1;
-	protected $_date_fmt	= 'Y-m-d H:i:s';
-	protected $_enabled	= TRUE;
-	protected $_levels	= array('ERROR' => '1', 'DEBUG' => '2',  'INFO' => '3', 'ALL' => '4');
+	protected $_threshold		= 1;
+	protected $_threshold_max	= 0;
+	protected $_threshold_array	= array();
+	protected $_date_fmt		= 'Y-m-d H:i:s';
+	protected $_enabled			= TRUE;
+	protected $_levels			= array('ERROR' => '1', 'DEBUG' => '2',  'INFO' => '3', 'ALL' => '4');
 
 	/**
 	 * Constructor
@@ -50,6 +52,11 @@
 		{
 			$this->_threshold = $config['log_threshold'];
 		}
+		elseif (is_array($config['log_threshold']))
+		{
+			$this->_threshold = $this->_threshold_max;
+			$this->_threshold_array = array_flip($config['log_threshold']);
+		}
 
 		if ($config['log_date_format'] != '')
 		{
@@ -80,9 +87,13 @@
 
 		if ( ! isset($this->_levels[$level]) OR ($this->_levels[$level] > $this->_threshold))
 		{
-			return FALSE;
+			if (empty($this->_threshold_array) OR ! isset($this->_threshold_array[$this->_levels[$level]]))
+			{
+				return FALSE;
+			}
 		}
 
+
 		$filepath = $this->_log_path.'log-'.date('Y-m-d').'.php';
 		$message  = '';
 
diff --git a/system/libraries/Migration.php b/system/libraries/Migration.php
index 3943ec1..3734e18 100644
--- a/system/libraries/Migration.php
+++ b/system/libraries/Migration.php
@@ -57,7 +57,7 @@
 		}
 
 		// If not set, set it
-		$this->_migration_path == '' OR $this->_migration_path = APPPATH . 'migrations/';
+		$this->_migration_path == '' AND $this->_migration_path = APPPATH . 'migrations/';
 
 		// Add trailing slash if not set
 		$this->_migration_path = rtrim($this->_migration_path, '/').'/';
diff --git a/system/libraries/Profiler.php b/system/libraries/Profiler.php
index 082a5ee..330acce 100644
--- a/system/libraries/Profiler.php
+++ b/system/libraries/Profiler.php
@@ -493,7 +493,7 @@
 	 *
 	 * @return 	string
 	 */
-	private function _compile_session_data()
+	protected function _compile_session_data()
 	{
 		if ( ! isset($this->CI->session))
 		{
@@ -555,4 +555,4 @@
 // END CI_Profiler class
 
 /* End of file Profiler.php */
-/* Location: ./system/libraries/Profiler.php */
\ No newline at end of file
+/* Location: ./system/libraries/Profiler.php */
diff --git a/user_guide/changelog.html b/user_guide/changelog.html
index 301b264..978b710 100644
--- a/user_guide/changelog.html
+++ b/user_guide/changelog.html
@@ -65,18 +65,22 @@
 <ul>
 	<li>General Changes
 		<ul>
+			<li class="reactor">Added Android to the list of user agents.</li>
 			<li class="reactor">Callback validation rules can now accept parameters like any other validation rule.</li>
+			<li class="reactor">Ability to log certain error types, not all under a threshold.</li>
+			<li class="reactor">Added html_escape() to <a href="general/common_functions.html">Common functions</a> to escape HTML output for preventing XSS.</li>
 		</ul>
 	</li>
 	<li>Helpers
 		<ul>
 			<li class="reactor">Added <samp>increment_string()</samp> to <a href="helpers/string_helper.html">String Helper</a> to turn "foo" into "foo-1" or "foo-1" into "foo-2".</li>
         	<li>Altered form helper - made action on form_open_multipart helper function call optional.  Fixes (#65)</li>
+			<li><samp>url_title()</samp> will now trim extra dashes from beginning and end.</li>
 		</ul>
 	</li>
 	<li>Database
 		<ul>
-			<li class="reactor">Added a <a href="http://www.cubrid.org/" target="_blank">CUBRID</a> driver to the <a href="libraries/database.html">Database Driver</a>. Thanks to the CUBRID team for supplying this patch.</li>
+			<li class="reactor">Added a <a href="http://www.cubrid.org/" target="_blank">CUBRID</a> driver to the <a href="database/index.html">Database Driver</a>. Thanks to the CUBRID team for supplying this patch.</li>
 			<li class="reactor">Typecast limit and offset in the <a href="database/queries.html">Database Driver</a> to integers to avoid possible injection.</li>
 			<li class="reactor">
 				Added additional option 'none' for the optional third argument for  <kbd>$this->db->like()</kbd> in the <a href="database/active_record.html">Database Driver</a>.
@@ -90,6 +94,13 @@
 			<li class="reactor">Added a <a href="libraries/migration.html">Migration Library</a> to assist with applying incremental updates to your database schema.</li>
 			<li class="reactor">Driver children can be located in any package path.</li>
 			<li class="reactor">Added max_filename_increment config setting for Upload library.</li>
+			<li><samp>CI_Loader::_ci_autoloader()</samp> is now a protected method.</li>
+			<li class="reactor">Added <kbd>is_unique</kbd> to the <a href="libraries/form_validation.html">Form Validation library</a>.</li>
+		</ul>
+	</li>
+	<li>Core
+		<ul>
+			<li class="reactor">Changed private functions in CI_URI to protected so MY_URI can override them.</li>
 		</ul>
 	</li>
 </ul>
@@ -104,6 +115,9 @@
     <li>Fixed a bug (#181) where a mis-spelling was in the form validation language file.</li>
 	<li>Fixed a bug (#160) - Removed unneeded array copy in the file cache driver.</li>
 	<li>Fixed a bug (#150) - <samp>field_data()</samp> now correctly returns column length.</li>
+	<li>Fixed a bug (#8) - <samp>load_class()</samp> now looks for core classes in <samp>APPPATH</samp> first, allowing them to be replaced.</li>
+	<li>Fixed a bug (#24) - ODBC database driver called incorrect parent in __construct().</li>
+	<li>Fixed a bug (#85) - OCI8 (Oracle) database escape_str() function did not escape correct.</li>
 </ul>
 
 <h2>Version 2.0.3</h2>
@@ -123,7 +137,13 @@
 			<li>Visual updates to the welcome_message view file and default error templates. Thanks to <a href="https://bitbucket.org/danijelb">danijelb</a> for the pull request.</li>
 			<li class="reactor">Added <samp>insert_batch()</samp> function to the PostgreSQL database driver.  Thanks to epallerols for the patch.</li>
 			<li class="reactor">Added "application/x-csv" to mimes.php.</li>
+			<li class="reactor">Added CSRF protection URI whitelisting.</li>
 			<li>Fixed a bug where <a href="libraries/email.html">Email library</a> attachments with a "." in the name would using invalid MIME-types.</li>
+            <li>Added support for pem,p10,p12,p7a,p7c,p7m,p7r,p7s,crt,crl,der,kdb,rsa,cer,sst,csr Certs to mimes.php.</li>
+            <li>Added support pgp,gpg to mimes.php.</li>
+            <li>Added support 3gp, 3g2, mp4, wmv, f4v, vlc Video files to mimes.php.</li>
+            <li>Added support m4a, aac, m4u, xspf, au, ac3, flac, ogg Audio files to mimes.php.</li>
+
 		</ul>
 	</li>
 	<li>Helpers
@@ -136,7 +156,6 @@
 	<li>Libraries
 		<ul>
 			<li>Altered Session to use a longer match against the user_agent string. See upgrade notes if using database sessions.</li>
-			<li class="reactor">Added <kbd>is_unique</kbd> to the <a href="libraries/form_validation.html">Form Validation library</a>.</li>
 			<li class="reactor">Added <kbd>$this->db->set_dbprefix()</kbd> to the <a href="database/queries.html">Database Driver</a>.</li>
 			<li class="reactor">Changed <kbd>$this->cart->insert()</kbd> in the <a href="libraries/cart.html">Cart Library</a> to return the Row ID if a single item was inserted successfully.</li>
 			<li class="reactor">Added <kbd>$this->load->get_var()</kbd> to the <a href="libraries/loader.html">Loader library</a> to retrieve global vars set with <kbd>$this->load->view()</kbd> and <kbd>$this->load->vars()</kbd>.</li>
diff --git a/user_guide/database/active_record.html b/user_guide/database/active_record.html
index 92d9614..0f09e78 100644
--- a/user_guide/database/active_record.html
+++ b/user_guide/database/active_record.html
@@ -79,9 +79,6 @@
 
 <p>The following functions allow you to build SQL <strong>SELECT</strong> statements.</p>
 
-<p><strong>Note: If you are using PHP 5 you can use method chaining for more compact syntax. This is described at the end of the page.</strong></p>
-
-
 <h2>$this->db->get();</h2>
 
 <p>Runs the selection query and returns the result.  Can be used by itself to retrieve all records from a table:</p>
@@ -532,7 +529,7 @@
 <p>Generates an insert string based on the data you supply, and runs the query. You can either pass an
 <strong>array</strong> or an <strong>object</strong> to the function.  Here is an example using an array:</p>
 
-<code> 
+<code>
 $data = array(<br/>
 &nbsp;&nbsp;&nbsp;array(<br />
 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'title' => 'My title' ,<br />
@@ -544,7 +541,7 @@
 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'name' => 'Another Name' ,<br />
 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'date' => 'Another date'<br />
 &nbsp;&nbsp;&nbsp;)<br/>
-);<br /> 
+);<br />
 <br />
 $this->db->update_batch('mytable', $data);
 <br /><br />
diff --git a/user_guide/general/common_functions.html b/user_guide/general/common_functions.html
index 6545775..7cff632 100644
--- a/user_guide/general/common_functions.html
+++ b/user_guide/general/common_functions.html
@@ -104,6 +104,8 @@
 <p>This function prevents inserting null characters between ascii characters, like Java\0script.</p>
 
 
+<h2>html_escape(<var>$mixed</var>)</h2>
+<p>This function provides short cut for htmlspecialchars() function. It accepts string and array. To prevent Cross Site Scripting (XSS), it is very useful.</p>
 
 </div>
 
diff --git a/user_guide/helpers/date_helper.html b/user_guide/helpers/date_helper.html
index f930ea3..5b00e25 100644
--- a/user_guide/helpers/date_helper.html
+++ b/user_guide/helpers/date_helper.html
@@ -234,6 +234,20 @@
 
 
 
+<h2>nice_date()</h2>
+
+<p>This function can take a number poorly-formed date formats and convert them into something useful. It also accepts well-formed dates.</p> 
+<p>The function will return a Unix timestamp by default. You can, optionally, pass a format string (the same type as the PHP date function accepts) as the second parameter. Example:</p>
+
+<code>$bad_time = 199605<br />
+<br />
+// Should Produce: 1996-05-01<br />
+$better_time = nice_date($bad_time,'Y-m-d');<br />
+<br />
+$bad_time = 9-11-2001<br />
+// Should Produce: 2001-09-11<br />
+$better_time = nice_date($human,'Y-m-d');</code>
+
 
 
 <h2>timespan()</h2>
diff --git a/user_guide/helpers/url_helper.html b/user_guide/helpers/url_helper.html
index ac9d0a6..e60e96b 100644
--- a/user_guide/helpers/url_helper.html
+++ b/user_guide/helpers/url_helper.html
@@ -27,7 +27,7 @@
 <div id="masthead">
 <table cellpadding="0" cellspacing="0" border="0" style="width:100%">
 <tr>
-<td><h1>CodeIgniter User Guide Version 2.0.2</h1></td>
+<td><h1>CodeIgniter User Guide Version 2.0.3</h1></td>
 <td id="breadcrumb_right"><a href="../toc.html">Table of Contents Page</a></td>
 </tr>
 </table>
diff --git a/user_guide/installation/index.html b/user_guide/installation/index.html
index 5e8ab38..84338e2 100644
--- a/user_guide/installation/index.html
+++ b/user_guide/installation/index.html
@@ -72,7 +72,9 @@
 
 <p>For the best security, both the <dfn>system</dfn> and any <dfn>application</dfn> folders should be placed above web root so that they are not directly accessible via a browser.  By default, .htaccess files are included in each folder to help prevent direct access, but it is best to remove them from public access entirely in case the web server configuration changes or doesn't abide by the .htaccess.</p>
 
-<p>After moving them, open your main <kdb>index.php</kbd> file and set the <samp>$system_folder</samp> and <samp>$application_folder</samp> variables, preferably with a full path, e.g. '<dfn>/www/MyUser/system</dfn>'.</p>
+<p>If you would like to keep your views public it is also possible to move the <dfn>views</dfn> folder out of your application folder.</p>
+
+<p>After moving them, open your main <kdb>index.php</kbd> file and set the <samp>$system_folder</samp>, <samp>$application_folder</samp> and <samp>$view_folder</samp> variables, preferably with a full path, e.g. '<dfn>/www/MyUser/system</dfn>'.</p>
 
 <p>
     One additional measure to take in production environments is to disable
diff --git a/user_guide/installation/upgrade_203.html b/user_guide/installation/upgrade_203.html
index 1d37a05..0489983 100644
--- a/user_guide/installation/upgrade_203.html
+++ b/user_guide/installation/upgrade_203.html
@@ -81,7 +81,7 @@
 
 <h2>Step 5: Remove APPPATH.'third_party' from autoload.php</h2>
 
-<p>Open application/autoload.php, and look for the following:</p>
+<p>Open application/config/autoload.php, and look for the following:</p>
 
 <code>$autoload['packages'] = array(APPPATH.'third_party');</code>
 
diff --git a/user_guide/libraries/form_validation.html b/user_guide/libraries/form_validation.html
index d9d8a45..ede1913 100644
--- a/user_guide/libraries/form_validation.html
+++ b/user_guide/libraries/form_validation.html
@@ -1042,6 +1042,13 @@
 	</tr>
 
 	<tr>
+		<td class="td"><strong>is_unique</strong></td>
+		<td class="td">Yes</td>
+		<td class="td">Returns FALSE if the form element is not unique in a database table.</td>
+		<td class="td">is_unique[table.field]</td>
+	</tr>
+
+	<tr>
 		<td class="td"><strong>valid_email</strong></td>
 		<td class="td">No</td>
 		<td class="td">Returns FALSE if the form element does not contain a valid email address.</td>
diff --git a/user_guide/libraries/security.html b/user_guide/libraries/security.html
index dd62a43..cbe12d8 100644
--- a/user_guide/libraries/security.html
+++ b/user_guide/libraries/security.html
@@ -116,6 +116,9 @@
 
 <p>If you use the <a href="../helpers/form_helper.html">form helper</a> the <var>form_open()</var> function will automatically insert a hidden csrf field in your forms.</p>
 
+<p>Select URIs can be whitelisted from csrf protection (for example API endpoints expecting externally POSTed content). You can add these URIs by editing the 'csrf_exclude_uris' config parameter:</p>
+<code>$config['csrf_exclude_uris'] = array('api/person/add');</code>
+
 </div>
 <!-- END CONTENT -->