Merge branch 'develop' into feature/user-guide-cleanup
diff --git a/.travis.yml b/.travis.yml
index ab0aa56..718e6aa 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -3,6 +3,8 @@
 php:
   - 5.3
   - 5.4
+  - 5.5
+  - hhvm
   
 env:
   - DB=mysql
@@ -21,6 +23,15 @@
 
 script: phpunit --coverage-text --configuration tests/travis/$DB.phpunit.xml
 
+matrix:
+  allow_failures:
+    - php: hhvm
+  exclude:
+    - php: hhvm
+      env: DB=mysqli
+      env: DB=pgsql
+      env: DB=pdo/pgsql
+
 branches:
   only:
     - develop
diff --git a/application/config/autoload.php b/application/config/autoload.php
index 5a20c94..43d5315 100644
--- a/application/config/autoload.php
+++ b/application/config/autoload.php
@@ -77,6 +77,11 @@
 | Prototype:
 |
 |	$autoload['libraries'] = array('database', 'email', 'xmlrpc');
+|
+| You can also supply an alternative library name to be assigned
+| in the controller:
+|
+|	$autoload['libraries'] = array('user_agent' => 'ua');
 */
 
 $autoload['libraries'] = array();
diff --git a/application/config/config.php b/application/config/config.php
index 0608348..ae748de 100644
--- a/application/config/config.php
+++ b/application/config/config.php
@@ -141,15 +141,18 @@
 | Allowed URL Characters
 |--------------------------------------------------------------------------
 |
-| This lets you specify with a regular expression which characters are permitted
-| within your URLs.  When someone tries to submit a URL with disallowed
-| characters they will get a warning message.
+| This lets you specify which characters are permitted within your URLs.
+| When someone tries to submit a URL with disallowed characters they will
+| get a warning message.
 |
 | As a security measure you are STRONGLY encouraged to restrict URLs to
 | as few characters as possible.  By default only these are allowed: a-z 0-9~%.:_-
 |
 | Leave blank to allow all characters -- but only if you are insane.
 |
+| The configured value is actually a regular expression character group
+| and it will be executed as: ! preg_match('/^[<permitted_uri_chars>]+$/i
+|
 | DO NOT CHANGE THIS UNLESS YOU FULLY UNDERSTAND THE REPERCUSSIONS!!
 |
 */
@@ -282,7 +285,7 @@
 | 'sess_driver'				= the driver to load: cookie (Classic), native (PHP sessions),
 |	or your custom driver name
 | 'sess_valid_drivers'		= additional valid drivers which may be loaded
-| 'sess_cookie_name'		= the name you want for the cookie
+| 'sess_cookie_name'		= the name you want for the cookie, must contain only [0-9a-z_-] characters
 | 'sess_expiration'			= the number of SECONDS you want the session to last.
 |   by default sessions last 7200 seconds (two hours).  Set to zero for no expiration.
 | 'sess_expire_on_close'	= Whether to cause the session to expire automatically
@@ -327,6 +330,20 @@
 
 /*
 |--------------------------------------------------------------------------
+| Standardize newlines
+|--------------------------------------------------------------------------
+|
+| Determines whether to standardize newline characters in input data,
+| meaning to replace \r\n, \r, \n occurences with the PHP_EOL value.
+|
+| This is particularly useful for portability between UNIX-based OSes,
+| (usually \n) and Windows (\r\n).
+|
+*/
+$config['standardize_newlines'] = TRUE;
+
+/*
+|--------------------------------------------------------------------------
 | Global XSS Filtering
 |--------------------------------------------------------------------------
 |
@@ -367,6 +384,9 @@
 | Even if it does, however, not all browsers support compression
 | so enable only if you are reasonably sure your visitors can handle it.
 |
+| Only used if zlib.output_compression is turned off in your php.ini.
+| Please do not use it together with httpd-level output compression.
+|
 | VERY IMPORTANT:  If you are getting a blank page when compression is enabled it
 | means you are prematurely outputting something to your browser. It could
 | even be a line of whitespace at the end of one of your scripts.  For
diff --git a/application/config/constants.php b/application/config/constants.php
index dc84712..e71097b 100644
--- a/application/config/constants.php
+++ b/application/config/constants.php
@@ -81,11 +81,11 @@
 | Used to indicate the conditions under which the script is exit()ing.
 | While there is no universal standard for error codes, there are some
 | broad conventions.  Three such conventions are mentioned below, for
-| those who wish to make use of them.  The CodeIgniter defaults were 
+| those who wish to make use of them.  The CodeIgniter defaults were
 | chosen for the least overlap with these conventions, while still
 | leaving room for others to be defined in future versions and user
 | applications.
-| 
+|
 | The three main conventions used for determining exit status codes
 | are as follows:
 |
@@ -108,7 +108,6 @@
 define('EXIT_DATABASE', 8); // database error
 define('EXIT__AUTO_MIN', 9); // lowest automatically-assigned error code
 define('EXIT__AUTO_MAX', 125); // highest automatically-assigned error code
- 
 
 /* End of file constants.php */
 /* Location: ./application/config/constants.php */
\ No newline at end of file
diff --git a/application/config/database.php b/application/config/database.php
index f0b8397..44fe307 100644
--- a/application/config/database.php
+++ b/application/config/database.php
@@ -68,6 +68,13 @@
 |	['stricton'] TRUE/FALSE - forces 'Strict Mode' connections
 |							- good for ensuring strict SQL while developing
 |	['failover'] array - A array with 0 or more data for connections if the main should fail.
+|	['save_queries'] TRUE/FALSE - Whether to "save" all executed queries.
+| 				NOTE: Disabling this will also effectively disable both
+| 				$this->db->last_query() and profiling of DB queries.
+| 				When you run a query, with this setting set to TRUE (default),
+| 				CodeIgniter will store the SQL statement for debugging purposes.
+| 				However, this may cause high memory usage, especially if you run
+| 				a lot of SQL queries ... disable this to avoid that problem.
 |
 | The $active_group variable lets you choose which connection group to
 | make active.  By default there is only one group (the 'default' group).
@@ -98,7 +105,8 @@
 	'encrypt' => FALSE,
 	'compress' => FALSE,
 	'stricton' => FALSE,
-	'failover' => array()
+	'failover' => array(),
+	'save_queries' => TRUE
 );
 
 /* End of file database.php */
diff --git a/application/config/doctypes.php b/application/config/doctypes.php
index fe54202..b1a8959 100644
--- a/application/config/doctypes.php
+++ b/application/config/doctypes.php
@@ -26,19 +26,19 @@
  */
 
 $_doctypes = array(
-	'xhtml11'		=> '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">',
+	'xhtml11'			=> '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">',
 	'xhtml1-strict'		=> '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">',
 	'xhtml1-trans'		=> '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">',
 	'xhtml1-frame'		=> '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">',
 	'xhtml-basic11'		=> '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">',
-	'html5'			=> '<!DOCTYPE html>',
+	'html5'				=> '<!DOCTYPE html>',
 	'html4-strict'		=> '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">',
 	'html4-trans'		=> '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">',
 	'html4-frame'		=> '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">',
-	'mathml1'		=> '<!DOCTYPE math SYSTEM "http://www.w3.org/Math/DTD/mathml1/mathml.dtd">',
-	'mathml2'		=> '<!DOCTYPE math PUBLIC "-//W3C//DTD MathML 2.0//EN" "http://www.w3.org/Math/DTD/mathml2/mathml2.dtd">',
-	'svg10'			=> '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">',
-	'svg11'			=> '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">',
+	'mathml1'			=> '<!DOCTYPE math SYSTEM "http://www.w3.org/Math/DTD/mathml1/mathml.dtd">',
+	'mathml2'			=> '<!DOCTYPE math PUBLIC "-//W3C//DTD MathML 2.0//EN" "http://www.w3.org/Math/DTD/mathml2/mathml2.dtd">',
+	'svg10'				=> '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">',
+	'svg11'				=> '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">',
 	'svg11-basic'		=> '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1 Basic//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11-basic.dtd">',
 	'svg11-tiny'		=> '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1 Tiny//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11-tiny.dtd">',
 	'xhtml-math-svg-xh'	=> '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN" "http://www.w3.org/2002/04/xhtml-math-svg/xhtml-math-svg.dtd">',
diff --git a/application/config/foreign_chars.php b/application/config/foreign_chars.php
index b0c32cf..ab98224 100644
--- a/application/config/foreign_chars.php
+++ b/application/config/foreign_chars.php
@@ -50,16 +50,16 @@
 	'/д/' => 'd',
 	'/Ð|Ď|Đ|Δ/' => 'Dj',
 	'/ð|ď|đ|δ/' => 'dj',
-	'/È|É|Ê|Ë|Ē|Ĕ|Ė|Ę|Ě|Ε|Έ|Ẽ|Ẻ|Ẹ|Ề|Ế|Ễ|Ể|Ệ|Е|Ё|Э/' => 'E',
-	'/è|é|ê|ë|ē|ĕ|ė|ę|ě|έ|ε|ẽ|ẻ|ẹ|ề|ế|ễ|ể|ệ|е|ё|э/' => 'e',
+	'/È|É|Ê|Ë|Ē|Ĕ|Ė|Ę|Ě|Ε|Έ|Ẽ|Ẻ|Ẹ|Ề|Ế|Ễ|Ể|Ệ|Е|Э/' => 'E',
+	'/è|é|ê|ë|ē|ĕ|ė|ę|ě|έ|ε|ẽ|ẻ|ẹ|ề|ế|ễ|ể|ệ|е|э/' => 'e',
 	'/Ф/' => 'F',
 	'/ф/' => 'f',
-	'/Ĝ|Ğ|Ġ|Ģ|Γ|Г/' => 'G',
-	'/ĝ|ğ|ġ|ģ|γ|г/' => 'g',
+	'/Ĝ|Ğ|Ġ|Ģ|Γ|Г|Ґ/' => 'G',
+	'/ĝ|ğ|ġ|ģ|γ|г|ґ/' => 'g',
 	'/Ĥ|Ħ/' => 'H',
 	'/ĥ|ħ/' => 'h',
-	'/Ì|Í|Î|Ï|Ĩ|Ī|Ĭ|Ǐ|Į|İ|Η|Ή|Ί|Ι|Ϊ|Ỉ|Ị|И|Й/' => 'I',
-	'/ì|í|î|ï|ĩ|ī|ĭ|ǐ|į|ı|η|ή|ί|ι|ϊ|ỉ|ị|и|й/' => 'i',
+	'/Ì|Í|Î|Ï|Ĩ|Ī|Ĭ|Ǐ|Į|İ|Η|Ή|Ί|Ι|Ϊ|Ỉ|Ị|И|Ы/' => 'I',
+	'/ì|í|î|ï|ĩ|ī|ĭ|ǐ|į|ı|η|ή|ί|ι|ϊ|ỉ|ị|и|ы|ї/' => 'i',
 	'/Ĵ/' => 'J',
 	'/ĵ/' => 'j',
 	'/Ķ|Κ|К/' => 'K',
@@ -80,10 +80,10 @@
 	'/ś|ŝ|ş|ș|š|ſ|σ|ς|с/' => 's',
 	'/Ț|Ţ|Ť|Ŧ|τ|Т/' => 'T',
 	'/ț|ţ|ť|ŧ|т/' => 't',
-	'/Ù|Ú|Û|Ũ|Ū|Ŭ|Ů|Ű|Ų|Ư|Ǔ|Ǖ|Ǘ|Ǚ|Ǜ|Ũ|Ủ|Ụ|Ừ|Ứ|Ữ|Ử|Ự|У|Ъ/' => 'U',
-	'/ù|ú|û|ũ|ū|ŭ|ů|ű|ų|ư|ǔ|ǖ|ǘ|ǚ|ǜ|υ|ύ|ϋ|ủ|ụ|ừ|ứ|ữ|ử|ự|у|ъ/' => 'u',
-	'/Ý|Ÿ|Ŷ|Υ|Ύ|Ϋ|Ỳ|Ỹ|Ỷ|Ỵ/' => 'Y',
-	'/ý|ÿ|ŷ|ỳ|ỹ|ỷ|ỵ/' => 'y',
+	'/Ù|Ú|Û|Ũ|Ū|Ŭ|Ů|Ű|Ų|Ư|Ǔ|Ǖ|Ǘ|Ǚ|Ǜ|Ũ|Ủ|Ụ|Ừ|Ứ|Ữ|Ử|Ự|У/' => 'U',
+	'/ù|ú|û|ũ|ū|ŭ|ů|ű|ų|ư|ǔ|ǖ|ǘ|ǚ|ǜ|υ|ύ|ϋ|ủ|ụ|ừ|ứ|ữ|ử|ự|у/' => 'u',
+	'/Ý|Ÿ|Ŷ|Υ|Ύ|Ϋ|Ỳ|Ỹ|Ỷ|Ỵ|Й/' => 'Y',
+	'/ý|ÿ|ŷ|ỳ|ỹ|ỷ|ỵ|й/' => 'y',
 	'/В/' => 'V',
 	'/в/' => 'v',
 	'/Ŵ/' => 'W',
@@ -91,7 +91,7 @@
 	'/Ź|Ż|Ž|Ζ|З/' => 'Z',
 	'/ź|ż|ž|ζ|з/' => 'z',
 	'/Æ|Ǽ/' => 'AE',
-	'/ß/'=> 'ss',
+	'/ß/' => 'ss',
 	'/IJ/' => 'IJ',
 	'/ij/' => 'ij',
 	'/Œ/' => 'OE',
@@ -101,22 +101,28 @@
 	'/β/' => 'v',
 	'/μ/' => 'm',
 	'/ψ/' => 'ps',
-	'/Ж/'=>'Zh',
-	'/ж/'=>'zh',
-	'/Х/'=>'Kh',
-	'/х/'=>'kh',
-	'/Ц/'=>'Tc',
-	'/ц/'=>'tc',
-	'/Ч/'=>'Ch',
-	'/ч/'=>'ch',
-	'/Ш/'=>'Sh',
-	'/ш/'=>'sh',
-	'/Щ/'=>'Shch',
-	'/щ/'=>'shch',
-	'/Ю/'=>'Iu',
-	'/ю/'=>'iu',
-	'/Я/'=>'Ia',
-	'/я/'=>'ia'
+	'/Ё/' => 'Yo',
+	'/ё/' => 'yo',
+	'/Є/' => 'Ye',
+	'/є/' => 'ye',
+	'/Ї/' => 'Yi',
+	'/Ж/' => 'Zh',
+	'/ж/' => 'zh',
+	'/Х/' => 'Kh',
+	'/х/' => 'kh',
+	'/Ц/' => 'Ts',
+	'/ц/' => 'ts',
+	'/Ч/' => 'Ch',
+	'/ч/' => 'ch',
+	'/Ш/' => 'Sh',
+	'/ш/' => 'sh',
+	'/Щ/' => 'Shch',
+	'/щ/' => 'shch',
+	'/Ъ|ъ|Ь|ь/' => '',
+	'/Ю/' => 'Yu',
+	'/ю/' => 'yu',
+	'/Я/' => 'Ya',
+	'/я/' => 'ya'
 );
 
 /* End of file foreign_chars.php */
diff --git a/application/config/migration.php b/application/config/migration.php
index b348fb3..a7576ca 100644
--- a/application/config/migration.php
+++ b/application/config/migration.php
@@ -105,7 +105,7 @@
 | Also, writing permission is required within the migrations path.
 |
 */
-$config['migration_path'] = APPPATH . 'migrations/';
+$config['migration_path'] = APPPATH.'migrations/';
 
 /* End of file migration.php */
 /* Location: ./application/config/migration.php */
\ No newline at end of file
diff --git a/application/config/mimes.php b/application/config/mimes.php
index 32d10f6..27d4b25 100644
--- a/application/config/mimes.php
+++ b/application/config/mimes.php
@@ -78,6 +78,7 @@
 	'sit'	=>	'application/x-stuffit',
 	'tar'	=>	'application/x-tar',
 	'tgz'	=>	array('application/x-tar', 'application/x-gzip-compressed'),
+	'z'	=>	'application/x-compress',
 	'xhtml'	=>	'application/xhtml+xml',
 	'xht'	=>	'application/xhtml+xml',
 	'zip'	=>	array('application/x-zip', 'application/zip', 'application/x-zip-compressed', 'application/s-compressed', 'multipart/x-zip'),
@@ -96,7 +97,7 @@
 	'ra'	=>	'audio/x-realaudio',
 	'rv'	=>	'video/vnd.rn-realvideo',
 	'wav'	=>	array('audio/x-wav', 'audio/wave', 'audio/wav'),
-	'bmp'	=>	array('image/bmp', 'image/x-windows-bmp'),
+	'bmp'	=>	array('image/bmp', 'image/x-bmp', 'image/x-bitmap', 'image/x-xbitmap', 'image/x-win-bitmap', 'image/x-windows-bmp', 'image/ms-bmp', 'image/x-ms-bmp', 'application/bmp', 'application/x-bmp', 'application/x-win-bitmap'),
 	'gif'	=>	'image/gif',
 	'jpeg'	=>	array('image/jpeg', 'image/pjpeg'),
 	'jpg'	=>	array('image/jpeg', 'image/pjpeg'),
diff --git a/application/config/smileys.php b/application/config/smileys.php
index 4b25309..3c49c46 100644
--- a/application/config/smileys.php
+++ b/application/config/smileys.php
@@ -30,7 +30,7 @@
 | SMILEYS
 | -------------------------------------------------------------------
 | This file contains an array of smileys for use with the emoticon helper.
-| Individual images can be used to replace multiple simileys.  For example:
+| Individual images can be used to replace multiple smileys.  For example:
 | :-) and :) use the same image replacement.
 |
 | Please see user guide for more info:
@@ -84,7 +84,7 @@
 	':vampire:'		=>	array('vampire.gif',		'19',	'19',	'vampire'),
 	':snake:'		=>	array('snake.gif',			'19',	'19',	'snake'),
 	':exclaim:'		=>	array('exclaim.gif',		'19',	'19',	'excaim'),
-	':question:'	=>	array('question.gif',		'19',	'19',	'question') // no comma after last item
+	':question:'	=>	array('question.gif',		'19',	'19',	'question')
 
 );
 
diff --git a/application/config/user_agents.php b/application/config/user_agents.php
index 88ab063..819e42b 100644
--- a/application/config/user_agents.php
+++ b/application/config/user_agents.php
@@ -36,6 +36,7 @@
 */
 
 $platforms = array(
+	'windows nt 6.3'	=> 'Windows 8.1',
 	'windows nt 6.2'	=> 'Windows 8',
 	'windows nt 6.1'	=> 'Windows 7',
 	'windows nt 6.0'	=> 'Windows Vista',
@@ -50,6 +51,7 @@
 	'win98'				=> 'Windows 98',
 	'windows 95'		=> 'Windows 95',
 	'win95'				=> 'Windows 95',
+	'windows phone'			=> 'Windows Phone',
 	'windows'			=> 'Unknown Windows OS',
 	'android'			=> 'Android',
 	'blackberry'		=> 'BlackBerry',
@@ -80,11 +82,15 @@
 // The order of this array should NOT be changed. Many browsers return
 // multiple browser types so we want to identify the sub-type first.
 $browsers = array(
+	'OPR'			=> 'Opera',
 	'Flock'			=> 'Flock',
 	'Chrome'		=> 'Chrome',
+	// Opera 10+ always reports Opera/9.80 and appends Version/<real version> to the user agent string
+	'Opera.*?Version'	=> 'Opera',
 	'Opera'			=> 'Opera',
 	'MSIE'			=> 'Internet Explorer',
 	'Internet Explorer'	=> 'Internet Explorer',
+	'Trident.* rv'	=> 'Internet Explorer',
 	'Shiira'		=> 'Shiira',
 	'Firefox'		=> 'Firefox',
 	'Chimera'		=> 'Chimera',
@@ -102,7 +108,8 @@
 	'hotjava'		=> 'HotJava',
 	'amaya'			=> 'Amaya',
 	'IBrowse'		=> 'IBrowse',
-	'Maxthon'		=> 'Maxthon'
+	'Maxthon'		=> 'Maxthon',
+	'Ubuntu'		=> 'Ubuntu Web Browser'
 );
 
 $mobiles = array(
@@ -182,7 +189,7 @@
 	'operamini'		=> 'Opera Mini',
 	'opera mini'	=> 'Opera Mini',
 	'opera mobi'	=> 'Opera Mobile',
-	'fennec'	=> 'Firefox Mobile',
+	'fennec'		=> 'Firefox Mobile',
 
 	// Other
 	'digital paths'	=> 'Digital Paths',
diff --git a/application/controllers/welcome.php b/application/controllers/Welcome.php
similarity index 96%
rename from application/controllers/welcome.php
rename to application/controllers/Welcome.php
index 2f0e358..31ceea9 100644
--- a/application/controllers/welcome.php
+++ b/application/controllers/Welcome.php
@@ -50,4 +50,4 @@
 }
 
 /* End of file welcome.php */
-/* Location: ./application/controllers/welcome.php */
\ No newline at end of file
+/* Location: ./application/controllers/Welcome.php */
\ No newline at end of file
diff --git a/application/views/errors/cli/error_404.php b/application/views/errors/cli/error_404.php
new file mode 100644
index 0000000..68ffdb3
--- /dev/null
+++ b/application/views/errors/cli/error_404.php
@@ -0,0 +1,33 @@
+<?php
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.2.4 or newer
+ *
+ * NOTICE OF LICENSE
+ *
+ * Licensed under the Academic Free License version 3.0
+ *
+ * This source file is subject to the Academic Free License (AFL 3.0) that is
+ * bundled with this package in the files license_afl.txt / license_afl.rst.
+ * It is also available through the world wide web at this URL:
+ * http://opensource.org/licenses/AFL-3.0
+ * If you did not receive a copy of the license and are unable to obtain it
+ * through the world wide web, please send an email to
+ * licensing@ellislab.com so we can send you a copy immediately.
+ *
+ * @package		CodeIgniter
+ * @author		EllisLab Dev Team
+ * @copyright	Copyright (c) 2008 - 2013, EllisLab, Inc. (http://ellislab.com/)
+ * @license		http://opensource.org/licenses/AFL-3.0 Academic Free License (AFL 3.0)
+ * @link		http://codeigniter.com
+ * @since		Version 3.0
+ * @filesource
+ */
+defined('BASEPATH') OR exit('No direct script access allowed');
+
+echo "\nERROR: ",
+	$heading,
+	"\n\n",
+	$message,
+	"\n\n";
\ No newline at end of file
diff --git a/application/views/errors/cli/error_db.php b/application/views/errors/cli/error_db.php
new file mode 100644
index 0000000..aca3a34
--- /dev/null
+++ b/application/views/errors/cli/error_db.php
@@ -0,0 +1,33 @@
+<?php
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.2.4 or newer
+ *
+ * NOTICE OF LICENSE
+ *
+ * Licensed under the Academic Free License version 3.0
+ *
+ * This source file is subject to the Academic Free License (AFL 3.0) that is
+ * bundled with this package in the files license_afl.txt / license_afl.rst.
+ * It is also available through the world wide web at this URL:
+ * http://opensource.org/licenses/AFL-3.0
+ * If you did not receive a copy of the license and are unable to obtain it
+ * through the world wide web, please send an email to
+ * licensing@ellislab.com so we can send you a copy immediately.
+ *
+ * @package		CodeIgniter
+ * @author		EllisLab Dev Team
+ * @copyright	Copyright (c) 2008 - 2013, EllisLab, Inc. (http://ellislab.com/)
+ * @license		http://opensource.org/licenses/AFL-3.0 Academic Free License (AFL 3.0)
+ * @link		http://codeigniter.com
+ * @since		Version 3.0
+ * @filesource
+ */
+defined('BASEPATH') OR exit('No direct script access allowed');
+
+echo "\nDatabase error: ",
+	$heading,
+	"\n\n",
+	$message,
+	"\n\n";
\ No newline at end of file
diff --git a/application/views/errors/cli/error_general.php b/application/views/errors/cli/error_general.php
new file mode 100644
index 0000000..1e5ffe5
--- /dev/null
+++ b/application/views/errors/cli/error_general.php
@@ -0,0 +1,33 @@
+<?php
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.2.4 or newer
+ *
+ * NOTICE OF LICENSE
+ *
+ * Licensed under the Academic Free License version 3.0
+ *
+ * This source file is subject to the Academic Free License (AFL 3.0) that is
+ * bundled with this package in the files license_afl.txt / license_afl.rst.
+ * It is also available through the world wide web at this URL:
+ * http://opensource.org/licenses/AFL-3.0
+ * If you did not receive a copy of the license and are unable to obtain it
+ * through the world wide web, please send an email to
+ * licensing@ellislab.com so we can send you a copy immediately.
+ *
+ * @package		CodeIgniter
+ * @author		EllisLab Dev Team
+ * @copyright	Copyright (c) 2008 - 2013, EllisLab, Inc. (http://ellislab.com/)
+ * @license		http://opensource.org/licenses/AFL-3.0 Academic Free License (AFL 3.0)
+ * @link		http://codeigniter.com
+ * @since		Version 1.0
+ * @filesource
+ */
+defined('BASEPATH') OR exit('No direct script access allowed');
+
+echo "\nERROR: ",
+	$heading,
+	"\n\n",
+	$message,
+	"\n\n";
\ No newline at end of file
diff --git a/application/views/errors/error_php.php b/application/views/errors/cli/error_php.php
similarity index 61%
copy from application/views/errors/error_php.php
copy to application/views/errors/cli/error_php.php
index c4e6b29..4dbc410 100644
--- a/application/views/errors/error_php.php
+++ b/application/views/errors/cli/error_php.php
@@ -21,39 +21,30 @@
  * @copyright	Copyright (c) 2008 - 2013, EllisLab, Inc. (http://ellislab.com/)
  * @license		http://opensource.org/licenses/AFL-3.0 Academic Free License (AFL 3.0)
  * @link		http://codeigniter.com
- * @since		Version 1.0
+ * @since		Version 3.0
  * @filesource
  */
 defined('BASEPATH') OR exit('No direct script access allowed');
 ?>
 
-<div style="border:1px solid #990000;padding-left:20px;margin:0 0 10px 0;">
+A PHP Error was encountered
 
-<h4>A PHP Error was encountered</h4>
-
-<p>Severity: <?php echo $severity; ?></p>
-<p>Message:  <?php echo $message; ?></p>
-<p>Filename: <?php echo $filepath; ?></p>
-<p>Line Number: <?php echo $line; ?></p>
+Severity: <?php echo $severity;?>
+Message:  <?php echo $message;?>
+Filename: <?php echo $filepath;?>
+Line Number: <?php echo $line;?>
 
 <?php if (defined('SHOW_DEBUG_BACKTRACE') && SHOW_DEBUG_BACKTRACE === TRUE): ?>
 
-	<p>Backtrace: </p>
-	<?php foreach(debug_backtrace() as $error): ?>
+Backtrace:
+	<?php foreach (debug_backtrace() as $error): ?>
+		<?php if (isset($error['file']) && strpos($error['file'], realpath(BASEPATH)) !== 0): ?>
 
-		<?php if(isset($error['file']) &&
-		         strpos($error['file'], realpath(BASEPATH)) !== 0): ?>
-
-			<p style="margin-left:10px">
-			File: <?php echo $error['file'] ?><br />
-			Line: <?php echo $error['line'] ?><br />
-			Function: <?php echo $error['function'] ?>
-			</p>
+	File: <?php echo $error['file'];?>
+	Line: <?php echo $error['line'];?>
+	Function: <?php echo $error['function'];?>
 
 		<?php endif ?>
 
-	<?php endforeach ?></p>
-
-<?php endif ?>
-
-</div>
\ No newline at end of file
+	<?php endforeach ?>
+<?php endif ?>
\ No newline at end of file
diff --git a/application/views/errors/cli/index.html b/application/views/errors/cli/index.html
new file mode 100644
index 0000000..c942a79
--- /dev/null
+++ b/application/views/errors/cli/index.html
@@ -0,0 +1,10 @@
+<html>
+<head>
+	<title>403 Forbidden</title>
+</head>
+<body>
+
+<p>Directory access is forbidden.</p>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/application/views/errors/error_404.php b/application/views/errors/html/error_404.php
similarity index 96%
rename from application/views/errors/error_404.php
rename to application/views/errors/html/error_404.php
index 21ff6db..11b8d99 100644
--- a/application/views/errors/error_404.php
+++ b/application/views/errors/html/error_404.php
@@ -74,8 +74,6 @@
 	margin: 10px;
 	border: 1px solid #D0D0D0;
 	box-shadow: 0 0 8px #D0D0D0;
-	-moz-box-shadow: 0 0 8px #D0D0D0;
-	-webkit-box-shadow: 0 0 8px #D0D0D0;
 }
 
 p {
diff --git a/application/views/errors/error_db.php b/application/views/errors/html/error_db.php
similarity index 96%
rename from application/views/errors/error_db.php
rename to application/views/errors/html/error_db.php
index a251e1c..f376e09 100644
--- a/application/views/errors/error_db.php
+++ b/application/views/errors/html/error_db.php
@@ -74,8 +74,6 @@
 	margin: 10px;
 	border: 1px solid #D0D0D0;
 	box-shadow: 0 0 8px #D0D0D0;
-	-moz-box-shadow: 0 0 8px #D0D0D0;
-	-webkit-box-shadow: 0 0 8px #D0D0D0;
 }
 
 p {
diff --git a/application/views/errors/error_general.php b/application/views/errors/html/error_general.php
similarity index 96%
rename from application/views/errors/error_general.php
rename to application/views/errors/html/error_general.php
index b9d5438..df435b3 100644
--- a/application/views/errors/error_general.php
+++ b/application/views/errors/html/error_general.php
@@ -74,8 +74,6 @@
 	margin: 10px;
 	border: 1px solid #D0D0D0;
 	box-shadow: 0 0 8px #D0D0D0;
-	-moz-box-shadow: 0 0 8px #D0D0D0;
-	-webkit-box-shadow: 0 0 8px #D0D0D0;
 }
 
 p {
diff --git a/application/views/errors/error_php.php b/application/views/errors/html/error_php.php
similarity index 90%
rename from application/views/errors/error_php.php
rename to application/views/errors/html/error_php.php
index c4e6b29..2267d98 100644
--- a/application/views/errors/error_php.php
+++ b/application/views/errors/html/error_php.php
@@ -38,11 +38,10 @@
 
 <?php if (defined('SHOW_DEBUG_BACKTRACE') && SHOW_DEBUG_BACKTRACE === TRUE): ?>
 
-	<p>Backtrace: </p>
-	<?php foreach(debug_backtrace() as $error): ?>
+	<p>Backtrace:</p>
+	<?php foreach (debug_backtrace() as $error): ?>
 
-		<?php if(isset($error['file']) &&
-		         strpos($error['file'], realpath(BASEPATH)) !== 0): ?>
+		<?php if (isset($error['file']) && strpos($error['file'], realpath(BASEPATH)) !== 0): ?>
 
 			<p style="margin-left:10px">
 			File: <?php echo $error['file'] ?><br />
diff --git a/application/views/errors/html/index.html b/application/views/errors/html/index.html
new file mode 100644
index 0000000..c942a79
--- /dev/null
+++ b/application/views/errors/html/index.html
@@ -0,0 +1,10 @@
+<html>
+<head>
+	<title>403 Forbidden</title>
+</head>
+<body>
+
+<p>Directory access is forbidden.</p>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/application/views/welcome_message.php b/application/views/welcome_message.php
index 3cc8b80..341a8d0 100644
--- a/application/views/welcome_message.php
+++ b/application/views/welcome_message.php
@@ -87,8 +87,7 @@
 	#container {
 		margin: 10px;
 		border: 1px solid #D0D0D0;
-		-moz-box-shadow: 0 0 8px #D0D0D0;
-		-webkit-box-shadow: 0 0 8px #D0D0D0;
+		box-shadow: 0 0 8px #D0D0D0;
 	}
 	</style>
 </head>
@@ -104,7 +103,7 @@
 		<code>application/views/welcome_message.php</code>
 
 		<p>The corresponding controller for this page is found at:</p>
-		<code>application/controllers/welcome.php</code>
+		<code>application/controllers/Welcome.php</code>
 
 		<p>If you are exploring CodeIgniter for the very first time, you should start by reading the <a href="user_guide/">User Guide</a>.</p>
 	</div>
diff --git a/index.php b/index.php
index cfb003e..72c97c4 100755
--- a/index.php
+++ b/index.php
@@ -61,7 +61,7 @@
 
 	case 'testing':
 	case 'production':
-		error_reporting(E_ALL ^ E_NOTICE ^ E_DEPRECATED ^ E_STRICT);
+		error_reporting(E_ALL & ~E_NOTICE & ~E_DEPRECATED & ~E_STRICT);
 		ini_set('display_errors', 0);
 	break;
 
@@ -77,7 +77,7 @@
  *---------------------------------------------------------------
  *
  * This variable must contain the name of your "system" folder.
- * Include the path if the folder is not in the same  directory
+ * Include the path if the folder is not in the same directory
  * as this file.
  */
 	$system_path = 'system';
@@ -220,28 +220,28 @@
 			$application_folder = $_temp;
 		}
 
-		define('APPPATH', $application_folder.'/');
+		define('APPPATH', $application_folder.DIRECTORY_SEPARATOR);
 	}
 	else
 	{
-		if ( ! is_dir(BASEPATH.$application_folder.'/'))
+		if ( ! is_dir(BASEPATH.$application_folder.DIRECTORY_SEPARATOR))
 		{
 			header('HTTP/1.1 503 Service Unavailable.', TRUE, 503);
 			echo 'Your application folder path does not appear to be set correctly. Please open the following file and correct this: '.SELF;
 			exit(3); // EXIT_* constants not yet defined; 3 is EXIT_CONFIG.
 		}
 
-		define('APPPATH', BASEPATH.$application_folder.'/');
+		define('APPPATH', BASEPATH.$application_folder.DIRECTORY_SEPARATOR);
 	}
 
 	// The path to the "views" folder
 	if ( ! is_dir($view_folder))
 	{
-		if ( ! empty($view_folder) && is_dir(APPPATH.$view_folder.'/'))
+		if ( ! empty($view_folder) && is_dir(APPPATH.$view_folder.DIRECTORY_SEPARATOR))
 		{
 			$view_folder = APPPATH.$view_folder;
 		}
-		elseif ( ! is_dir(APPPATH.'views/'))
+		elseif ( ! is_dir(APPPATH.'views'.DIRECTORY_SEPARATOR))
 		{
 			header('HTTP/1.1 503 Service Unavailable.', TRUE, 503);
 			echo 'Your view folder path does not appear to be set correctly. Please open the following file and correct this: '.SELF;
@@ -255,11 +255,11 @@
 
 	if (($_temp = realpath($view_folder)) !== FALSE)
 	{
-		$view_folder = $_temp.'/';
+		$view_folder = $_temp.DIRECTORY_SEPARATOR;
 	}
 	else
 	{
-		$view_folder = rtrim($view_folder, '/').'/';
+		$view_folder = rtrim($view_folder, '/\\').DIRECTORY_SEPARATOR;
 	}
 
 	define('VIEWPATH', $view_folder);
@@ -274,4 +274,4 @@
 require_once BASEPATH.'core/CodeIgniter.php';
 
 /* End of file index.php */
-/* Location: ./index.php */
+/* Location: ./index.php */
\ No newline at end of file
diff --git a/readme.rst b/readme.rst
index d768162..b4984ea 100644
--- a/readme.rst
+++ b/readme.rst
@@ -14,7 +14,7 @@
 Release Information
 *******************
 
-This repo contains in development code for future releases. To download the
+This repo contains in-development code for future releases. To download the
 latest stable release please visit the `CodeIgniter Downloads
 <http://codeigniter.com/downloads/>`_ page.
 
@@ -49,9 +49,9 @@
 Resources
 *********
 
--  `User Guide <http://codeigniter.com/user_guide/>`_
--  `Community Forums <http://codeigniter.com/forums/>`_
--  `Community Wiki <http://codeigniter.com/wiki/>`_
+-  `User Guide <http://ellislab.com/codeigniter/user_guide/>`_
+-  `Community Forums <http://ellislab.com/forums/>`_
+-  `Community Wiki <https://github.com/EllisLab/CodeIgniter/wiki/>`_
 -  `Community IRC <http://ellislab.com/codeigniter/irc>`_
 
 ***************
diff --git a/system/core/CodeIgniter.php b/system/core/CodeIgniter.php
index c682664..74a9eb0 100644
--- a/system/core/CodeIgniter.php
+++ b/system/core/CodeIgniter.php
@@ -48,6 +48,18 @@
 
 /*
  * ------------------------------------------------------
+ *  Load the framework constants
+ * ------------------------------------------------------
+ */
+	if (file_exists(APPPATH.'config/'.ENVIRONMENT.'/constants.php'))
+	{
+		require_once(APPPATH.'config/'.ENVIRONMENT.'/constants.php');
+	}
+
+	require_once(APPPATH.'config/constants.php');
+
+/*
+ * ------------------------------------------------------
  *  Load the global functions
  * ------------------------------------------------------
  */
@@ -55,29 +67,14 @@
 
 /*
  * ------------------------------------------------------
- *  Load the framework constants
- * ------------------------------------------------------
- */
-	if (file_exists(APPPATH.'config/'.ENVIRONMENT.'/constants.php'))
-	{
-		require(APPPATH.'config/'.ENVIRONMENT.'/constants.php');
-	}
-	else
-	{
-		require(APPPATH.'config/constants.php');
-	}
-
-/*
- * ------------------------------------------------------
  *  Define a custom error handler so we can log PHP errors
  * ------------------------------------------------------
  */
 	set_error_handler('_exception_handler');
+	register_shutdown_function('_shutdown_handler');
 
-	if ( ! is_php('5.4'))
-	{
-		@ini_set('magic_quotes_runtime', 0); // Kill magic quotes
-	}
+	// Kill magic quotes
+	is_php('5.4') OR @ini_set('magic_quotes_runtime', 0);
 
 /*
  * ------------------------------------------------------
@@ -88,7 +85,7 @@
  * The subclass prefix allows CI to know if a core class is
  * being extended via a library in the local application
  * "libraries" folder. Since CI allows config items to be
- * overriden via data set in the main index. php file,
+ * overriden via data set in the main index.php file,
  * before proceeding we need to know if a subclass_prefix
  * override exists. If so, we will set this value now,
  * before any classes are loaded
@@ -166,12 +163,6 @@
  */
 	$RTR =& load_class('Router', 'core');
 
-	// Set any routing overrides that may exist in the main index file
-	if (isset($routing))
-	{
-		$RTR->_set_overrides($routing);
-	}
-
 /*
  * ------------------------------------------------------
  *  Instantiate the output class
@@ -218,7 +209,7 @@
  *
  */
 	// Load the base controller class
-	require BASEPATH.'core/Controller.php';
+	require_once BASEPATH.'core/Controller.php';
 
 	/**
 	 * Reference to the CI_Controller method.
@@ -234,92 +225,117 @@
 
 	if (file_exists(APPPATH.'core/'.$CFG->config['subclass_prefix'].'Controller.php'))
 	{
-		require APPPATH.'core/'.$CFG->config['subclass_prefix'].'Controller.php';
+		require_once APPPATH.'core/'.$CFG->config['subclass_prefix'].'Controller.php';
 	}
 
-	// Load the local application controller
-	// Note: The Router class automatically validates the controller path using the router->_validate_request().
-	// If this include fails it means that the default controller in the Routes.php file is not resolving to something valid.
-	if ( ! file_exists(APPPATH.'controllers/'.$RTR->directory.$RTR->class.'.php'))
-	{
-		show_error('Unable to load your default controller. Please make sure the controller specified in your Routes.php file is valid.');
-	}
-
-	include(APPPATH.'controllers/'.$RTR->directory.$RTR->class.'.php');
-
 	// Set a mark point for benchmarking
 	$BM->mark('loading_time:_base_classes_end');
 
 /*
  * ------------------------------------------------------
- *  Security check
+ *  Sanity checks
  * ------------------------------------------------------
  *
- *  None of the methods in the app controller or the
- *  loader class can be called via the URI, nor can
- *  controller functions that begin with an underscore.
+ *  The Router class has already validated the request,
+ *  leaving us with 3 options here:
+ *
+ *	1) an empty class name, if we reached the default
+ *	   controller, but it didn't exist;
+ *	2) a query string which doesn't go through a
+ *	   file_exists() check
+ *	3) a regular request for a non-existing page
+ *
+ *  We handle all of these as a 404 error.
+ *
+ *  Furthermore, none of the methods in the app controller
+ *  or the loader class can be called via the URI, nor can
+ *  controller methods that begin with an underscore.
  */
-	$class	= $RTR->class;
-	$method	= $RTR->method;
 
-	if ( ! class_exists($class, FALSE) OR $method[0] === '_' OR method_exists('CI_Controller', $method))
+	$e404 = FALSE;
+	$class = ucfirst($RTR->class);
+	$method = $RTR->method;
+
+	if (empty($class) OR ! file_exists(APPPATH.'controllers/'.$RTR->directory.$class.'.php'))
 	{
-		if ( ! empty($RTR->routes['404_override']))
-		{
-			if (sscanf($RTR->routes['404_override'], '%[^/]/%s', $class, $method) !== 2)
-			{
-				$method = 'index';
-			}
-
-			if ( ! class_exists($class, FALSE))
-			{
-				if ( ! file_exists(APPPATH.'controllers/'.$class.'.php'))
-				{
-					show_404($class.'/'.$method);
-				}
-
-				include_once(APPPATH.'controllers/'.$class.'.php');
-			}
-		}
-		else
-		{
-			show_404($class.'/'.$method);
-		}
-	}
-
-	if (method_exists($class, '_remap'))
-	{
-		$params = array($method, array_slice($URI->rsegments, 2));
-		$method = '_remap';
+		$e404 = TRUE;
 	}
 	else
 	{
+		require_once(APPPATH.'controllers/'.$RTR->directory.$class.'.php');
+
+		if ( ! class_exists($class, FALSE) OR $method[0] === '_' OR method_exists('CI_Controller', $method))
+		{
+			$e404 = TRUE;
+		}
+		elseif (method_exists($class, '_remap'))
+		{
+			$params = array($method, array_slice($URI->rsegments, 2));
+			$method = '_remap';
+		}
 		// WARNING: It appears that there are issues with is_callable() even in PHP 5.2!
 		// Furthermore, there are bug reports and feature/change requests related to it
 		// that make it unreliable to use in this context. Please, DO NOT change this
 		// work-around until a better alternative is available.
-		if ( ! in_array(strtolower($method), array_map('strtolower', get_class_methods($class)), TRUE))
+		elseif ( ! in_array(strtolower($method), array_map('strtolower', get_class_methods($class)), TRUE))
 		{
-			if (empty($RTR->routes['404_override']))
+			$e404 = TRUE;
+		}
+	}
+
+	if ($e404)
+	{
+		if ( ! empty($RTR->routes['404_override']))
+		{
+			if (sscanf($RTR->routes['404_override'], '%[^/]/%s', $error_class, $error_method) !== 2)
 			{
-				show_404($class.'/'.$method);
-			}
-			elseif (sscanf($RTR->routes['404_override'], '%[^/]/%s', $class, $method) !== 2)
-			{
-				$method = 'index';
+				$error_method = 'index';
 			}
 
-			if ( ! class_exists($class, FALSE))
+			$error_class = ucfirst($error_class);
+
+			if ( ! class_exists($error_class, FALSE))
 			{
-				if ( ! file_exists(APPPATH.'controllers/'.$class.'.php'))
+				if (file_exists(APPPATH.'controllers/'.$RTR->directory.$error_class.'.php'))
 				{
-					show_404($class.'/'.$method);
+					require_once(APPPATH.'controllers/'.$RTR->directory.$error_class.'.php');
+					$e404 = ! class_exists($error_class, FALSE);
 				}
-
-				include_once(APPPATH.'controllers/'.$class.'.php');
+				// Were we in a directory? If so, check for a global override
+				elseif ( ! empty($RTR->directory) && file_exists(APPPATH.'controllers/'.$error_class.'.php'))
+				{
+					require_once(APPPATH.'controllers/'.$error_class.'.php');
+					if (($e404 = ! class_exists($error_class, FALSE)) === FALSE)
+					{
+						$RTR->directory = '';
+					}
+				}
+			}
+			else
+			{
+				$e404 = FALSE;
 			}
 		}
 
+		// Did we reset the $e404 flag? If so, set the rsegments, starting from index 1
+		if ( ! $e404)
+		{
+			$class = $error_class;
+			$method = $error_method;
+
+			$URI->rsegments = array(
+				1 => $class,
+				2 => $method
+			);
+		}
+		else
+		{
+			show_404($RTR->directory.$class.'/'.$method);
+		}
+	}
+
+	if ($method !== '_remap')
+	{
 		$params = array_slice($URI->rsegments, 2);
 	}
 
diff --git a/system/core/Common.php b/system/core/Common.php
index b95a05d..00e3030 100644
--- a/system/core/Common.php
+++ b/system/core/Common.php
@@ -82,7 +82,7 @@
 	function is_really_writable($file)
 	{
 		// If we're on a Unix server with safe_mode off we call is_writable
-		if (DIRECTORY_SEPARATOR === '/' && (bool) @ini_get('safe_mode') === FALSE)
+		if (DIRECTORY_SEPARATOR === '/' && (is_php('5.4') OR (bool) @ini_get('safe_mode') === FALSE))
 		{
 			return is_writable($file);
 		}
@@ -224,56 +224,51 @@
 	 * @param	array
 	 * @return	array
 	 */
-	function &get_config($replace = array())
+	function &get_config(Array $replace = array())
 	{
 		static $_config;
 
-		if (isset($_config))
+		if (empty($_config))
 		{
-			return $_config[0];
-		}
-
-		$file_path = APPPATH.'config/config.php';
-		$found = FALSE;
-		if (file_exists($file_path))
-		{
-			$found = TRUE;
-			require($file_path);
-		}
-
-		// Is the config file in the environment folder?
-		if (file_exists($file_path = APPPATH.'config/'.ENVIRONMENT.'/config.php'))
-		{
-			require($file_path);
-		}
-		elseif ( ! $found)
-		{
-			set_status_header(503);
-			echo 'The configuration file does not exist.';
-			exit(EXIT_CONFIG);
-		}
-
-		// Does the $config array exist in the file?
-		if ( ! isset($config) OR ! is_array($config))
-		{
-			set_status_header(503);
-			echo 'Your config file does not appear to be formatted correctly.';
-			exit(EXIT_CONFIG);
-		}
-
-		// Are any values being dynamically replaced?
-		if (count($replace) > 0)
-		{
-			foreach ($replace as $key => $val)
+			$file_path = APPPATH.'config/config.php';
+			$found = FALSE;
+			if (file_exists($file_path))
 			{
-				if (isset($config[$key]))
-				{
-					$config[$key] = $val;
-				}
+				$found = TRUE;
+				require($file_path);
 			}
+
+			// Is the config file in the environment folder?
+			if (file_exists($file_path = APPPATH.'config/'.ENVIRONMENT.'/config.php'))
+			{
+				require($file_path);
+			}
+			elseif ( ! $found)
+			{
+				set_status_header(503);
+				echo 'The configuration file does not exist.';
+				exit(EXIT_CONFIG);
+			}
+
+			// Does the $config array exist in the file?
+			if ( ! isset($config) OR ! is_array($config))
+			{
+				set_status_header(503);
+				echo 'Your config file does not appear to be formatted correctly.';
+				exit(EXIT_CONFIG);
+			}
+
+			// references cannot be directly assigned to static variables, so we use an array
+			$_config[0] =& $config;
 		}
 
-		return $_config[0] =& $config;
+		// Are any values being dynamically added or replaced?
+		foreach ($replace as $key => $val)
+		{
+			$_config[0][$key] = $val;
+		}
+
+		return $_config[0];
 	}
 }
 
@@ -360,6 +355,24 @@
 
 // ------------------------------------------------------------------------
 
+if ( ! function_exists('is_cli'))
+{
+
+	/**
+	 * Is CLI?
+	 *
+	 * Test to see if a request was made from the command line.
+	 *
+	 * @return 	bool
+	 */
+	function is_cli()
+	{
+		return (PHP_SAPI === 'cli' OR defined('STDIN'));
+	}
+}
+
+// ------------------------------------------------------------------------
+
 if ( ! function_exists('show_error'))
 {
 	/**
@@ -434,29 +447,19 @@
 	 *
 	 * @param	string	the error level: 'error', 'debug' or 'info'
 	 * @param	string	the error message
-	 * @param	bool	whether the error is a native PHP error
 	 * @return	void
 	 */
-	function log_message($level, $message, $php_error = FALSE)
+	function log_message($level, $message)
 	{
-		static $_log, $_log_threshold;
-
-		if ($_log_threshold === NULL)
-		{
-			$_log_threshold = config_item('log_threshold');
-		}
-
-		if ($_log_threshold === 0)
-		{
-			return;
-		}
+		static $_log;
 
 		if ($_log === NULL)
 		{
-			$_log =& load_class('Log', 'core');
+			// references cannot be directly assigned to static variables, so we use an array
+			$_log[0] =& load_class('Log', 'core');
 		}
 
-		$_log->write_log($level, $message, $php_error);
+		$_log[0]->write_log($level, $message);
 	}
 }
 
@@ -538,7 +541,7 @@
 
 		$server_protocol = isset($_SERVER['SERVER_PROTOCOL']) ? $_SERVER['SERVER_PROTOCOL'] : FALSE;
 
-		if (strpos(php_sapi_name(), 'cgi') === 0)
+		if (strpos(PHP_SAPI, 'cgi') === 0)
 		{
 			header('Status: '.$code.' '.$text, TRUE);
 		}
@@ -556,22 +559,35 @@
 	/**
 	 * Exception Handler
 	 *
-	 * This is the custom exception handler that is declaired at the top
-	 * of Codeigniter.php. The main reason we use this is to permit
+	 * This is the custom exception handler that is declared at the top
+	 * of CodeIgniter.php. The main reason we use this is to permit
 	 * PHP errors to be logged in our own log files since the user may
 	 * not have access to server logs. Since this function
 	 * effectively intercepts PHP errors, however, we also need
 	 * to display errors based on the current error_reporting level.
 	 * We do that with the use of a PHP error template.
 	 *
-	 * @param	int
-	 * @param	string
-	 * @param	string
-	 * @param	int
+	 * @param	int	$severity
+	 * @param	string	$message
+	 * @param	string	$filepath
+	 * @param	int	$line
 	 * @return	void
 	 */
 	function _exception_handler($severity, $message, $filepath, $line)
 	{
+		$is_error = (((E_ERROR | E_COMPILE_ERROR | E_CORE_ERROR | E_USER_ERROR) & $severity) === $severity);
+
+		// When an error occurred, set the status header to '500 Internal Server Error'
+		// to indicate to the client something went wrong.
+		// This can't be done within the $_error->show_php_error method because
+		// it is only called when the display_errors flag is set (which isn't usually
+		// the case in a production environment) or when errors are ignored because
+		// they are above the error_reporting threshold.
+		if ($is_error)
+		{
+			set_status_header(500);
+		}
+
 		$_error =& load_class('Exceptions', 'core');
 
 		// Should we ignore the error? We'll get the current error_reporting
@@ -588,6 +604,42 @@
 		}
 
 		$_error->log_exception($severity, $message, $filepath, $line);
+
+		// If the error is fatal, the execution of the script should be stopped because
+		// errors can't be recovered from. Halting the script conforms with PHP's
+		// default error handling. See http://www.php.net/manual/en/errorfunc.constants.php
+		if ($is_error)
+		{
+			exit(EXIT_ERROR);
+		}
+	}
+}
+
+// ------------------------------------------------------------------------
+
+if ( ! function_exists('_shutdown_handler'))
+{
+	/**
+	 * Shutdown Handler
+	 *
+	 * This is the shutdown handler that is declared at the top
+	 * of CodeIgniter.php. The main reason we use this is to simulate
+	 * a complete custom exception handler.
+	 *
+	 * E_STRICT is purposivly neglected because such events may have
+	 * been caught. Duplication or none? None is preferred for now.
+	 *
+	 * @link	http://insomanic.me.uk/post/229851073/php-trick-catching-fatal-errors-e-error-with-a
+	 * @return	void
+	 */
+	function _shutdown_handler()
+	{
+		$last_error = error_get_last();
+		if (isset($last_error) &&
+			($last_error['type'] & (E_ERROR | E_PARSE | E_CORE_ERROR | E_CORE_WARNING | E_COMPILE_ERROR | E_COMPILE_WARNING)))
+		{
+			_exception_handler($last_error['type'], $last_error['message'], $last_error['file'], $last_error['line']);
+		}
 	}
 }
 
diff --git a/system/core/Config.php b/system/core/Config.php
index 7e64444..a0e830a 100644
--- a/system/core/Config.php
+++ b/system/core/Config.php
@@ -184,16 +184,16 @@
 	 *
 	 * @param	string	$item	Config item name
 	 * @param	string	$index	Index name
-	 * @return	string|bool	The configuration item or FALSE on failure
+	 * @return	string|null	The configuration item or NULL if the item doesn't exist
 	 */
 	public function item($item, $index = '')
 	{
 		if ($index == '')
 		{
-			return isset($this->config[$item]) ? $this->config[$item] : FALSE;
+			return isset($this->config[$item]) ? $this->config[$item] : NULL;
 		}
 
-		return isset($this->config[$index], $this->config[$index][$item]) ? $this->config[$index][$item] : FALSE;
+		return isset($this->config[$index], $this->config[$index][$item]) ? $this->config[$index][$item] : NULL;
 	}
 
 	// --------------------------------------------------------------------
@@ -202,13 +202,13 @@
 	 * Fetch a config file item with slash appended (if not empty)
 	 *
 	 * @param	string		$item	Config item name
-	 * @return	string|bool	The configuration item or FALSE on failure
+	 * @return	string|null	The configuration item or NULL if the item doesn't exist
 	 */
 	public function slash_item($item)
 	{
 		if ( ! isset($this->config[$item]))
 		{
-			return FALSE;
+			return NULL;
 		}
 		elseif (trim($this->config[$item]) === '')
 		{
@@ -228,13 +228,21 @@
 	 * @uses	CI_Config::_uri_string()
 	 *
 	 * @param	string|string[]	$uri	URI string or an array of segments
+	 * @param	string	$protocol
 	 * @return	string
 	 */
-	public function site_url($uri = '')
+	public function site_url($uri = '', $protocol = NULL)
 	{
+		$base_url = $this->slash_item('base_url');
+
+		if (isset($protocol))
+		{
+			$base_url = $protocol.substr($base_url, strpos($base_url, '://'));
+		}
+
 		if (empty($uri))
 		{
-			return $this->slash_item('base_url').$this->item('index_page');
+			return $base_url.$this->item('index_page');
 		}
 
 		$uri = $this->_uri_string($uri);
@@ -255,14 +263,14 @@
 				}
 			}
 
-			return $this->slash_item('base_url').$this->slash_item('index_page').$uri;
+			return $base_url.$this->slash_item('index_page').$uri;
 		}
 		elseif (strpos($uri, '?') === FALSE)
 		{
 			$uri = '?'.$uri;
 		}
 
-		return $this->slash_item('base_url').$this->item('index_page').$uri;
+		return $base_url.$this->item('index_page').$uri;
 	}
 
 	// -------------------------------------------------------------
@@ -275,11 +283,19 @@
 	 * @uses	CI_Config::_uri_string()
 	 *
 	 * @param	string|string[]	$uri	URI string or an array of segments
+	 * @param	string	$protocol
 	 * @return	string
 	 */
-	public function base_url($uri = '')
+	public function base_url($uri = '', $protocol = NULL)
 	{
-		return $this->slash_item('base_url').ltrim($this->_uri_string($uri), '/');
+		$base_url = $this->slash_item('base_url');
+
+		if (isset($protocol))
+		{
+			$base_url = $protocol.substr($base_url, strpos($base_url, '://'));
+		}
+
+		return $base_url.ltrim($this->_uri_string($uri), '/');
 	}
 
 	// -------------------------------------------------------------
diff --git a/system/core/Exceptions.php b/system/core/Exceptions.php
index 9c68d06..809dc02 100644
--- a/system/core/Exceptions.php
+++ b/system/core/Exceptions.php
@@ -91,7 +91,7 @@
 	public function log_exception($severity, $message, $filepath, $line)
 	{
 		$severity = isset($this->levels[$severity]) ? $this->levels[$severity] : $severity;
-		log_message('error', 'Severity: '.$severity.'  --> '.$message. ' '.$filepath.' '.$line, TRUE);
+		log_message('error', 'Severity: '.$severity.' --> '.$message.' '.$filepath.' '.$line);
 	}
 
 	// --------------------------------------------------------------------
@@ -107,13 +107,21 @@
 	 */
 	public function show_404($page = '', $log_error = TRUE)
 	{
-		$heading = '404 Page Not Found';
-		$message = 'The page you requested was not found.';
+		if (is_cli())
+		{
+			$heading = 'Not Found';
+			$message = 'The controller/method pair you requested was not found.';
+		}
+		else
+		{
+			$heading = '404 Page Not Found';
+			$message = 'The page you requested was not found.';
+		}
 
 		// By default we log this, but allow a dev to skip it
 		if ($log_error)
 		{
-			log_message('error', '404 Page Not Found --> '.$page);
+			log_message('error', $heading.': '.$page);
 		}
 
 		echo $this->show_error($heading, $message, 'error_404', 404);
@@ -137,16 +145,24 @@
 	 */
 	public function show_error($heading, $message, $template = 'error_general', $status_code = 500)
 	{
-		set_status_header($status_code);
-
-		$message = '<p>'.implode('</p><p>', is_array($message) ? $message : array($message)).'</p>';
+		if (is_cli())
+		{
+			$message = "\t".(is_array($message) ? implode("\n\t", $message) : $message);
+			$template = 'cli'.DIRECTORY_SEPARATOR.$template;
+		}
+		else
+		{
+			set_status_header($status_code);
+			$message = '<p>'.(is_array($message) ? implode('</p><p>', $message) : $message).'</p>';
+			$template = 'html'.DIRECTORY_SEPARATOR.$template;
+		}
 
 		if (ob_get_level() > $this->ob_level + 1)
 		{
 			ob_end_flush();
 		}
 		ob_start();
-		include(VIEWPATH.'errors/'.$template.'.php');
+		include(VIEWPATH.'errors'.DIRECTORY_SEPARATOR.$template.'.php');
 		$buffer = ob_get_contents();
 		ob_end_clean();
 		return $buffer;
@@ -166,13 +182,22 @@
 	public function show_php_error($severity, $message, $filepath, $line)
 	{
 		$severity = isset($this->levels[$severity]) ? $this->levels[$severity] : $severity;
-		$filepath = str_replace('\\', '/', $filepath);
 
-		// For safety reasons we do not show the full file path
-		if (FALSE !== strpos($filepath, '/'))
+		// For safety reasons we don't show the full file path in non-CLI requests
+		if ( ! is_cli())
 		{
-			$x = explode('/', $filepath);
-			$filepath = $x[count($x)-2].'/'.end($x);
+			$filepath = str_replace('\\', '/', $filepath);
+			if (FALSE !== strpos($filepath, '/'))
+			{
+				$x = explode('/', $filepath);
+				$filepath = $x[count($x)-2].'/'.end($x);
+			}
+
+			$template = 'html'.DIRECTORY_SEPARATOR.'error_php';
+		}
+		else
+		{
+			$template = 'cli'.DIRECTORY_SEPARATOR.'error_php';
 		}
 
 		if (ob_get_level() > $this->ob_level + 1)
@@ -180,7 +205,7 @@
 			ob_end_flush();
 		}
 		ob_start();
-		include(VIEWPATH.'errors/error_php.php');
+		include(VIEWPATH.'errors'.DIRECTORY_SEPARATOR.$template.'.php');
 		$buffer = ob_get_contents();
 		ob_end_clean();
 		echo $buffer;
diff --git a/system/core/Hooks.php b/system/core/Hooks.php
index b3b1119..9bcc23a 100644
--- a/system/core/Hooks.php
+++ b/system/core/Hooks.php
@@ -54,6 +54,13 @@
 	public $hooks =	array();
 
 	/**
+	 * Array with class objects to use hooks methods
+	 *
+	 * @var array
+	 */
+	protected $_objects = array();
+
+	/**
 	 * In progress flag
 	 *
 	 * Determines whether hook is in progress, used to prevent infinte loops
@@ -184,7 +191,7 @@
 		$function	= empty($data['function']) ? FALSE : $data['function'];
 		$params		= isset($data['params']) ? $data['params'] : '';
 
-		if ($class === FALSE && $function === FALSE)
+		if (empty($function))
 		{
 			return FALSE;
 		}
@@ -195,19 +202,39 @@
 		// Call the requested class and/or function
 		if ($class !== FALSE)
 		{
-			if ( ! class_exists($class, FALSE))
+			// The object is stored?
+			if (isset($this->_objects[$class]))
 			{
-				require($filepath);
+				if (method_exists($this->_objects[$class], $function))
+				{
+					$this->_objects[$class]->$function($params);
+				}
+				else
+				{
+					return $this->_in_progress = FALSE;
+				}
 			}
+			else
+			{
+				class_exists($class, FALSE) OR require_once($filepath);
 
-			$HOOK = new $class();
-			$HOOK->$function($params);
+				if ( ! class_exists($class, FALSE) OR ! method_exists($class, $function))
+				{
+					return $this->_in_progress = FALSE;
+				}
+
+				// Store the object and execute the method
+				$this->_objects[$class] = new $class();
+				$this->_objects[$class]->$function($params);
+			}
 		}
 		else
 		{
+			function_exists($function) OR require_once($filepath);
+
 			if ( ! function_exists($function))
 			{
-				require($filepath);
+				return $this->_in_progress = FALSE;
 			}
 
 			$function($params);
diff --git a/system/core/Input.php b/system/core/Input.php
index 0ef8112..ccb70da 100644
--- a/system/core/Input.php
+++ b/system/core/Input.php
@@ -47,7 +47,7 @@
 	public $ip_address = FALSE;
 
 	/**
-	 * User agent strin
+	 * User agent string
 	 *
 	 * @var	string
 	 */
@@ -63,7 +63,7 @@
 	protected $_allow_get_array = TRUE;
 
 	/**
-	 * Standartize new lines flag
+	 * Standardize new lines flag
 	 *
 	 * If set to TRUE, then newlines are standardized.
 	 *
@@ -121,9 +121,10 @@
 	{
 		log_message('debug', 'Input Class Initialized');
 
-		$this->_allow_get_array	= (config_item('allow_get_array') === TRUE);
-		$this->_enable_xss	= (config_item('global_xss_filtering') === TRUE);
-		$this->_enable_csrf	= (config_item('csrf_protection') === TRUE);
+		$this->_allow_get_array		= (config_item('allow_get_array') === TRUE);
+		$this->_enable_xss		= (config_item('global_xss_filtering') === TRUE);
+		$this->_enable_csrf		= (config_item('csrf_protection') === TRUE);
+		$this->_sandardize_newlines	= (bool) config_item('standardize_newlines');
 
 		global $SEC;
 		$this->security =& $SEC;
@@ -151,8 +152,10 @@
 	 * @param	bool	$xss_clean	Whether to apply XSS filtering
 	 * @return	mixed
 	 */
-	protected function _fetch_from_array(&$array, $index = '', $xss_clean = FALSE)
+	protected function _fetch_from_array(&$array, $index = '', $xss_clean = NULL)
 	{
+		is_bool($xss_clean) OR $xss_clean = $this->_enable_xss;
+
 		if (isset($array[$index]))
 		{
 			$value = $array[$index];
@@ -197,8 +200,10 @@
 	 * @param	bool	$xss_clean	Whether to apply XSS filtering
 	 * @return	mixed
 	 */
-	public function get($index = NULL, $xss_clean = FALSE)
+	public function get($index = NULL, $xss_clean = NULL)
 	{
+		is_bool($xss_clean) OR $xss_clean = $this->_enable_xss;
+
 		// Check if a field has been provided
 		if ($index === NULL)
 		{
@@ -229,8 +234,10 @@
 	 * @param	bool	$xss_clean	Whether to apply XSS filtering
 	 * @return	mixed
 	 */
-	public function post($index = NULL, $xss_clean = FALSE)
+	public function post($index = NULL, $xss_clean = NULL)
 	{
+		is_bool($xss_clean) OR $xss_clean = $this->_enable_xss;
+
 		// Check if a field has been provided
 		if ($index === NULL)
 		{
@@ -261,8 +268,10 @@
 	 * @param	bool	$xss_clean	Whether to apply XSS filtering
 	 * @return	mixed
 	 */
-	public function get_post($index = '', $xss_clean = FALSE)
+	public function post_get($index = '', $xss_clean = NULL)
 	{
+		is_bool($xss_clean) OR $xss_clean = $this->_enable_xss;
+
 		return isset($_POST[$index])
 			? $this->post($index, $xss_clean)
 			: $this->get($index, $xss_clean);
@@ -271,14 +280,34 @@
 	// --------------------------------------------------------------------
 
 	/**
+	 * Fetch an item from GET data with fallback to POST
+	 *
+	 * @param	string	$index		Index for item to be fetched from $_GET or $_POST
+	 * @param	bool	$xss_clean	Whether to apply XSS filtering
+	 * @return	mixed
+	 */
+	public function get_post($index = '', $xss_clean = NULL)
+	{
+		is_bool($xss_clean) OR $xss_clean = $this->_enable_xss;
+
+		return isset($_GET[$index])
+			? $this->get($index, $xss_clean)
+			: $this->post($index, $xss_clean);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
 	 * Fetch an item from the COOKIE array
 	 *
 	 * @param	string	$index		Index for item to be fetched from $_COOKIE
 	 * @param	bool	$xss_clean	Whether to apply XSS filtering
 	 * @return	mixed
 	 */
-	public function cookie($index = '', $xss_clean = FALSE)
+	public function cookie($index = '', $xss_clean = NULL)
 	{
+		is_bool($xss_clean) OR $xss_clean = $this->_enable_xss;
+
 		return $this->_fetch_from_array($_COOKIE, $index, $xss_clean);
 	}
 
@@ -291,8 +320,10 @@
 	 * @param	bool	$xss_clean	Whether to apply XSS filtering
 	 * @return	mixed
 	 */
-	public function server($index = '', $xss_clean = FALSE)
+	public function server($index = '', $xss_clean = NULL)
 	{
+		is_bool($xss_clean) OR $xss_clean = $this->_enable_xss;
+
 		return $this->_fetch_from_array($_SERVER, $index, $xss_clean);
 	}
 
@@ -307,8 +338,10 @@
 	 * @param	bool	$xss_clean	Whether to apply XSS filtering
 	 * @return	mixed
 	 */
-	public function input_stream($index = '', $xss_clean = FALSE)
+	public function input_stream($index = '', $xss_clean = NULL)
 	{
+		is_bool($xss_clean) OR $xss_clean = $this->_enable_xss;
+
 		// The input stream can only be read once, so we'll need to check
 		// if we have already done that first.
 		if (is_array($this->_input_stream))
@@ -345,7 +378,7 @@
 	 * @param	bool		$httponly	Whether to only makes the cookie accessible via HTTP (no javascript)
 	 * @return	void
 	 */
-	public function set_cookie($name = '', $value = '', $expire = '', $domain = '', $path = '/', $prefix = '', $secure = FALSE, $httponly = FALSE)
+	public function set_cookie($name, $value = '', $expire = '', $domain = '', $path = '/', $prefix = '', $secure = FALSE, $httponly = FALSE)
 	{
 		if (is_array($name))
 		{
@@ -671,13 +704,22 @@
 			// but that when present will trip our 'Disallowed Key Characters' alarm
 			// http://www.ietf.org/rfc/rfc2109.txt
 			// note that the key names below are single quoted strings, and are not PHP variables
-			unset($_COOKIE['$Version']);
-			unset($_COOKIE['$Path']);
-			unset($_COOKIE['$Domain']);
+			unset(
+				$_COOKIE['$Version'],
+				$_COOKIE['$Path'],
+				$_COOKIE['$Domain']
+			);
 
 			foreach ($_COOKIE as $key => $val)
 			{
-				$_COOKIE[$this->_clean_input_keys($key)] = $this->_clean_input_data($val);
+				if (($cookie_key = $this->_clean_input_keys($key)) !== FALSE)
+				{
+					$_COOKIE[$cookie_key] = $this->_clean_input_data($val);
+				}
+				else
+				{
+					unset($_COOKIE[$key]);
+				}
 			}
 		}
 
@@ -685,12 +727,12 @@
 		$_SERVER['PHP_SELF'] = strip_tags($_SERVER['PHP_SELF']);
 
 		// CSRF Protection check
-		if ($this->_enable_csrf === TRUE && ! $this->is_cli_request())
+		if ($this->_enable_csrf === TRUE && ! is_cli())
 		{
 			$this->security->csrf_verify();
 		}
 
-		log_message('debug', 'Global POST and COOKIE data sanitized');
+		log_message('debug', 'Global POST, GET and COOKIE data sanitized');
 	}
 
 	// --------------------------------------------------------------------
@@ -733,13 +775,7 @@
 		}
 
 		// Remove control characters
-		$str = remove_invisible_characters($str);
-
-		// Should we filter the input data?
-		if ($this->_enable_xss === TRUE)
-		{
-			$str = $this->security->xss_clean($str);
-		}
+		$str = remove_invisible_characters($str, FALSE);
 
 		// Standardize newlines if needed
 		if ($this->_standardize_newlines === TRUE)
@@ -760,15 +796,25 @@
 	 * only named with alpha-numeric text and a few other items.
 	 *
 	 * @param	string	$str	Input string
-	 * @return	string
+	 * @param	string	$fatal	Whether to terminate script exection
+	 *				or to return FALSE if an invalid
+	 *				key is encountered
+	 * @return	string|bool
 	 */
-	protected function _clean_input_keys($str)
+	protected function _clean_input_keys($str, $fatal = TRUE)
 	{
 		if ( ! preg_match('/^[a-z0-9:_\/|-]+$/i', $str))
 		{
-			set_status_header(503);
-			echo 'Disallowed Key Characters.';
-			exit(EXIT_USER_INPUT);
+			if ($fatal === TRUE)
+			{
+				return FALSE;
+			}
+			else
+			{
+				set_status_header(503);
+				echo 'Disallowed Key Characters.';
+				exit(EXIT_USER_INPUT);
+			}
 		}
 
 		// Clean UTF-8 if supported
@@ -868,11 +914,12 @@
 	 *
 	 * Test to see if a request was made from the command line.
 	 *
-	 * @return 	bool
+	 * @deprecated	3.0.0	Use is_cli() instead
+	 * @return      bool
 	 */
 	public function is_cli_request()
 	{
-		return (php_sapi_name() === 'cli' OR defined('STDIN'));
+		return is_cli();
 	}
 
 	// --------------------------------------------------------------------
diff --git a/system/core/Lang.php b/system/core/Lang.php
index 3236709..290b38b 100644
--- a/system/core/Lang.php
+++ b/system/core/Lang.php
@@ -166,7 +166,7 @@
 	 * @param	bool	$log_errors	Whether to log an error message if the line is not found
 	 * @return	string	Translation
 	 */
-	public function line($line = '', $log_errors = TRUE)
+	public function line($line, $log_errors = TRUE)
 	{
 		$value = ($line === '' OR ! isset($this->language[$line])) ? FALSE : $this->language[$line];
 
diff --git a/system/core/Loader.php b/system/core/Loader.php
index 70a6b6f..8c8d5a3 100644
--- a/system/core/Loader.php
+++ b/system/core/Loader.php
@@ -76,13 +76,6 @@
 	protected $_ci_helper_paths =	array(APPPATH, BASEPATH);
 
 	/**
-	 * List of loaded base classes
-	 *
-	 * @var	array
-	 */
-	protected $_base_classes =	array(); // Set by the controller class
-
-	/**
 	 * List of cached variables
 	 *
 	 * @var	array
@@ -120,6 +113,8 @@
 		'user_agent' => 'agent'
 	);
 
+	// --------------------------------------------------------------------
+
 	/**
 	 * Class constructor
 	 *
@@ -129,7 +124,8 @@
 	 */
 	public function __construct()
 	{
-		$this->_ci_ob_level  = ob_get_level();
+		$this->_ci_ob_level = ob_get_level();
+		$this->_ci_classes =& is_loaded();
 
 		log_message('debug', 'Loader Class Initialized');
 	}
@@ -147,7 +143,6 @@
 	 */
 	public function initialize()
 	{
-		$this->_base_classes =& is_loaded();
 		$this->_ci_autoloader();
 	}
 
@@ -165,7 +160,7 @@
 	 */
 	public function is_loaded($class)
 	{
-		return isset($this->_ci_classes[$class]) ? $this->_ci_classes[$class] : FALSE;
+		return array_search(ucfirst($class), $this->_ci_classes, TRUE);
 	}
 
 	// --------------------------------------------------------------------
@@ -179,23 +174,29 @@
 	 * @param	string	$library	Library name
 	 * @param	array	$params		Optional parameters to pass to the library class constructor
 	 * @param	string	$object_name	An optional object name to assign to
-	 * @return	void
+	 * @return	object
 	 */
-	public function library($library = '', $params = NULL, $object_name = NULL)
+	public function library($library, $params = NULL, $object_name = NULL)
 	{
-		if (is_array($library))
+		if (empty($library))
 		{
-			foreach ($library as $class)
+			return $this;
+		}
+		elseif (is_array($library))
+		{
+			foreach ($library as $key => $value)
 			{
-				$this->library($class, $params);
+				if (is_int($key))
+				{
+					$this->library($value, $params);
+				}
+				else
+				{
+					$this->library($key, $params, $value);
+				}
 			}
 
-			return;
-		}
-
-		if ($library === '' OR isset($this->_base_classes[$library]))
-		{
-			return;
+			return $this;
 		}
 
 		if ($params !== NULL && ! is_array($params))
@@ -204,6 +205,7 @@
 		}
 
 		$this->_ci_load_class($library, $params, $object_name);
+		return $this;
 	}
 
 	// --------------------------------------------------------------------
@@ -216,21 +218,22 @@
 	 * @param	string	$model		Model name
 	 * @param	string	$name		An optional object name to assign to
 	 * @param	bool	$db_conn	An optional database connection configuration to initialize
-	 * @return	void
+	 * @return	object
 	 */
 	public function model($model, $name = '', $db_conn = FALSE)
 	{
 		if (empty($model))
 		{
-			return;
+			return $this;
 		}
 		elseif (is_array($model))
 		{
 			foreach ($model as $key => $value)
 			{
-				$this->model(is_int($key) ? $value : $key, $value);
+				is_int($key) ? $this->model($value, '', $db_conn) : $this->model($key, $value, $db_conn);
 			}
-			return;
+
+			return $this;
 		}
 
 		$path = '';
@@ -252,7 +255,7 @@
 
 		if (in_array($name, $this->_ci_models, TRUE))
 		{
-			return;
+			return $this;
 		}
 
 		$CI =& get_instance();
@@ -261,7 +264,22 @@
 			show_error('The model name you are loading is the name of a resource that is already being used: '.$name);
 		}
 
-		$model = strtolower($model);
+		if ($db_conn !== FALSE && ! class_exists('CI_DB', FALSE))
+		{
+			if ($db_conn === TRUE)
+			{
+				$db_conn = '';
+			}
+
+			$CI->load->database($db_conn, FALSE, TRUE);
+		}
+
+		if ( ! class_exists('CI_Model', FALSE))
+		{
+			load_class('Model', 'core');
+		}
+
+		$model = ucfirst(strtolower($model));
 
 		foreach ($this->_ci_model_paths as $mod_path)
 		{
@@ -270,27 +288,11 @@
 				continue;
 			}
 
-			if ($db_conn !== FALSE && ! class_exists('CI_DB', FALSE))
-			{
-				if ($db_conn === TRUE)
-				{
-					$db_conn = '';
-				}
-
-				$CI->load->database($db_conn, FALSE, TRUE);
-			}
-
-			if ( ! class_exists('CI_Model', FALSE))
-			{
-				load_class('Model', 'core');
-			}
-
 			require_once($mod_path.'models/'.$path.$model.'.php');
 
-			$model = ucfirst($model);
 			$CI->$name = new $model();
 			$this->_ci_models[] = $name;
-			return;
+			return $this;
 		}
 
 		// couldn't find the model
@@ -307,8 +309,8 @@
 	 * @param	bool	$query_builder	Whether to enable Query Builder
 	 *					(overrides the configuration setting)
 	 *
-	 * @return	void|object|bool	Database object if $return is set to TRUE,
-	 *					FALSE on failure, void in any other case
+	 * @return	object|bool	Database object if $return is set to TRUE,
+	 *					FALSE on failure, CI_Loader instance in any other case
 	 */
 	public function database($params = '', $return = FALSE, $query_builder = NULL)
 	{
@@ -334,6 +336,7 @@
 
 		// Load the DB class
 		$CI->db =& DB($params, $query_builder);
+		return $this;
 	}
 
 	// --------------------------------------------------------------------
@@ -342,8 +345,8 @@
 	 * Load the Database Utilities Class
 	 *
 	 * @param	object	$db	Database object
-	 * @param	bool	$return	Whether to return the DB Forge class object or not
-	 * @return	void|object
+	 * @param	bool	$return	Whether to return the DB Utilities class object or not
+	 * @return	object
 	 */
 	public function dbutil($db = NULL, $return = FALSE)
 	{
@@ -365,6 +368,7 @@
 		}
 
 		$CI->dbutil = new $class($db);
+		return $this;
 	}
 
 	// --------------------------------------------------------------------
@@ -374,7 +378,7 @@
 	 *
 	 * @param	object	$db	Database object
 	 * @param	bool	$return	Whether to return the DB Forge class object or not
-	 * @return	void|object
+	 * @return	object
 	 */
 	public function dbforge($db = NULL, $return = FALSE)
 	{
@@ -408,6 +412,7 @@
 		}
 
 		$CI->dbforge = new $class($db);
+		return $this;
 	}
 
 	// --------------------------------------------------------------------
@@ -422,7 +427,7 @@
 	 *				to be extracted for use in the view
 	 * @param	bool	$return	Whether to return the view output
 	 *				or leave it to the Output class
-	 * @return	void
+	 * @return	object|string
 	 */
 	public function view($view, $vars = array(), $return = FALSE)
 	{
@@ -436,7 +441,7 @@
 	 *
 	 * @param	string	$path	File path
 	 * @param	bool	$return	Whether to return the file output
-	 * @return	void|string
+	 * @return	object|string
 	 */
 	public function file($path, $return = FALSE)
 	{
@@ -455,9 +460,9 @@
 	 *					An associative array or object containing values
 	 *					to be set, or a value's name if string
 	 * @param 	string	$val	Value to set, only used if $vars is a string
-	 * @return	void
+	 * @return	object
 	 */
-	public function vars($vars = array(), $val = '')
+	public function vars($vars, $val = '')
 	{
 		if (is_string($vars))
 		{
@@ -473,6 +478,23 @@
 				$this->_ci_cached_vars[$key] = $val;
 			}
 		}
+
+		return $this;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Clear Cached Variables
+	 *
+	 * Clears the cached variables.
+	 *
+	 * @return  object
+	 */
+	public function clear_vars()
+	{
+		$this->_ci_cached_vars = array();
+		return $this;
 	}
 
 	// --------------------------------------------------------------------
@@ -510,7 +532,7 @@
 	 * Helper Loader
 	 *
 	 * @param	string|string[]	$helpers	Helper name(s)
-	 * @return	void
+	 * @return	object
 	 */
 	public function helper($helpers = array())
 	{
@@ -567,6 +589,8 @@
 				show_error('Unable to load the requested file: helpers/'.$helper.'.php');
 			}
 		}
+
+		return $this;
 	}
 
 	// --------------------------------------------------------------------
@@ -579,11 +603,11 @@
 	 *
 	 * @uses	CI_Loader::helper()
 	 * @param	string|string[]	$helpers	Helper name(s)
-	 * @return	void
+	 * @return	object
 	 */
 	public function helpers($helpers = array())
 	{
-		$this->helper($helpers);
+		return $this->helper($helpers);
 	}
 
 	// --------------------------------------------------------------------
@@ -595,18 +619,19 @@
 	 *
 	 * @param	string|string[]	$files	List of language file names to load
 	 * @param	string		Language name
-	 * @return	void
+	 * @return	object
 	 */
-	public function language($files = array(), $lang = '')
+	public function language($files, $lang = '')
 	{
 		$CI =& get_instance();
-
 		is_array($files) OR $files = array($files);
 
 		foreach ($files as $langfile)
 		{
 			$CI->lang->load($langfile, $lang);
 		}
+
+		return $this;
 	}
 
 	// --------------------------------------------------------------------
@@ -622,10 +647,9 @@
 	 * @param	bool	$fail_gracefully	Whether to just return FALSE or display an error message
 	 * @return	bool	TRUE if the file was loaded correctly or FALSE on failure
 	 */
-	public function config($file = '', $use_sections = FALSE, $fail_gracefully = FALSE)
+	public function config($file, $use_sections = FALSE, $fail_gracefully = FALSE)
 	{
-		$CI =& get_instance();
-		return $CI->config->load($file, $use_sections, $fail_gracefully);
+		return get_instance()->config->load($file, $use_sections, $fail_gracefully);
 	}
 
 	// --------------------------------------------------------------------
@@ -639,10 +663,10 @@
 	 * @param	array		$params		Optional parameters to pass to the driver
 	 * @param	string		$object_name	An optional object name to assign to
 	 *
-	 * @return	void|object|bool	Object or FALSE on failure if $library is a string
-	 *					and $object_name is set. void otherwise.
+	 * @return	object|bool	Object or FALSE on failure if $library is a string
+	 *				and $object_name is set. CI_Loader instance otherwise.
 	 */
-	public function driver($library = '', $params = NULL, $object_name = NULL)
+	public function driver($library, $params = NULL, $object_name = NULL)
 	{
 		if (is_array($library))
 		{
@@ -650,10 +674,10 @@
 			{
 				$this->driver($driver);
 			}
-			return;
-		}
 
-		if ($library === '')
+			return $this;
+		}
+		elseif (empty($library))
 		{
 			return FALSE;
 		}
@@ -689,7 +713,7 @@
 	 *
 	 * @param	string	$path		Path to add
 	 * @param 	bool	$view_cascade	(default: TRUE)
-	 * @return	void
+	 * @return	object
 	 */
 	public function add_package_path($path, $view_cascade = TRUE)
 	{
@@ -704,6 +728,8 @@
 		// Add config file path
 		$config =& $this->_ci_get_component('config');
 		$config->_config_paths[] = $path;
+
+		return $this;
 	}
 
 	// --------------------------------------------------------------------
@@ -731,7 +757,7 @@
 	 * added path will be removed removed.
 	 *
 	 * @param	string	$path	Path to remove
-	 * @return	void
+	 * @return	object
 	 */
 	public function remove_package_path($path = '')
 	{
@@ -773,6 +799,8 @@
 		$this->_ci_model_paths = array_unique(array_merge($this->_ci_model_paths, array(APPPATH)));
 		$this->_ci_view_paths = array_merge($this->_ci_view_paths, array(APPPATH.'views/' => TRUE));
 		$config->_config_paths = array_unique(array_merge($config->_config_paths, array(APPPATH)));
+
+		return $this;
 	}
 
 	// --------------------------------------------------------------------
@@ -788,7 +816,7 @@
 	 * @used-by	CI_Loader::view()
 	 * @used-by	CI_Loader::file()
 	 * @param	array	$_ci_data	Data to load
-	 * @return	void
+	 * @return	object
 	 */
 	protected function _ci_load($_ci_data)
 	{
@@ -912,6 +940,8 @@
 			$_ci_CI->output->append_output(ob_get_contents());
 			@ob_end_clean();
 		}
+
+		return $this;
 	}
 
 	// --------------------------------------------------------------------
@@ -1118,30 +1148,35 @@
 
 		// Set the variable name we will assign the class to
 		// Was a custom class name supplied? If so we'll use it
-		$class = strtolower($class);
-
-		if ($object_name === NULL)
+		if (empty($object_name))
 		{
-			$classvar = isset($this->_ci_varmap[$class]) ? $this->_ci_varmap[$class] : $class;
+			$object_name = strtolower($class);
+			if (isset($this->_ci_varmap[$object_name]))
+			{
+				$object_name = $this->_ci_varmap[$object_name];
+			}
 		}
-		else
+
+		// Don't overwrite existing properties
+		$CI =& get_instance();
+		if (isset($CI->$object_name))
 		{
-			$classvar = $object_name;
+			if ($CI->$object_name instanceof $name)
+			{
+				log_message('debug', $class." has already been instantiated as '".$object_name."'. Second attempt aborted.");
+				return;
+			}
+
+			show_error("Resource '".$object_name."' already exists and is not a ".$class." instance.");
 		}
 
 		// Save the class name and object name
-		$this->_ci_classes[$class] = $classvar;
+		$this->_ci_classes[$object_name] = $class;
 
 		// Instantiate the class
-		$CI =& get_instance();
-		if ($config !== NULL)
-		{
-			$CI->$classvar = new $name($config);
-		}
-		else
-		{
-			$CI->$classvar = new $name();
-		}
+		$CI->$object_name = isset($config)
+			? new $name($config)
+			: new $name();
 	}
 
 	// --------------------------------------------------------------------
@@ -1198,6 +1233,15 @@
 			}
 		}
 
+		// Autoload drivers
+		if (isset($autoload['drivers']))
+		{
+			foreach ($autoload['drivers'] as $item)
+			{
+				$this->driver($item);
+			}
+		}
+
 		// Load libraries
 		if (isset($autoload['libraries']) && count($autoload['libraries']) > 0)
 		{
@@ -1215,15 +1259,6 @@
 			}
 		}
 
-		// Autoload drivers
-		if (isset($autoload['drivers']))
-		{
-			foreach ($autoload['drivers'] as $item)
-			{
-				$this->driver($item);
-			}
-		}
-
 		// Autoload models
 		if (isset($autoload['model']))
 		{
diff --git a/system/core/Log.php b/system/core/Log.php
index e4d72b5..63fef20 100644
--- a/system/core/Log.php
+++ b/system/core/Log.php
@@ -140,10 +140,9 @@
 	 *
 	 * @param	string	the error level: 'error', 'debug' or 'info'
 	 * @param	string	the error message
-	 * @param	bool	whether the error is a native PHP error
 	 * @return	bool
 	 */
-	public function write_log($level, $msg, $php_error = FALSE)
+	public function write_log($level, $msg)
 	{
 		if ($this->_enabled === FALSE)
 		{
@@ -176,10 +175,18 @@
 			return FALSE;
 		}
 
-		$message .= $level.' '.($level === 'INFO' ? ' -' : '-').' '.date($this->_date_fmt).' --> '.$msg."\n";
+		$message .= $level.' - '.date($this->_date_fmt).' --> '.$msg."\n";
 
 		flock($fp, LOCK_EX);
-		fwrite($fp, $message);
+
+		for ($written = 0, $length = strlen($message); $written < $length; $written += $result)
+		{
+			if (($result = fwrite($fp, substr($message, $written))) === FALSE)
+			{
+				break;
+			}
+		}
+
 		flock($fp, LOCK_UN);
 		fclose($fp);
 
@@ -188,7 +195,7 @@
 			@chmod($filepath, FILE_WRITE_MODE);
 		}
 
-		return TRUE;
+		return is_int($result);
 	}
 
 }
diff --git a/system/core/Model.php b/system/core/Model.php
index 1eb6f90..11e6075 100644
--- a/system/core/Model.php
+++ b/system/core/Model.php
@@ -59,8 +59,7 @@
 	 */
 	public function __get($key)
 	{
-		$CI =& get_instance();
-		return $CI->$key;
+		return get_instance()->$key;
 	}
 
 }
diff --git a/system/core/Output.php b/system/core/Output.php
index 06d7a86..2ad8e90 100644
--- a/system/core/Output.php
+++ b/system/core/Output.php
@@ -58,21 +58,21 @@
 	 *
 	 * @var	array
 	 */
-	public $headers =	array();
+	public $headers = array();
 
 	/**
 	 * List of mime types
 	 *
 	 * @var	array
 	 */
-	public $mimes =		array();
+	public $mimes =	array();
 
 	/**
 	 * Mime-type for the current page
 	 *
 	 * @var	string
 	 */
-	protected $mime_type	= 'text/html';
+	protected $mime_type = 'text/html';
 
 	/**
 	 * Enable Profiler flag
@@ -82,11 +82,18 @@
 	public $enable_profiler = FALSE;
 
 	/**
-	 * zLib output compression flag
+	 * php.ini zlib.output_compression flag
 	 *
 	 * @var	bool
 	 */
-	protected $_zlib_oc =		FALSE;
+	protected $_zlib_oc = FALSE;
+
+	/**
+	 * CI output compression flag
+	 *
+	 * @var	bool
+	 */
+	protected $_compress_output = FALSE;
 
 	/**
 	 * List of profiler sections
@@ -102,7 +109,7 @@
 	 *
 	 * @var	bool
 	 */
-	public $parse_exec_vars =	TRUE;
+	public $parse_exec_vars = TRUE;
 
 	/**
 	 * Class constructor
@@ -114,6 +121,11 @@
 	public function __construct()
 	{
 		$this->_zlib_oc = (bool) @ini_get('zlib.output_compression');
+		$this->_compress_output = (
+			$this->_zlib_oc === FALSE
+			&& config_item('compress_output') === TRUE
+			&& extension_loaded('zlib')
+		);
 
 		// Get mime types for later
 		$this->mimes =& get_mimes();
@@ -436,15 +448,14 @@
 		if ($this->parse_exec_vars === TRUE)
 		{
 			$memory	= round(memory_get_usage() / 1024 / 1024, 2).'MB';
-
 			$output = str_replace(array('{elapsed_time}', '{memory_usage}'), array($elapsed, $memory), $output);
 		}
 
 		// --------------------------------------------------------------------
 
 		// Is compression requested?
-		if ($CFG->item('compress_output') === TRUE && $this->_zlib_oc === FALSE
-			&& extension_loaded('zlib')
+		if (isset($CI) // This means that we're not serving a cache file, if we were, it would already be compressed
+			&& $this->_compress_output === TRUE
 			&& isset($_SERVER['HTTP_ACCEPT_ENCODING']) && strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== FALSE)
 		{
 			ob_start('ob_gzhandler');
@@ -468,6 +479,21 @@
 		// simply echo out the data and exit.
 		if ( ! isset($CI))
 		{
+			if ($this->_compress_output === TRUE)
+			{
+				if (isset($_SERVER['HTTP_ACCEPT_ENCODING']) && strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== FALSE)
+				{
+					header('Content-Encoding: gzip');
+					header('Content-Length: '.strlen($output));
+				}
+				else
+				{
+					// User agent doesn't support gzip compression,
+					// so we'll have to decompress our cache
+					$output = gzinflate(substr($output, 10, -8));
+				}
+			}
+
 			echo $output;
 			log_message('debug', 'Final output sent to browser');
 			log_message('debug', 'Total execution time: '.$elapsed);
@@ -530,9 +556,9 @@
 			return;
 		}
 
-		$uri =	$CI->config->item('base_url').
-				$CI->config->item('index_page').
-				$CI->uri->uri_string();
+		$uri = $CI->config->item('base_url')
+			.$CI->config->item('index_page')
+			.$CI->uri->uri_string();
 
 		$cache_path .= md5($uri);
 
@@ -542,17 +568,39 @@
 			return;
 		}
 
-		$expire = time() + ($this->cache_expiration * 60);
-
-		// Put together our serialized info.
-		$cache_info = serialize(array(
-			'expire'	=> $expire,
-			'headers'	=> $this->headers
-		));
-
 		if (flock($fp, LOCK_EX))
 		{
-			fwrite($fp, $cache_info.'ENDCI--->'.$output);
+			// If output compression is enabled, compress the cache
+			// itself, so that we don't have to do that each time
+			// we're serving it
+			if ($this->_compress_output === TRUE)
+			{
+				$output = gzencode($output);
+
+				if ($this->get_header('content-type') === NULL)
+				{
+					$this->set_content_type($this->mime_type);
+				}
+			}
+
+			$expire = time() + ($this->cache_expiration * 60);
+
+			// Put together our serialized info.
+			$cache_info = serialize(array(
+				'expire'	=> $expire,
+				'headers'	=> $this->headers
+			));
+
+			$output = $cache_info.'ENDCI--->'.$output;
+
+			for ($written = 0, $length = strlen($output); $written < $length; $written += $result)
+			{
+				if (($result = fwrite($fp, substr($output, $written))) === FALSE)
+				{
+					break;
+				}
+			}
+
 			flock($fp, LOCK_UN);
 		}
 		else
@@ -560,13 +608,22 @@
 			log_message('error', 'Unable to secure a file lock for file at: '.$cache_path);
 			return;
 		}
+
 		fclose($fp);
-		@chmod($cache_path, FILE_WRITE_MODE);
 
-		log_message('debug', 'Cache file written: '.$cache_path);
+		if (is_int($result))
+		{
+			@chmod($cache_path, FILE_WRITE_MODE);
+			log_message('debug', 'Cache file written: '.$cache_path);
 
-		// Send HTTP cache-control headers to browser to match file cache settings.
-		$this->set_cache_header($_SERVER['REQUEST_TIME'], $expire);
+			// Send HTTP cache-control headers to browser to match file cache settings.
+			$this->set_cache_header($_SERVER['REQUEST_TIME'], $expire);
+		}
+		else
+		{
+			@unlink($cache_path);
+			log_message('error', 'Unable to write the complete cache content at: '.$cache_path);
+		}
 	}
 
 	// --------------------------------------------------------------------
@@ -701,7 +758,7 @@
 		else
 		{
 			header('Pragma: public');
-			header('Cache-Control: max-age=' . $max_age . ', public');
+			header('Cache-Control: max-age='.$max_age.', public');
 			header('Expires: '.gmdate('D, d M Y H:i:s', $expiration).' GMT');
 			header('Last-modified: '.gmdate('D, d M Y H:i:s', $last_modified).' GMT');
 		}
@@ -740,13 +797,13 @@
 				preg_match_all('{<style.+</style>}msU', $output, $style_clean);
 				foreach ($style_clean[0] as $s)
 				{
-					$output = str_replace($s, $this->_minify_script_style($s, TRUE), $output);
+					$output = str_replace($s, $this->_minify_js_css($s, 'css', TRUE), $output);
 				}
 
 				// Minify the javascript in <script> tags.
 				foreach ($javascript_clean[0] as $s)
 				{
-					$javascript_mini[] = $this->_minify_script_style($s, TRUE);
+					$javascript_mini[] = $this->_minify_js_css($s, 'js', TRUE);
 				}
 
 				// Replace multiple spaces with a single space.
@@ -792,13 +849,14 @@
 			break;
 
 			case 'text/css':
+
+				return $this->_minify_js_css($output, 'css');
+
 			case 'text/javascript':
 			case 'application/javascript':
 			case 'application/x-javascript':
 
-				$output = $this->_minify_script_style($output);
-
-			break;
+				return $this->_minify_js_css($output, 'js');
 
 			default: break;
 		}
@@ -809,134 +867,100 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 * Minify Style and Script
+	 * Minify JavaScript and CSS code
 	 *
-	 * Reduce excessive size of CSS/JavaScript content.  To remove spaces this
-	 * script walks the string as an array and determines if the pointer is inside
-	 * a string created by single quotes or double quotes.  spaces inside those
-	 * strings are not stripped.  Opening and closing tags are severed from
-	 * the string initially and saved without stripping whitespace to preserve
-	 * the tags and any associated properties if tags are present
+	 * Strips comments and excessive whitespace characters
 	 *
-	 * Minification logic/workflow is similar to methods used by Douglas Crockford
-	 * in JSMIN. http://www.crockford.com/javascript/jsmin.html
-	 *
-	 * KNOWN ISSUE: ending a line with a closing parenthesis ')' and no semicolon
-	 * where there should be one will break the Javascript. New lines after a
-	 * closing parenthesis are not recognized by the script. For best results
-	 * be sure to terminate lines with a semicolon when appropriate.
-	 *
-	 * @param	string	$output		Output to minify
-	 * @param	bool	$has_tags	Specify if the output has style or script tags
-	 * @return	string	Minified output
+	 * @param	string	$output
+	 * @param	string	$type	'js' or 'css'
+	 * @param	bool	$tags	Whether $output contains the 'script' or 'style' tag
+	 * @return	string
 	 */
-	protected function _minify_script_style($output, $has_tags = FALSE)
+	protected function _minify_js_css($output, $type, $tags = FALSE)
 	{
-		// We only need this if there are tags in the file
-		if ($has_tags === TRUE)
+		if ($tags === TRUE)
 		{
-			// Remove opening tag and save for later
-			$pos = strpos($output, '>') + 1;
-			$open_tag = substr($output, 0, $pos);
-			$output = substr_replace($output, '', 0, $pos);
+			$tags = array('close' => strrchr($output, '<'));
 
-			// Remove closing tag and save it for later
-			$pos = strpos($output, '</');
-			$closing_tag = substr($output, $pos, strlen($output));
-			$output = substr_replace($output, '', $pos);
+			$open_length = strpos($output, '>') + 1;
+			$tags['open'] = substr($output, 0, $open_length);
+
+			$output = substr($output, $open_length, -strlen($tags['close']));
+
+			// Strip spaces from the tags
+			$tags = preg_replace('#\s{2,}#', ' ', $tags);
 		}
 
-		// Remove CSS comments
-		$output = preg_replace('!/\*[^*]*\*+([^/][^*]*\*+)*/!i', '', $output);
+		$output = trim($output);
 
-		// Remove spaces around curly brackets, colons,
-		// semi-colons, parenthesis, commas
-		$chunks = preg_split('/([\'|"]).+(?![^\\\]\\1)\\1/iU', $output, -1, PREG_SPLIT_OFFSET_CAPTURE);
-		for ($i = count($chunks) - 1; $i >= 0; $i--)
+		if ($type === 'js')
 		{
-			$output = substr_replace(
-				$output,
-				preg_replace('/\s*(:|;|,|}|{|\(|\))\s*/i', '$1', $chunks[$i][0]),
-				$chunks[$i][1],
-				strlen($chunks[$i][0])
+			// Catch all string literals and comment blocks
+			if (preg_match_all('#((?:((?<!\\\)\'|")|(/\*)|(//)).*(?(2)(?<!\\\)\2|(?(3)\*/|\n)))#msuUS', $output, $match, PREG_OFFSET_CAPTURE))
+			{
+				$js_literals = $js_code = array();
+				for ($match = $match[0], $c = count($match), $i = $pos = $offset = 0; $i < $c; $i++)
+				{
+					$js_code[$pos++] = trim(substr($output, $offset, $match[$i][1] - $offset));
+					$offset = $match[$i][1] + strlen($match[$i][0]);
+
+					// Save only if we haven't matched a comment block
+					if ($match[$i][0][0] !== '/')
+					{
+						$js_literals[$pos++] = array_shift($match[$i]);
+					}
+				}
+				$js_code[$pos] = substr($output, $offset);
+
+				// $match might be quite large, so free it up together with other vars that we no longer need
+				unset($match, $offset, $pos);
+			}
+			else
+			{
+				$js_code = array($output);
+				$js_literals = array();
+			}
+
+			$varname = 'js_code';
+		}
+		else
+		{
+			$varname = 'output';
+		}
+
+		// Standartize new lines
+		$$varname = str_replace(array("\r\n", "\r"), "\n", $$varname);
+
+		if ($type === 'js')
+		{
+			$patterns = array(
+				'#\s*([!\#%&()*+,\-./:;<=>?@\[\]^`{|}~])\s*#'	=> '$1',	// Remove spaces following and preceeding JS-wise non-special & non-word characters
+				'#\s{2,}#'					=> ' '		// Reduce the remaining multiple whitespace characters to a single space
+			);
+		}
+		else
+		{
+			$patterns = array(
+				'#/\*.*(?=\*/)\*/#s'	=> '',		// Remove /* block comments */
+				'#\n?//[^\n]*#'		=> '',		// Remove // line comments
+				'#\s*([^\w.\#%])\s*#U'	=> '$1',	// Remove spaces following and preceeding non-word characters, excluding dots, hashes and the percent sign
+				'#\s{2,}#'		=> ' '		// Reduce the remaining multiple space characters to a single space
 			);
 		}
 
-		// Replace tabs with spaces
-		// Replace carriage returns & multiple new lines with single new line
-		// and trim any leading or trailing whitespace
-		$output = trim(preg_replace(array('/\t+/', '/\r/', '/\n+/'), array(' ', "\n", "\n"), $output));
+		$$varname = preg_replace(array_keys($patterns), array_values($patterns), $$varname);
 
-		// Remove spaces when safe to do so.
-		$in_string = $in_dstring = $prev = FALSE;
-		$array_output = str_split($output);
-		foreach ($array_output as $key => $value)
+		// Glue back JS quoted strings
+		if ($type === 'js')
 		{
-			if ($in_string === FALSE && $in_dstring === FALSE)
-			{
-				if ($value === ' ')
-				{
-					// Get the next element in the array for comparisons
-					$next = $array_output[$key + 1];
-
-					// Strip spaces preceded/followed by a non-ASCII character
-					// or not preceded/followed by an alphanumeric
-					// or not preceded/followed \ $ and _
-					if ((preg_match('/^[\x20-\x7f]*$/D', $next) OR preg_match('/^[\x20-\x7f]*$/D', $prev))
-						&& ( ! ctype_alnum($next) OR ! ctype_alnum($prev))
-						&& ! in_array($next, array('\\', '_', '$'), TRUE)
-						&& ! in_array($prev, array('\\', '_', '$'), TRUE)
-					)
-					{
-						unset($array_output[$key]);
-					}
-				}
-				else
-				{
-					// Save this value as previous for the next iteration
-					// if it is not a blank space
-					$prev = $value;
-				}
-			}
-
-			if ($value === "'")
-			{
-				$in_string = ! $in_string;
-			}
-			elseif ($value === '"')
-			{
-				$in_dstring = ! $in_dstring;
-			}
+			$js_code += $js_literals;
+			ksort($js_code);
+			$output = implode($js_code);
+			unset($js_code, $js_literals, $varname, $patterns);
 		}
 
-		// Put the string back together after spaces have been stripped
-		$output = implode($array_output);
-
-		// Remove new line characters unless previous or next character is
-		// printable or Non-ASCII
-		preg_match_all('/[\n]/', $output, $lf, PREG_OFFSET_CAPTURE);
-		$removed_lf = 0;
-		foreach ($lf as $feed_position)
-		{
-			foreach ($feed_position as $position)
-			{
-				$position = $position[1] - $removed_lf;
-				$next = $output[$position + 1];
-				$prev = $output[$position - 1];
-				if ( ! ctype_print($next) && ! ctype_print($prev)
-					&& ! preg_match('/^[\x20-\x7f]*$/D', $next)
-					&& ! preg_match('/^[\x20-\x7f]*$/D', $prev)
-				)
-				{
-					$output = substr_replace($output, '', $position, 1);
-					$removed_lf++;
-				}
-			}
-		}
-
-		// Put the opening and closing tags back if applicable
-		return isset($open_tag)
-			? $open_tag.$output.$closing_tag
+		return is_array($tags)
+			? $tags['open'].$output.$tags['close']
 			: $output;
 	}
 
diff --git a/system/core/Router.php b/system/core/Router.php
index cc3916f..6335240 100644
--- a/system/core/Router.php
+++ b/system/core/Router.php
@@ -91,6 +91,15 @@
 	 */
 	public $translate_uri_dashes = FALSE;
 
+	/**
+	 * Enable query strings flag
+	 *
+	 * Determines wether to use GET parameters or segment URIs
+	 *
+	 * @var	bool
+	 */
+	public $enable_query_strings = FALSE;
+
 	// --------------------------------------------------------------------
 
 	/**
@@ -102,9 +111,34 @@
 	 */
 	public function __construct()
 	{
+		global $routing;
+
 		$this->config =& load_class('Config', 'core');
 		$this->uri =& load_class('URI', 'core');
+
+		$this->enable_query_strings = ( ! is_cli() && $this->config->item('enable_query_strings') === TRUE);
 		$this->_set_routing();
+
+		// Set any routing overrides that may exist in the main index file
+		if (isset($routing) && is_array($routing))
+		{
+			if (isset($routing['directory']))
+			{
+				$this->set_directory($routing['directory']);
+			}
+
+			if ( ! empty($routing['controller']))
+			{
+				$this->set_class($routing['controller']);
+			}
+
+			if (isset($routing['function']))
+			{
+				$routing['function'] = empty($routing['function']) ? 'index' : $routing['function'];
+				$this->set_method($routing['function']);
+			}
+		}
+
 		log_message('debug', 'Router Class Initialized');
 	}
 
@@ -123,26 +157,39 @@
 		// Are query strings enabled in the config file? Normally CI doesn't utilize query strings
 		// since URI segments are more search-engine friendly, but they can optionally be used.
 		// If this feature is enabled, we will gather the directory/class/method a little differently
-		$segments = array();
-		if ($this->config->item('enable_query_strings') === TRUE
-			&& ! empty($_GET[$this->config->item('controller_trigger')])
-			&& is_string($_GET[$this->config->item('controller_trigger')])
-		)
+		if ($this->enable_query_strings)
 		{
-			if (isset($_GET[$this->config->item('directory_trigger')]) && is_string($_GET[$this->config->item('directory_trigger')]))
+			$_d = $this->config->item('directory_trigger');
+			$_d = isset($_GET[$_d]) ? trim($_GET[$_d], " \t\n\r\0\x0B/") : '';
+			if ($_d !== '')
 			{
-				$this->set_directory(trim($this->uri->_filter_uri($_GET[$this->config->item('directory_trigger')])));
-				$segments[] = $this->directory;
+				$this->set_directory($this->uri->filter_uri($_d));
 			}
 
-			$this->set_class(trim($this->uri->_filter_uri($_GET[$this->config->item('controller_trigger')])));
-			$segments[] = $this->class;
-
-			if ( ! empty($_GET[$this->config->item('function_trigger')]) && is_string($_GET[$this->config->item('function_trigger')]))
+			$_c = $this->config->item('controller_trigger');
+			if ( ! empty($_GET[$_c]))
 			{
-				$this->set_method(trim($this->uri->_filter_uri($_GET[$this->config->item('function_trigger')])));
-				$segments[] = $this->method;
+				$this->set_class(trim($this->uri->filter_uri(trim($_GET[$_c]))));
+
+				$_f = $this->config->item('function_trigger');
+				if ( ! empty($_GET[$_f]))
+				{
+					$this->set_method(trim($this->uri->filter_uri($_GET[$_f])));
+				}
+
+				$this->uri->rsegments = array(
+					1 => $this->class,
+					2 => $this->method
+				);
 			}
+			else
+			{
+				$this->_set_default_controller();
+			}
+
+			// Routing rules don't apply to query strings and we don't need to detect
+			// directories, so we're done here
+			return;
 		}
 
 		// Load the routes.php file.
@@ -165,25 +212,58 @@
 			$this->routes = $route;
 		}
 
-		// Were there any query string segments? If so, we'll validate them and bail out since we're done.
-		if (count($segments) > 0)
+		// Is there anything to parse?
+		if ($this->uri->uri_string !== '')
 		{
-			return $this->_validate_request($segments);
+			$this->_parse_routes();
+		}
+		else
+		{
+			$this->_set_default_controller();
+		}
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Set request route
+	 *
+	 * Takes an array of URI segments as input and sets the class/method
+	 * to be called.
+	 *
+	 * @used-by	CI_Router::_parse_routes()
+	 * @param	array	$segments	URI segments
+	 * @return	void
+	 */
+	protected function _set_request($segments = array())
+	{
+		$segments = $this->_validate_request($segments);
+		// If we don't have any segments left - try the default controller;
+		// WARNING: Directories get shifted out of the segments array!
+		if (empty($segments))
+		{
+			$this->_set_default_controller();
+			return;
 		}
 
-		// Fetch the complete URI string
-		$this->uri->_fetch_uri_string();
-
-		// Is there a URI string? If not, the default controller specified in the "routes" file will be shown.
-		if ($this->uri->uri_string == '')
+		if ($this->translate_uri_dashes === TRUE)
 		{
-			return $this->_set_default_controller();
+			$segments[0] = str_replace('-', '_', $segments[0]);
+			if (isset($segments[1]))
+			{
+				$segments[1] = str_replace('-', '_', $segments[1]);
+			}
 		}
 
-		$this->uri->_remove_url_suffix(); // Remove the URL suffix
-		$this->uri->_explode_segments(); // Compile the segments into an array
-		$this->_parse_routes(); // Parse any custom routing that may exist
-		$this->uri->_reindex_segments(); // Re-index the segment array so that it starts with 1 rather than 0
+		$this->set_class($segments[0]);
+		if (isset($segments[1]))
+		{
+			$this->set_method($segments[1]);
+		}
+
+		array_unshift($segments, NULL);
+		unset($segments[0]);
+		$this->uri->rsegments = $segments;
 	}
 
 	// --------------------------------------------------------------------
@@ -206,10 +286,20 @@
 			$method = 'index';
 		}
 
-		$this->_set_request(array($class, $method));
+		if ( ! file_exists(APPPATH.'controllers/'.$this->directory.ucfirst($class).'.php'))
+		{
+			// This will trigger 404 later
+			return;
+		}
 
-		// re-index the routed segments array so it starts with 1 rather than 0
-		$this->uri->_reindex_segments();
+		$this->set_class($class);
+		$this->set_method($method);
+
+		// Assign routed segments, index starting from 1
+		$this->uri->rsegments = array(
+			1 => $class,
+			2 => $method
+		);
 
 		log_message('debug', 'No URI present. Default controller set.');
 	}
@@ -217,119 +307,35 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 * Set request route
-	 *
-	 * Takes an array of URI segments as input and sets the class/method
-	 * to be called.
-	 *
-	 * @param	array	$segments	URI segments
-	 * @return	void
-	 */
-	protected function _set_request($segments = array())
-	{
-		$segments = $this->_validate_request($segments);
-
-		if (count($segments) === 0)
-		{
-			return $this->_set_default_controller();
-		}
-
-		if ($this->translate_uri_dashes === TRUE)
-		{
-			$segments[0] = str_replace('-', '_', $segments[0]);
-			if (isset($segments[1]))
-			{
-				$segments[1] = str_replace('-', '_', $segments[1]);
-			}
-		}
-
-		$this->set_class($segments[0]);
-		isset($segments[1]) OR $segments[1] = 'index';
-		$this->set_method($segments[1]);
-
-		// Update our "routed" segment array to contain the segments.
-		// Note: If there is no custom routing, this array will be
-		// identical to $this->uri->segments
-		$this->uri->rsegments = $segments;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
 	 * Validate request
 	 *
 	 * Attempts validate the URI request and determine the controller path.
 	 *
+	 * @used-by	CI_Router::_set_request()
 	 * @param	array	$segments	URI segments
-	 * @return	array	URI segments
+	 * @return	mixed	URI segments
 	 */
 	protected function _validate_request($segments)
 	{
-		if (count($segments) === 0)
+		$c = count($segments);
+		// Loop through our segments and return as soon as a controller
+		// is found or when such a directory doesn't exist
+		while ($c-- > 0)
 		{
-			return $segments;
-		}
+			$test = $this->directory
+				.ucfirst($this->translate_uri_dashes === TRUE ? str_replace('-', '_', $segments[0]) : $segments[0]);
 
-		$test = ($this->translate_uri_dashes === TRUE)
-			? str_replace('-', '_', $segments[0]) : $segments[0];
-
-		// Does the requested controller exist in the root folder?
-		if (file_exists(APPPATH.'controllers/'.$test.'.php'))
-		{
-			return $segments;
-		}
-
-		// Is the controller in a sub-folder?
-		if (is_dir(APPPATH.'controllers/'.$segments[0]))
-		{
-			// Set the directory and remove it from the segment array
-			$this->set_directory(array_shift($segments));
-			if (count($segments) > 0)
+			if ( ! file_exists(APPPATH.'controllers/'.$test.'.php') && is_dir(APPPATH.'controllers/'.$this->directory.$segments[0]))
 			{
-				$test = ($this->translate_uri_dashes === TRUE)
-					? str_replace('-', '_', $segments[0]) : $segments[0];
-
-				// Does the requested controller exist in the sub-directory?
-				if ( ! file_exists(APPPATH.'controllers/'.$this->directory.$test.'.php'))
-				{
-					if ( ! empty($this->routes['404_override']))
-					{
-						$this->directory = '';
-						return explode('/', $this->routes['404_override'], 2);
-					}
-					else
-					{
-						show_404($this->directory.$segments[0]);
-					}
-				}
-			}
-			else
-			{
-				// Is the method being specified in the route?
-				$segments = explode('/', $this->default_controller);
-				if ( ! file_exists(APPPATH.'controllers/'.$this->directory.$segments[0].'.php'))
-				{
-					$this->directory = '';
-				}
+				$this->set_directory(array_shift($segments), TRUE);
+				continue;
 			}
 
 			return $segments;
 		}
 
-		// If we've gotten this far it means that the URI does not correlate to a valid
-		// controller class. We will now see if there is an override
-		if ( ! empty($this->routes['404_override']))
-		{
-			if (sscanf($this->routes['404_override'], '%[^/]/%s', $class, $method) !== 2)
-			{
-				$method = 'index';
-			}
-
-			return array($class, $method);
-		}
-
-		// Nothing else to do at this point but show a 404
-		show_404($segments[0]);
+		// This means that all segments were actually directories
+		return $segments;
 	}
 
 	// --------------------------------------------------------------------
@@ -347,16 +353,43 @@
 		// Turn the segment array into a URI string
 		$uri = implode('/', $this->uri->segments);
 
+		// Get HTTP verb
+		$http_verb = isset($_SERVER['REQUEST_METHOD']) ? strtolower($_SERVER['REQUEST_METHOD']) : 'cli';
+
 		// Is there a literal match?  If so we're done
-		if (isset($this->routes[$uri]) && is_string($this->routes[$uri]))
+		if (isset($this->routes[$uri]))
 		{
-			return $this->_set_request(explode('/', $this->routes[$uri]));
+			// Check default routes format
+			if (is_string($this->routes[$uri]))
+			{
+				$this->_set_request(explode('/', $this->routes[$uri]));
+				return;
+			}
+			// Is there a matching http verb?
+			elseif (is_array($this->routes[$uri]) && isset($this->routes[$uri][$http_verb]))
+			{
+				$this->_set_request(explode('/', $this->routes[$uri][$http_verb]));
+				return;
+			}
 		}
 
-		// Loop through the route array looking for wild-cards
+		// Loop through the route array looking for wildcards
 		foreach ($this->routes as $key => $val)
 		{
-			// Convert wild-cards to RegEx
+			// Check if route format is using http verb
+			if (is_array($val))
+			{
+				if (isset($val[$http_verb]))
+				{
+					$val = $val[$http_verb];
+				}
+				else
+				{
+					continue;
+				}
+			}
+
+			// Convert wildcards to RegEx
 			$key = str_replace(array(':any', ':num'), array('[^/]+', '[0-9]+'), $key);
 
 			// Does the RegEx match?
@@ -406,13 +439,14 @@
 					$val = preg_replace('#^'.$key.'$#', $val, $uri);
 				}
 
-				return $this->_set_request(explode('/', $val));
+				$this->_set_request(explode('/', $val));
+				return;
 			}
 		}
 
 		// If we got this far it means we didn't encounter a
 		// matching route so we'll set the site default route
-		$this->_set_request($this->uri->segments);
+		$this->_set_request(array_values($this->uri->segments));
 	}
 
 	// --------------------------------------------------------------------
@@ -473,11 +507,19 @@
 	 * Set directory name
 	 *
 	 * @param	string	$dir	Directory name
+	 * @param	bool	$appent	Whether we're appending rather then setting the full value
 	 * @return	void
 	 */
-	public function set_directory($dir)
+	public function set_directory($dir, $append = FALSE)
 	{
-		$this->directory = str_replace(array('/', '.'), '', $dir).'/';
+		if ($append !== TRUE OR empty($this->directory))
+		{
+			$this->directory = str_replace('.', '', trim($dir, '/')).'/';
+		}
+		else
+		{
+			$this->directory .= str_replace('.', '', trim($dir, '/')).'/';
+		}
 	}
 
 	// --------------------------------------------------------------------
@@ -496,38 +538,6 @@
 		return $this->directory;
 	}
 
-	// --------------------------------------------------------------------
-
-	/**
-	 * Set controller overrides
-	 *
-	 * @param	array	$routing	Route overrides
-	 * @return	void
-	 */
-	public function _set_overrides($routing)
-	{
-		if ( ! is_array($routing))
-		{
-			return;
-		}
-
-		if (isset($routing['directory']))
-		{
-			$this->set_directory($routing['directory']);
-		}
-
-		if ( ! empty($routing['controller']))
-		{
-			$this->set_class($routing['controller']);
-		}
-
-		if (isset($routing['function']))
-		{
-			$routing['function'] = empty($routing['function']) ? 'index' : $routing['function'];
-			$this->set_method($routing['function']);
-		}
-	}
-
 }
 
 /* End of file Router.php */
diff --git a/system/core/Security.php b/system/core/Security.php
index 196d611..95957a3 100644
--- a/system/core/Security.php
+++ b/system/core/Security.php
@@ -38,6 +38,30 @@
 class CI_Security {
 
 	/**
+	 * List of sanitize filename strings
+	 *
+	 * @var	array
+	 */
+	public $filename_bad_chars =	array(
+		'../', '<!--', '-->', '<', '>',
+		"'", '"', '&', '$', '#',
+		'{', '}', '[', ']', '=',
+		';', '?', '%20', '%22',
+		'%3c',		// <
+		'%253c',	// <
+		'%3e',		// >
+		'%0e',		// >
+		'%28',		// (
+		'%29',		// )
+		'%2528',	// (
+		'%26',		// &
+		'%24',		// $
+		'%3f',		// ?
+		'%3b',		// ;
+		'%3d'		// =
+	);
+
+	/**
 	 * XSS Hash
 	 *
 	 * Random Hash for protecting URLs.
@@ -93,7 +117,6 @@
 		'document.write'	=> '[removed]',
 		'.parentNode'		=> '[removed]',
 		'.innerHTML'		=> '[removed]',
-		'window.location'	=> '[removed]',
 		'-moz-binding'		=> '[removed]',
 		'<!--'				=> '&lt;!--',
 		'-->'				=> '--&gt;',
@@ -108,6 +131,7 @@
 	 */
 	protected $_never_allowed_regex = array(
 		'javascript\s*:',
+		'(document|(document\.)?window)\.(location|on\w*)',
 		'expression\s*(\(|&\#40;)', // CSS and IE
 		'vbscript\s*:', // IE, surprise!
 		'Redirect\s+302',
@@ -527,13 +551,13 @@
 
 		do
 		{
-			$matches = $matches1 = 0;
+			$m1 = $m2 = 0;
 
+			$str = preg_replace('/(&#x0*[0-9a-f]{2,5})(?![0-9a-f;])/iS', '$1;', $str, -1, $m1);
+			$str = preg_replace('/(&#\d{2,4})(?![0-9;])/S', '$1;', $str, -1, $m2);
 			$str = html_entity_decode($str, ENT_COMPAT, $charset);
-			$str = preg_replace('~&#x(0*[0-9a-f]{2,5})~ei', 'chr(hexdec("\\1"))', $str, -1, $matches);
-			$str = preg_replace('~&#([0-9]{2,4})~e', 'chr(\\1)', $str, -1, $matches1);
 		}
-		while ($matches OR $matches1);
+		while ($m1 OR $m2);
 
 		return $str;
 	}
@@ -549,24 +573,7 @@
 	 */
 	public function sanitize_filename($str, $relative_path = FALSE)
 	{
-		$bad = array(
-			'../', '<!--', '-->', '<', '>',
-			"'", '"', '&', '$', '#',
-			'{', '}', '[', ']', '=',
-			';', '?', '%20', '%22',
-			'%3c',		// <
-			'%253c',	// <
-			'%3e',		// >
-			'%0e',		// >
-			'%28',		// (
-			'%29',		// )
-			'%2528',	// (
-			'%26',		// &
-			'%24',		// $
-			'%3f',		// ?
-			'%3b',		// ;
-			'%3d'		// =
-		);
+		$bad = $this->filename_bad_chars;
 
 		if ( ! $relative_path)
 		{
@@ -596,7 +603,7 @@
 	 */
 	public function strip_image_tags($str)
 	{
-		return preg_replace(array('#<img\s+.*?src\s*=\s*["\'](.+?)["\'].*?\>#', '#<img\s+.*?src\s*=\s*(.+?).*?\>#'), '\\1', $str);
+		return preg_replace(array('#<img[\s/]+.*?src\s*=\s*["\'](.+?)["\'].*?\>#', '#<img[\s/]+.*?src\s*=\s*(.+?).*?\>#'), '\\1', $str);
 	}
 
 	// ----------------------------------------------------------------
@@ -641,8 +648,8 @@
 	 */
 	protected function _remove_evil_attributes($str, $is_image)
 	{
-		// All javascript event handlers (e.g. onload, onclick, onmouseover), style, and xmlns
-		$evil_attributes = array('on\w*', 'style', 'xmlns', 'formaction');
+		// Formaction, style, and xmlns
+		$evil_attributes = array('style', 'xmlns', 'formaction');
 
 		if ($is_image === TRUE)
 		{
@@ -830,14 +837,15 @@
 		 * Add a semicolon if missing.  We do this to enable
 		 * the conversion of entities to ASCII later.
 		 */
-		$str = preg_replace('#(&\#?[0-9a-z]{2,})([\x00-\x20])*;?#i', '\\1;\\2', $str);
+		$str = preg_replace('/(&#\d{2,4})(?![0-9;])/', '$1;', $str);
+		$str = preg_replace('/(&[a-z]{2,})(?![a-z;])/i', '$1;', $str);
 
 		/*
 		 * Validate UTF16 two byte encoding (x00)
 		 *
 		 * Just as above, adds a semicolon if missing.
 		 */
-		$str = preg_replace('#(&\#x?)([0-9A-F]+);?#i', '\\1\\2;', $str);
+		$str = preg_replace('/(&#x0*[0-9a-f]{2,5})(?![0-9a-f;])/i', '$1;', $str);
 
 		/*
 		 * Un-Protect GET variables in URLs
@@ -877,7 +885,7 @@
 	{
 		if ($this->_csrf_hash === '')
 		{
-			// If the cookie exists we will use it's value.
+			// If the cookie exists we will use its value.
 			// We don't necessarily want to regenerate it with
 			// each page load since a page could contain embedded
 			// sub-pages causing this feature to fail
@@ -887,7 +895,7 @@
 				return $this->_csrf_hash = $_COOKIE[$this->_csrf_cookie_name];
 			}
 
-			$this->_csrf_hash = md5(uniqid(rand(), TRUE));
+			$this->_csrf_hash = md5(uniqid(mt_rand(), TRUE));
 			$this->csrf_set_cookie();
 		}
 
diff --git a/system/core/URI.php b/system/core/URI.php
index bc086d2..13682cb 100644
--- a/system/core/URI.php
+++ b/system/core/URI.php
@@ -44,21 +44,21 @@
 	 *
 	 * @var	array
 	 */
-	public $keyval =	array();
+	public $keyval = array();
 
 	/**
 	 * Current URI string
 	 *
 	 * @var	string
 	 */
-	public $uri_string;
+	public $uri_string = '';
 
 	/**
 	 * List of URI segments
 	 *
 	 * @var	array
 	 */
-	public $segments =	array();
+	public $segments = array();
 
 	/**
 	 * Re-indexed list of URI segments
@@ -67,90 +67,67 @@
 	 *
 	 * @var	array
 	 */
-	public $rsegments =	array();
+	public $rsegments = array();
+
+	/**
+	 * Permitted URI chars
+	 *
+	 * PCRE character group allowed in URI segments
+	 *
+	 * @var	string
+	 */
+	protected $_permitted_uri_chars;
 
 	/**
 	 * Class constructor
 	 *
-	 * Simply globalizes the $RTR object. The front
-	 * loads the Router class early on so it's not available
-	 * normally as other classes are.
-	 *
 	 * @return	void
 	 */
 	public function __construct()
 	{
 		$this->config =& load_class('Config', 'core');
-		log_message('debug', 'URI Class Initialized');
-	}
 
-	// --------------------------------------------------------------------
-
-	/**
-	 * Fetch URI String
-	 *
-	 * @used-by	CI_Router
-	 * @return	void
-	 */
-	public function _fetch_uri_string()
-	{
-		$protocol = strtoupper($this->config->item('uri_protocol'));
-
-		if ($protocol === 'AUTO')
+		// If query strings are enabled, we don't need to parse any segments.
+		// However, they don't make sense under CLI.
+		if (is_cli() OR $this->config->item('enable_query_strings') !== TRUE)
 		{
-			// Is the request coming from the command line?
-			if ($this->_is_cli_request())
+			$this->_permitted_uri_chars = $this->config->item('permitted_uri_chars');
+
+			// If it's a CLI request, ignore the configuration
+			if (is_cli() OR ($protocol = strtoupper($this->config->item('uri_protocol'))) === 'CLI')
 			{
 				$this->_set_uri_string($this->_parse_argv());
-				return;
 			}
-
-			// Is there a PATH_INFO variable? This should be the easiest solution.
-			if (isset($_SERVER['PATH_INFO']))
+			elseif ($protocol === 'AUTO')
 			{
-				$this->_set_uri_string($_SERVER['PATH_INFO']);
-				return;
+				// Is there a PATH_INFO variable? This should be the easiest solution.
+				if (isset($_SERVER['PATH_INFO']))
+				{
+					$this->_set_uri_string($_SERVER['PATH_INFO']);
+				}
+				// No PATH_INFO? Let's try REQUST_URI or QUERY_STRING then
+				elseif (($uri = $this->_parse_request_uri()) !== '' OR ($uri = $this->_parse_query_string()) !== '')
+				{
+					$this->_set_uri_string($uri);
+				}
+				// As a last ditch effor, let's try using the $_GET array
+				elseif (is_array($_GET) && count($_GET) === 1 && trim(key($_GET), '/') !== '')
+				{
+					$this->_set_uri_string(key($_GET));
+				}
 			}
-
-			// Let's try REQUEST_URI then, this will work in most situations
-			if (($uri = $this->_parse_request_uri()) !== '')
+			elseif (method_exists($this, ($method = '_parse_'.strtolower($protocol))))
 			{
+				$this->_set_uri_string($this->$method());
+			}
+			else
+			{
+				$uri = isset($_SERVER[$protocol]) ? $_SERVER[$protocol] : @getenv($protocol);
 				$this->_set_uri_string($uri);
-				return;
 			}
-
-			// No REQUEST_URI either?... What about QUERY_STRING?
-			if (($uri = $this->_parse_query_string()) !== '')
-			{
-				$this->_set_uri_string($uri);
-				return;
-			}
-
-			// 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));
-				return;
-			}
-
-			// We've exhausted all our options...
-			$this->uri_string = '';
-			return;
 		}
 
-		if ($protocol === 'CLI')
-		{
-			$this->_set_uri_string($this->_parse_argv());
-			return;
-		}
-		elseif (method_exists($this, ($method = '_parse_'.strtolower($protocol))))
-		{
-			$this->_set_uri_string($this->$method());
-			return;
-		}
-
-		$uri = isset($_SERVER[$protocol]) ? $_SERVER[$protocol] : @getenv($protocol);
-		$this->_set_uri_string($uri);
+		log_message('debug', 'URI Class Initialized');
 	}
 
 	// --------------------------------------------------------------------
@@ -165,6 +142,35 @@
 	{
 		// Filter out control characters and trim slashes
 		$this->uri_string = trim(remove_invisible_characters($str, FALSE), '/');
+
+		if ($this->uri_string !== '')
+		{
+			// Remove the URL suffix, if present
+			if (($suffix = (string) $this->config->item('url_suffix')) !== '')
+			{
+				$slen = strlen($suffix);
+
+				if (substr($this->uri_string, -$slen) === $suffix)
+				{
+					$this->uri_string = substr($this->uri_string, 0, -$slen);
+				}
+			}
+
+			$this->segments[0] = NULL;
+			// Populate the segments array
+			foreach (explode('/', preg_replace('|/*(.+?)/*$|', '\\1', $this->uri_string)) as $val)
+			{
+				// Filter segments for security
+				$val = trim($this->filter_uri($val));
+
+				if ($val !== '')
+				{
+					$this->segments[] = $val;
+				}
+			}
+
+			unset($this->segments[0]);
+		}
 	}
 
 	// --------------------------------------------------------------------
@@ -225,36 +231,10 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 * Remove relative directory (../) and multi slashes (///)
-	 *
-	 * Do some final cleaning of the URI and return it, currently only used in self::_parse_request_uri()
-	 *
-	 * @param	string	$url
-	 * @return	string
-	 */
-	protected function _remove_relative_directory($uri)
-	{
-		$uris = array();
-		$tok = strtok($uri, '/');
-		while ($tok !== FALSE)
-		{
-			if (( ! empty($tok) OR $tok === '0') && $tok !== '..')
-			{
-				$uris[] = $tok;
-			}
-			$tok = strtok('/');
-		}
-		return implode('/', $uris);
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
 	 * Parse QUERY_STRING
 	 *
 	 * Will parse QUERY_STRING and automatically detect the URI from it.
 	 *
-	 * @used-by	CI_URI::_fetch_uri_string()
 	 * @return	string
 	 */
 	protected function _parse_query_string()
@@ -280,23 +260,6 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 * Is CLI Request?
-	 *
-	 * Duplicate of method from the Input class to test to see if
-	 * a request was made from the command line.
-	 *
-	 * @see		CI_Input::is_cli_request()
-	 * @used-by	CI_URI::_fetch_uri_string()
-	 * @return 	bool
-	 */
-	protected function _is_cli_request()
-	{
-		return (PHP_SAPI === 'cli') OR defined('STDIN');
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
 	 * Parse CLI arguments
 	 *
 	 * Take each command line argument and assume it is a URI segment.
@@ -312,104 +275,52 @@
 	// --------------------------------------------------------------------
 
 	/**
+	 * Remove relative directory (../) and multi slashes (///)
+	 *
+	 * Do some final cleaning of the URI and return it, currently only used in self::_parse_request_uri()
+	 *
+	 * @param	string	$url
+	 * @return	string
+	 */
+	protected function _remove_relative_directory($uri)
+	{
+		$uris = array();
+		$tok = strtok($uri, '/');
+		while ($tok !== FALSE)
+		{
+			if (( ! empty($tok) OR $tok === '0') && $tok !== '..')
+			{
+				$uris[] = $tok;
+			}
+			$tok = strtok('/');
+		}
+
+		return implode('/', $uris);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
 	 * Filter URI
 	 *
 	 * Filters segments for malicious characters.
 	 *
-	 * @used-by	CI_Router
 	 * @param	string	$str
 	 * @return	string
 	 */
-	public function _filter_uri($str)
+	public function filter_uri($str)
 	{
-		if ($str !== '' && $this->config->item('permitted_uri_chars') != '' && $this->config->item('enable_query_strings') === FALSE)
+		if ( ! empty($str) && ! empty($this->_permitted_uri_chars) && ! preg_match('/^['.$this->_permitted_uri_chars.']+$/i'.(UTF8_ENABLED ? 'u' : ''), $str))
 		{
-			// preg_quote() in PHP 5.3 escapes -, so the str_replace() and addition of - to preg_quote() is to maintain backwards
-			// compatibility as many are unaware of how characters in the permitted_uri_chars will be parsed as a regex pattern
-			if ( ! preg_match('|^['.str_replace(array('\\-', '\-'), '-', preg_quote($this->config->item('permitted_uri_chars'), '-')).']+$|i', $str))
-			{
-				show_error('The URI you submitted has disallowed characters.', 400);
-			}
+			show_error('The URI you submitted has disallowed characters.', 400);
 		}
 
 		// Convert programatic characters to entities and return
 		return str_replace(
-					array('$',     '(',     ')',     '%28',   '%29'), // Bad
-					array('&#36;', '&#40;', '&#41;', '&#40;', '&#41;'), // Good
-					$str);
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Remove URL suffix
-	 *
-	 * Removes the suffix from the URL if needed.
-	 *
-	 * @used-by	CI_Router
-	 * @return	void
-	 */
-	public function _remove_url_suffix()
-	{
-		$suffix = (string) $this->config->item('url_suffix');
-
-		if ($suffix === '')
-		{
-			return;
-		}
-
-		$slen = strlen($suffix);
-
-		if (substr($this->uri_string, -$slen) === $suffix)
-		{
-			$this->uri_string = substr($this->uri_string, 0, -$slen);
-		}
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Explode URI segments
-	 *
-	 * The individual segments will be stored in the $this->segments array.
-	 *
-	 * @see		CI_URI::$segments
-	 * @used-by	CI_Router
-	 * @return	void
-	 */
-	public function _explode_segments()
-	{
-		foreach (explode('/', preg_replace('|/*(.+?)/*$|', '\\1', $this->uri_string)) as $val)
-		{
-			// Filter segments for security
-			$val = trim($this->_filter_uri($val));
-
-			if ($val !== '')
-			{
-				$this->segments[] = $val;
-			}
-		}
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Re-index Segments
-	 *
-	 * Re-indexes the CI_URI::$segment array so that it starts at 1 rather
-	 * than 0. Doing so makes it simpler to use methods like
-	 * CI_URI::segment(n) since there is a 1:1 relationship between the
-	 * segment array and the actual segments.
-	 *
-	 * @used-by	CI_Router
-	 * @return	void
-	 */
-	public function _reindex_segments()
-	{
-		array_unshift($this->segments, NULL);
-		array_unshift($this->rsegments, NULL);
-		unset($this->segments[0]);
-		unset($this->rsegments[0]);
+			array('$',     '(',     ')',     '%28',   '%29'),	// Bad
+			array('&#36;', '&#40;', '&#41;', '&#40;', '&#41;'),	// Good
+			$str
+		);
 	}
 
 	// --------------------------------------------------------------------
@@ -720,12 +631,7 @@
 	{
 		global $RTR;
 
-		if (($dir = $RTR->directory) === '/')
-		{
-			$dir = '';
-		}
-
-		return $dir.implode('/', $this->rsegment_array());
+		return ltrim($RTR->directory, '/').implode('/', $this->rsegments);
 	}
 
 }
diff --git a/system/core/Utf8.php b/system/core/Utf8.php
index a78616d..828a8ae 100644
--- a/system/core/Utf8.php
+++ b/system/core/Utf8.php
@@ -66,7 +66,7 @@
 		}
 
 		if (
-			@preg_match('/./u', 'é') === 1	// PCRE must support UTF-8
+			defined('PREG_BAD_UTF8_ERROR')	// PCRE must support UTF-8
 			&& function_exists('iconv')	// iconv must be installed
 			&& MB_ENABLED === TRUE		// mbstring must be enabled
 			&& $charset === 'UTF-8'		// Application charset must be UTF-8
diff --git a/system/database/DB.php b/system/database/DB.php
index 8742800..96da87c 100644
--- a/system/database/DB.php
+++ b/system/database/DB.php
@@ -206,11 +206,6 @@
 		$DB->initialize();
 	}
 
-	if ( ! empty($params['stricton']))
-	{
-		$DB->query('SET SESSION sql_mode="STRICT_ALL_TABLES"');
-	}
-
 	return $DB;
 }
 
diff --git a/system/database/DB_driver.php b/system/database/DB_driver.php
index 425657e..f066b58 100644
--- a/system/database/DB_driver.php
+++ b/system/database/DB_driver.php
@@ -624,7 +624,14 @@
 				// 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_depth > 0 && $this->trans_complete();
+				if ($this->_trans_depth !== 0)
+				{
+					do
+					{
+						$this->trans_complete();
+					}
+					while ($this->_trans_depth !== 0);
+				}
 
 				// Display errors
 				return $this->display_error(array('Error Number: '.$error['code'], $error['message'], $sql));
@@ -917,7 +924,7 @@
 	 */
 	public function is_write_type($sql)
 	{
-		return (bool) preg_match('/^\s*"?(SET|INSERT|UPDATE|DELETE|REPLACE|CREATE|DROP|TRUNCATE|LOAD|COPY|ALTER|RENAME|GRANT|REVOKE|LOCK|UNLOCK|REINDEX)\s+/i', $sql);
+		return (bool) preg_match('/^\s*"?(SET|INSERT|UPDATE|DELETE|REPLACE|CREATE|DROP|TRUNCATE|LOAD|COPY|ALTER|RENAME|GRANT|REVOKE|LOCK|UNLOCK|REINDEX)\s/i', $sql);
 	}
 
 	// --------------------------------------------------------------------
@@ -1135,7 +1142,7 @@
 				else
 				{
 					/* We have no other choice but to just get the first element's key.
-					 * Due to array_shift() accepting it's argument by reference, if
+					 * Due to array_shift() accepting its argument by reference, if
 					 * E_STRICT is on, this would trigger a warning. So we'll have to
 					 * assign it first.
 					 */
@@ -1375,7 +1382,9 @@
 			$fields[$this->protect_identifiers($key)] = $this->escape($val);
 		}
 
-		return $this->_update($this->protect_identifiers($table, TRUE, NULL, FALSE), $fields);
+		$sql = $this->_update($this->protect_identifiers($table, TRUE, NULL, FALSE), $fields);
+		$this->_reset_write();
+		return $sql;
 	}
 
 	// --------------------------------------------------------------------
@@ -1412,7 +1421,7 @@
 	 */
 	protected function _has_operator($str)
 	{
-		return (bool) preg_match('/(<|>|!|=|\sIS NULL|\sIS NOT NULL|\sBETWEEN|\sLIKE|\sIN\s*\(|\s)/i', trim($str));
+		return (bool) preg_match('/(<|>|!|=|\sIS NULL|\sIS NOT NULL|\sEXISTS|\sBETWEEN|\sLIKE|\sIN\s*\(|\s)/i', trim($str));
 	}
 
 	// --------------------------------------------------------------------
@@ -1438,6 +1447,8 @@
 				'\s*>\s*',			// >
 				'\s+IS NULL',			// IS NULL
 				'\s+IS NOT NULL',		// IS NOT NULL
+				'\s+EXISTS\s*\([^\)]+\)',	// EXISTS(sql)
+				'\s+NOT EXISTS\s*\([^\)]+\)',	// NOT EXISTS(sql)
 				'\s+BETWEEN\s+\S+\s+AND\s+\S+',	// BETWEEN value AND value
 				'\s+IN\s*\([^\)]+\)',		// IN(list)
 				'\s+NOT IN\s*\([^\)]+\)',	// NOT IN (list)
@@ -1474,7 +1485,7 @@
 		}
 
 		return (func_num_args() > 1)
-			? call_user_func_array($function, array_splice(func_get_args(), 1))
+			? call_user_func_array($function, array_slice(func_get_args(), 1))
 			: call_user_func($function);
 	}
 
diff --git a/system/database/DB_forge.php b/system/database/DB_forge.php
index d52029e..1cebb18 100644
--- a/system/database/DB_forge.php
+++ b/system/database/DB_forge.php
@@ -740,6 +740,18 @@
 					'_literal'		=> FALSE
 			);
 
+			if ($create_table === FALSE)
+			{
+				if (isset($attributes['AFTER']))
+				{
+					$field['after'] = $attributes['AFTER'];
+				}
+				elseif (isset($attributes['FIRST']))
+				{
+					$field['first'] = (bool) $attributes['FIRST'];
+				}
+			}
+
 			$this->_attr_default($attributes, $field);
 
 			if (isset($attributes['NULL']))
@@ -748,11 +760,15 @@
 				{
 					$field['null'] = empty($this->_null) ? '' : ' '.$this->_null;
 				}
-				elseif ($create_table === TRUE)
+				else
 				{
 					$field['null'] = ' NOT NULL';
 				}
 			}
+			elseif ($create_table === TRUE)
+			{
+				$field['null'] = ' NOT NULL';
+			}
 
 			$this->_attr_auto_increment($attributes, $field);
 			$this->_attr_unique($attributes, $field);
@@ -968,7 +984,6 @@
 	 */
 	protected function _process_indexes($table)
 	{
-		$table = $this->db->escape_identifiers($table);
 		$sqls = array();
 
 		for ($i = 0, $c = count($this->keys); $i < $c; $i++)
@@ -992,7 +1007,7 @@
 
 			is_array($this->keys[$i]) OR $this->keys[$i] = array($this->keys[$i]);
 
-			$sqls[] = 'CREATE INDEX '.$this->db->escape_identifiers(implode('_', $this->keys[$i]))
+			$sqls[] = 'CREATE INDEX '.$this->db->escape_identifiers($table.'_'.implode('_', $this->keys[$i]))
 				.' ON '.$this->db->escape_identifiers($table)
 				.' ('.implode(', ', $this->db->escape_identifiers($this->keys[$i])).');';
 		}
diff --git a/system/database/DB_query_builder.php b/system/database/DB_query_builder.php
index 292621b..c543e15 100644
--- a/system/database/DB_query_builder.php
+++ b/system/database/DB_query_builder.php
@@ -385,7 +385,7 @@
 			$alias = $this->_create_alias_from_table(trim($select));
 		}
 
-		$sql = $this->protect_identifiers($type.'('.trim($select).')').' AS '.$this->escape_identifiers(trim($alias));
+		$sql = $type.'('.$this->protect_identifiers(trim($select)).') AS '.$this->escape_identifiers(trim($alias));
 
 		$this->qb_select[] = $sql;
 		$this->qb_no_escape[] = NULL;
@@ -1138,7 +1138,7 @@
 	 * ORDER BY
 	 *
 	 * @param	string	$orderby
-	 * @param	string	$direction	ASC or DESC
+	 * @param	string	$direction	ASC, DESC or RANDOM
 	 * @param	bool	$escape
 	 * @return	CI_DB_query_builder
 	 */
@@ -1152,7 +1152,7 @@
 
 			// Do we have a seed value?
 			$orderby = ctype_digit((string) $orderby)
-				? $orderby = sprintf($this->_random_keyword[1], $orderby)
+				? sprintf($this->_random_keyword[1], $orderby)
 				: $this->_random_keyword[0];
 		}
 		elseif (empty($orderby))
@@ -1338,7 +1338,7 @@
 	 * returned by an Query Builder query.
 	 *
 	 * @param	string
-	 * @return	string
+	 * @return	int
 	 */
 	public function count_all_results($table = '')
 	{
@@ -1846,6 +1846,7 @@
 		{
 			$this->query($this->_update_batch($this->protect_identifiers($table, TRUE, NULL, FALSE), array_slice($this->qb_set, $i, 100), $this->protect_identifiers($index)));
 			$affected_rows += $this->affected_rows();
+			$this->qb_where = array();
 		}
 
 		$this->_reset_write();
@@ -2290,7 +2291,12 @@
 		{
 			for ($i = 0, $c = count($this->$qb_key); $i < $c; $i++)
 			{
-				if ($this->{$qb_key}[$i]['escape'] === FALSE)
+				// Is this condition already compiled?
+				if (is_string($this->{$qb_key}[$i]))
+				{
+					continue;
+				}
+				elseif ($this->{$qb_key}[$i]['escape'] === FALSE)
 				{
 					$this->{$qb_key}[$i] = $this->{$qb_key}[$i]['condition'];
 					continue;
@@ -2360,6 +2366,12 @@
 		{
 			for ($i = 0, $c = count($this->qb_groupby); $i < $c; $i++)
 			{
+				// Is it already compiled?
+				if (is_string($this->qb_groupby))
+				{
+					continue;
+				}
+
 				$this->qb_groupby[$i] = ($this->qb_groupby[$i]['escape'] === FALSE OR $this->_is_literal($this->qb_groupby[$i]['field']))
 					? $this->qb_groupby[$i]['field']
 					: $this->protect_identifiers($this->qb_groupby[$i]['field']);
@@ -2544,17 +2556,34 @@
 		{
 			return;
 		}
+		elseif (in_array('select', $this->qb_cache_exists, TRUE))
+		{
+			$qb_no_escape = $this->qb_cache_no_escape;
+		}
 
-		foreach ($this->qb_cache_exists as $val)
+		foreach (array_unique($this->qb_cache_exists) as $val) // select, from, etc.
 		{
 			$qb_variable	= 'qb_'.$val;
 			$qb_cache_var	= 'qb_cache_'.$val;
+			$qb_new 	= $this->$qb_cache_var;
 
-			if (count($this->$qb_cache_var) === 0)
+			for ($i = 0, $c = count($this->$qb_variable); $i < $c; $i++)
 			{
-				continue;
+				if ( ! in_array($this->{$qb_variable}[$i], $qb_new, TRUE))
+				{
+					$qb_new[] = $this->{$qb_variable}[$i];
+					if ($val === 'select')
+					{
+						$qb_no_escape[] = $this->qb_no_escape[$i];
+					}
+				}
 			}
-			$this->$qb_variable = array_merge($this->$qb_variable, array_diff($this->$qb_cache_var, $this->$qb_variable));
+
+			$this->$qb_variable = $qb_new;
+			if ($val === 'select')
+			{
+				$this->qb_no_escape = $qb_no_escape;
+			}
 		}
 
 		// If we are "protecting identifiers" we need to examine the "from"
@@ -2563,8 +2592,6 @@
 		{
 			$this->_track_aliases($this->qb_from);
 		}
-
-		$this->qb_no_escape = array_merge($this->qb_no_escape, array_diff($this->qb_cache_no_escape, $this->qb_no_escape));
 	}
 
 	// --------------------------------------------------------------------
diff --git a/system/database/DB_utility.php b/system/database/DB_utility.php
index 9f953d4..6656159 100644
--- a/system/database/DB_utility.php
+++ b/system/database/DB_utility.php
@@ -282,8 +282,7 @@
 		extract($params);
 
 		// Load the xml helper
-		$CI =& get_instance();
-		$CI->load->helper('xml');
+		get_instance()->load->helper('xml');
 
 		// Generate the result
 		$xml = '<'.$root.'>'.$newline;
diff --git a/system/database/drivers/mysql/mysql_driver.php b/system/database/drivers/mysql/mysql_driver.php
index b94642b..16b2f6f 100644
--- a/system/database/drivers/mysql/mysql_driver.php
+++ b/system/database/drivers/mysql/mysql_driver.php
@@ -66,6 +66,15 @@
 	 */
 	public $delete_hack = TRUE;
 
+	/**
+	 * Strict ON flag
+	 *
+	 * Whether we're running in strict SQL mode.
+	 *
+	 * @var	bool
+	 */
+	public $stricton = FALSE;
+
 	// --------------------------------------------------------------------
 
 	/**
@@ -126,6 +135,11 @@
 				: FALSE;
 		}
 
+		if ($this->stricton && is_resource($this->conn_id))
+		{
+			$this->simple_query('SET SESSION sql_mode="STRICT_ALL_TABLES"');
+		}
+
 		return $this->conn_id;
 	}
 
diff --git a/system/database/drivers/mysqli/mysqli_driver.php b/system/database/drivers/mysqli/mysqli_driver.php
index ef2cb8a..62ba2c5 100644
--- a/system/database/drivers/mysqli/mysqli_driver.php
+++ b/system/database/drivers/mysqli/mysqli_driver.php
@@ -66,6 +66,15 @@
 	 */
 	public $delete_hack = TRUE;
 
+	/**
+	 * Strict ON flag
+	 *
+	 * Whether we're running in strict SQL mode.
+	 *
+	 * @var	bool
+	 */
+	public $stricton = FALSE;
+
 	// --------------------------------------------------------------------
 
 	/**
@@ -93,6 +102,11 @@
 		$client_flags = ($this->compress === TRUE) ? MYSQLI_CLIENT_COMPRESS : 0;
 		$mysqli = mysqli_init();
 
+		if ($this->stricton)
+		{
+			$mysqli->options(MYSQLI_INIT_COMMAND, 'SET SESSION sql_mode="STRICT_ALL_TABLES"');
+		}
+
 		return @$mysqli->real_connect($hostname, $this->username, $this->password, $this->database, $port, NULL, $client_flags)
 			? $mysqli : FALSE;
 	}
@@ -241,9 +255,10 @@
 		// even if the queries produce a successful result.
 		$this->_trans_failure = ($test_mode === TRUE);
 
-		$this->simple_query('SET AUTOCOMMIT=0');
-		$this->simple_query('START TRANSACTION'); // can also be BEGIN or BEGIN WORK
-		return TRUE;
+		$this->conn_id->autocommit(FALSE);
+		return is_php('5.5')
+			? $this->conn_id->begin_transaction()
+			: $this->simple_query('START TRANSACTION'); // can also be BEGIN or BEGIN WORK
 	}
 
 	// --------------------------------------------------------------------
@@ -261,9 +276,13 @@
 			return TRUE;
 		}
 
-		$this->simple_query('COMMIT');
-		$this->simple_query('SET AUTOCOMMIT=1');
-		return TRUE;
+		if ($this->conn_id->commit())
+		{
+			$this->conn_id->autocommit(TRUE);
+			return TRUE;
+		}
+
+		return FALSE;
 	}
 
 	// --------------------------------------------------------------------
@@ -281,9 +300,13 @@
 			return TRUE;
 		}
 
-		$this->simple_query('ROLLBACK');
-		$this->simple_query('SET AUTOCOMMIT=1');
-		return TRUE;
+		if ($this->conn_id->rollback())
+		{
+			$this->conn_id->autocommit(TRUE);
+			return TRUE;
+		}
+
+		return FALSE;
 	}
 
 	// --------------------------------------------------------------------
diff --git a/system/database/drivers/oci8/oci8_driver.php b/system/database/drivers/oci8/oci8_driver.php
index 93e62b4..d75ed28 100644
--- a/system/database/drivers/oci8/oci8_driver.php
+++ b/system/database/drivers/oci8/oci8_driver.php
@@ -18,7 +18,7 @@
  *
  * @package		CodeIgniter
  * @author		EllisLab Dev Team
- * @copyright   Copyright (c) 2008 - 2013, EllisLab, Inc. (http://ellislab.com/)
+ * @copyright	Copyright (c) 2008 - 2013, EllisLab, Inc. (http://ellislab.com/)
  * @license		http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
  * @link		http://codeigniter.com
  * @since		Version 1.0
@@ -344,7 +344,7 @@
 				$have_cursor = TRUE;
 			}
 		}
-		$sql = trim($sql, ',') . '); END;';
+		$sql = trim($sql, ',').'); END;';
 
 		$this->stmt_id = FALSE;
 		$this->_set_stmt_id($sql);
diff --git a/system/database/drivers/oci8/oci8_result.php b/system/database/drivers/oci8/oci8_result.php
index fd1d287..ce09b62 100644
--- a/system/database/drivers/oci8/oci8_result.php
+++ b/system/database/drivers/oci8/oci8_result.php
@@ -18,7 +18,7 @@
  *
  * @package		CodeIgniter
  * @author		EllisLab Dev Team
- * @copyright   Copyright (c) 2008 - 2013, EllisLab, Inc. (http://ellislab.com/)
+ * @copyright	Copyright (c) 2008 - 2013, EllisLab, Inc. (http://ellislab.com/)
  * @license		http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
  * @link		http://codeigniter.com
  * @since		Version 1.0
diff --git a/system/database/drivers/pdo/pdo_driver.php b/system/database/drivers/pdo/pdo_driver.php
index fa89661..184a8df 100644
--- a/system/database/drivers/pdo/pdo_driver.php
+++ b/system/database/drivers/pdo/pdo_driver.php
@@ -69,7 +69,7 @@
 	{
 		parent::__construct($params);
 
-		if (preg_match('/([^;]+):/', $this->dsn, $match) && count($match) === 2)
+		if (preg_match('/([^:]+):/', $this->dsn, $match) && count($match) === 2)
 		{
 			// If there is a minimum valid dsn string pattern found, we're done
 			// This is for general PDO users, who tend to have a full DSN string.
@@ -77,7 +77,7 @@
 			return;
 		}
 		// Legacy support for DSN specified in the hostname field
-		elseif (preg_match('/([^;]+):/', $this->hostname, $match) && count($match) === 2)
+		elseif (preg_match('/([^:]+):/', $this->hostname, $match) && count($match) === 2)
 		{
 			$this->dsn = $this->hostname;
 			$this->hostname = NULL;
diff --git a/system/database/drivers/pdo/subdrivers/pdo_mysql_driver.php b/system/database/drivers/pdo/subdrivers/pdo_mysql_driver.php
index ff486fc..bc92cab 100644
--- a/system/database/drivers/pdo/subdrivers/pdo_mysql_driver.php
+++ b/system/database/drivers/pdo/subdrivers/pdo_mysql_driver.php
@@ -55,6 +55,15 @@
 	 */
 	public $compress = FALSE;
 
+	/**
+	 * Strict ON flag
+	 *
+	 * Whether we're running in strict SQL mode.
+	 *
+	 * @var	bool
+	 */
+	public $stricton = FALSE;
+
 	// --------------------------------------------------------------------
 
 	/**
@@ -114,6 +123,18 @@
 				.(empty($this->dbcollat) ? '' : ' COLLATE '.$this->dbcollat);
 		}
 
+		if ($this->stricton)
+		{
+			if (empty($this->options[PDO::MYSQL_ATTR_INIT_COMMAND]))
+			{
+				$this->options[PDO::MYSQL_ATTR_INIT_COMMAND] = 'SET SESSION sql_mode="STRICT_ALL_TABLES"';
+			}
+			else
+			{
+				$this->options[PDO::MYSQL_ATTR_INIT_COMMAND] .= ', @@session.sql_mode = "STRICT_ALL_TABLES"';
+			}
+		}
+
 		if ($this->compress === TRUE)
 		{
 			$this->options[PDO::MYSQL_ATTR_COMPRESS] = TRUE;
diff --git a/system/database/drivers/pdo/subdrivers/pdo_pgsql_driver.php b/system/database/drivers/pdo/subdrivers/pdo_pgsql_driver.php
index d0cdde2..6ee327b 100644
--- a/system/database/drivers/pdo/subdrivers/pdo_pgsql_driver.php
+++ b/system/database/drivers/pdo/subdrivers/pdo_pgsql_driver.php
@@ -137,7 +137,7 @@
 	 */
 	public function is_write_type($sql)
 	{
-		return (bool) preg_match('/^\s*"?(SET|INSERT(?![^\)]+\)\s+RETURNING)|UPDATE|DELETE|REPLACE|CREATE|DROP|TRUNCATE|LOAD|COPY|ALTER|RENAME|GRANT|REVOKE|LOCK|UNLOCK|REINDEX)\s+/i', $sql);
+		return (bool) preg_match('/^\s*"?(SET|INSERT(?![^\)]+\)\s+RETURNING)|UPDATE(?!.*\sRETURNING)|DELETE|CREATE|DROP|TRUNCATE|LOAD|COPY|ALTER|RENAME|GRANT|REVOKE|LOCK|UNLOCK|REINDEX)\s/i', str_replace(array("\r\n", "\r", "\n"), ' ', $sql));
 	}
 
 	// --------------------------------------------------------------------
@@ -166,7 +166,7 @@
 	 * ORDER BY
 	 *
 	 * @param	string	$orderby
-	 * @param	string	$direction	ASC or DESC
+	 * @param	string	$direction	ASC, DESC or RANDOM
 	 * @param	bool	$escape
 	 * @return	object
 	 */
diff --git a/system/database/drivers/postgre/postgre_driver.php b/system/database/drivers/postgre/postgre_driver.php
index ac7345a..19404ae 100644
--- a/system/database/drivers/postgre/postgre_driver.php
+++ b/system/database/drivers/postgre/postgre_driver.php
@@ -318,7 +318,7 @@
 	 */
 	public function is_write_type($sql)
 	{
-		return (bool) preg_match('/^\s*"?(SET|INSERT(?![^\)]+\)\s+RETURNING)|UPDATE|DELETE|REPLACE|CREATE|DROP|TRUNCATE|LOAD|COPY|ALTER|RENAME|GRANT|REVOKE|LOCK|UNLOCK|REINDEX)\s+/i', $sql);
+		return (bool) preg_match('/^\s*"?(SET|INSERT(?![^\)]+\)\s+RETURNING)|UPDATE(?!.*\sRETURNING)|DELETE|CREATE|DROP|TRUNCATE|LOAD|COPY|ALTER|RENAME|GRANT|REVOKE|LOCK|UNLOCK|REINDEX)\s/i', str_replace(array("\r\n", "\r", "\n"), ' ', $sql));
 	}
 
 	// --------------------------------------------------------------------
@@ -331,7 +331,7 @@
 	 */
 	protected function _escape_str($str)
 	{
-		return pg_escape_string($str);
+		return pg_escape_string($this->conn_id, $str);
 	}
 
 	// --------------------------------------------------------------------
@@ -346,7 +346,11 @@
 	 */
 	public function escape($str)
 	{
-		if (is_bool($str))
+		if (is_php('5.4.4') && (is_string($str) OR (is_object($str) && method_exists($str, '__toString'))))
+		{
+			return pg_escape_literal($this->conn_id, $str);
+		}
+		elseif (is_bool($str))
 		{
 			return ($str) ? 'TRUE' : 'FALSE';
 		}
@@ -512,7 +516,7 @@
 	 * ORDER BY
 	 *
 	 * @param	string	$orderby
-	 * @param	string	$direction	ASC or DESC
+	 * @param	string	$direction	ASC, DESC or RANDOM
 	 * @param	bool	$escape
 	 * @return	object
 	 */
diff --git a/system/helpers/captcha_helper.php b/system/helpers/captcha_helper.php
index 2d2ae77..24cd535 100644
--- a/system/helpers/captcha_helper.php
+++ b/system/helpers/captcha_helper.php
@@ -126,9 +126,9 @@
 		// Determine angle and position
 		// -----------------------------------
 		$length	= strlen($word);
-		$angle	= ($length >= 6) ? rand(-($length-6), ($length-6)) : 0;
-		$x_axis	= rand(6, (360/$length)-16);
-		$y_axis = ($angle >= 0) ? rand($img_height, $img_width) : rand(6, $img_height);
+		$angle	= ($length >= 6) ? mt_rand(-($length-6), ($length-6)) : 0;
+		$x_axis	= mt_rand(6, (360/$length)-16);
+		$y_axis = ($angle >= 0) ? mt_rand($img_height, $img_width) : mt_rand(6, $img_height);
 
 		// Create image
 		// PHP.net recommends imagecreatetruecolor(), but it isn't always available
@@ -142,7 +142,7 @@
 
 		is_array($colors) OR $colors = $defaults['colors'];
 
-		foreach (array_keys($default['colors']) as $key)
+		foreach (array_keys($defaults['colors']) as $key)
 		{
 			// Check for a possible missing value
 			is_array($colors[$key]) OR $colors[$key] = $defaults['colors'][$key];
@@ -183,13 +183,13 @@
 		if ($use_font === FALSE)
 		{
 			$font_size = 5;
-			$x = rand(0, $img_width / ($length / 3));
+			$x = mt_rand(0, $img_width / ($length / 3));
 			$y = 0;
 		}
 		else
 		{
 			$font_size = 16;
-			$x = rand(0, $img_width / ($length / 1.5));
+			$x = mt_rand(0, $img_width / ($length / 1.5));
 			$y = $font_size + 2;
 		}
 
@@ -197,13 +197,13 @@
 		{
 			if ($use_font === FALSE)
 			{
-				$y = rand(0 , $img_height / 2);
+				$y = mt_rand(0 , $img_height / 2);
 				imagestring($im, $font_size, $x, $y, $word[$i], $colors['text']);
 				$x += ($font_size * 2);
 			}
 			else
 			{
-				$y = rand($img_height / 2, $img_height - 3);
+				$y = mt_rand($img_height / 2, $img_height - 3);
 				imagettftext($im, $font_size, $angle, $x, $y, $colors['text'], $font_path, $word[$i]);
 				$x += $font_size;
 			}
@@ -215,12 +215,12 @@
 		// -----------------------------------
 		//  Generate the image
 		// -----------------------------------
-		$img_name = $now.'.jpg';
-		ImageJPEG($im, $img_path.$img_name);
-		$img = '<img src="'.$img_url.$img_name.'" style="width: '.$img_width.'; height: '.$img_height .'; border: 0;" alt=" " />';
+		$img_filename = $now.'.jpg';
+		ImageJPEG($im, $img_path.$img_filename);
+		$img = '<img src="'.$img_url.$img_filename.'" style="width: '.$img_width.'; height: '.$img_height .'; border: 0;" alt=" " />';
 		ImageDestroy($im);
 
-		return array('word' => $word, 'time' => $now, 'image' => $img);
+		return array('word' => $word, 'time' => $now, 'image' => $img, 'filename' => $img_filename);
 	}
 }
 
diff --git a/system/helpers/cookie_helper.php b/system/helpers/cookie_helper.php
index e5cf6b1..a79083a 100644
--- a/system/helpers/cookie_helper.php
+++ b/system/helpers/cookie_helper.php
@@ -56,11 +56,10 @@
 	 * @param	bool	true makes the cookie accessible via http(s) only (no javascript)
 	 * @return	void
 	 */
-	function set_cookie($name = '', $value = '', $expire = '', $domain = '', $path = '/', $prefix = '', $secure = FALSE, $httponly = FALSE)
+	function set_cookie($name, $value = '', $expire = '', $domain = '', $path = '/', $prefix = '', $secure = FALSE, $httponly = FALSE)
 	{
 		// Set the config file options
-		$CI =& get_instance();
-		$CI->input->set_cookie($name, $value, $expire, $domain, $path, $prefix, $secure, $httponly);
+		get_instance()->input->set_cookie($name, $value, $expire, $domain, $path, $prefix, $secure, $httponly);
 	}
 }
 
@@ -75,11 +74,11 @@
 	 * @param	bool
 	 * @return	mixed
 	 */
-	function get_cookie($index = '', $xss_clean = FALSE)
+	function get_cookie($index, $xss_clean = NULL)
 	{
-		$CI =& get_instance();
+		is_bool($xss_clean) OR $xss_clean = (config_item('global_xss_filtering') === TRUE);
 		$prefix = isset($_COOKIE[$index]) ? '' : config_item('cookie_prefix');
-		return $CI->input->cookie($prefix.$index, $xss_clean);
+		return get_instance()->input->cookie($prefix.$index, $xss_clean);
 	}
 }
 
@@ -96,7 +95,7 @@
 	 * @param	string	the cookie prefix
 	 * @return	void
 	 */
-	function delete_cookie($name = '', $domain = '', $path = '/', $prefix = '')
+	function delete_cookie($name, $domain = '', $path = '/', $prefix = '')
 	{
 		set_cookie($name, '', '', $domain, $path, $prefix);
 	}
diff --git a/system/helpers/file_helper.php b/system/helpers/file_helper.php
index 4b45a62..0587740 100644
--- a/system/helpers/file_helper.php
+++ b/system/helpers/file_helper.php
@@ -79,11 +79,19 @@
 		}
 
 		flock($fp, LOCK_EX);
-		fwrite($fp, $data);
+
+		for ($written = 0, $length = strlen($data); $written < $length; $written += $result)
+		{
+			if (($result = fwrite($fp, substr($data, $written))) === FALSE)
+			{
+				break;
+			}
+		}
+
 		flock($fp, LOCK_UN);
 		fclose($fp);
 
-		return TRUE;
+		return is_int($result);
 	}
 }
 
diff --git a/system/helpers/form_helper.php b/system/helpers/form_helper.php
index 2002d42..a3d299b 100644
--- a/system/helpers/form_helper.php
+++ b/system/helpers/form_helper.php
@@ -50,15 +50,10 @@
 	 * @param	array	a key/value pair hidden data
 	 * @return	string
 	 */
-	function form_open($action = '', $attributes = '', $hidden = array())
+	function form_open($action = '', $attributes = array(), $hidden = array())
 	{
 		$CI =& get_instance();
 
-		if ($attributes === '')
-		{
-			$attributes = 'method="post"';
-		}
-
 		// If an action is not a full URL then turn it into one
 		if ($action && strpos($action, '://') === FALSE)
 		{
@@ -70,10 +65,22 @@
 			$action = $CI->config->site_url($CI->uri->uri_string());
 		}
 
-		$form = '<form action="'.$action.'"'._attributes_to_string($attributes, TRUE).">\n";
+		$attributes = _attributes_to_string($attributes);
+
+		if (stripos($attributes, 'method=') === FALSE)
+		{
+			$attributes .= ' method="post"';
+		}
+
+		if (stripos($attributes, 'accept-charset=') === FALSE)
+		{
+			$attributes .= ' accept-charset="'.strtolower(config_item('charset')).'"';
+		}
+
+		$form = '<form action="'.$action.'"'.$attributes.">\n";
 
 		// Add CSRF field if enabled, but leave it out for GET requests and requests to external websites
-		if ($CI->config->item('csrf_protection') === TRUE && ! (strpos($action, $CI->config->base_url()) === FALSE OR strpos($form, 'method="get"')))
+		if ($CI->config->item('csrf_protection') === TRUE && ! (strpos($action, $CI->config->base_url()) === FALSE OR stripos($form, 'method="get"')))
 		{
 			$hidden[$CI->security->get_csrf_token_name()] = $CI->security->get_csrf_hash();
 		}
@@ -309,7 +316,7 @@
 		{
 			isset($name['options']) OR $name['options'] = array();
 			isset($name['selected']) OR $name['selected'] = array();
-			isset($name['extra']) OR $name['extra'] = array();
+			isset($name['extra']) OR $name['extra'] = '';
 
 			return form_dropdown($name['name'], $name['options'], $name['selected'], $name['extra']);
 		}
@@ -322,10 +329,7 @@
 			$selected = array($_POST[$name]);
 		}
 
-		if ($extra != '')
-		{
-			$extra = ' '.$extra;
-		}
+		$extra = _attributes_to_string($extra);
 
 		$multiple = (count($selected) > 1 && strpos($extra, 'multiple') === FALSE) ? ' multiple="multiple"' : '';
 
@@ -542,12 +546,12 @@
 	 * use form_fieldset_close()
 	 *
 	 * @param	string	The legend text
-	 * @param	string	Additional attributes
+	 * @param	array	Additional attributes
 	 * @return	string
 	 */
 	function form_fieldset($legend_text = '', $attributes = array())
 	{
-		$fieldset = '<fieldset'._attributes_to_string($attributes, FALSE).">\n";
+		$fieldset = '<fieldset'._attributes_to_string($attributes).">\n";
 		if ($legend_text !== '')
 		{
 			return $fieldset.'<legend>'.$legend_text."</legend>\n";
@@ -668,37 +672,33 @@
 	 */
 	function set_select($field = '', $value = '', $default = FALSE)
 	{
-		$OBJ =& _get_validation_object();
+		$CI =& get_instance();
 
-		if ($OBJ === FALSE)
+		if (isset($CI->form_validation) && is_object($CI->form_validation) && $CI->form_validation->has_rule($field))
 		{
-			if ( ! isset($_POST[$field]))
+			return $CI->form_validation->set_select($field, $value, $default);
+		}
+		elseif (($input = $CI->input->post($field, FALSE)) === NULL)
+		{
+			return ($default === TRUE) ? ' selected="selected"' : '';
+		}
+
+		$value = (string) $value;
+		if (is_array($input))
+		{
+			// Note: in_array('', array(0)) returns TRUE, do not use it
+			foreach ($input as &$v)
 			{
-				if (count($_POST) === 0 && $default === TRUE)
+				if ($value === $v)
 				{
 					return ' selected="selected"';
 				}
-				return '';
 			}
 
-			$field = $_POST[$field];
-
-			if (is_array($field))
-			{
-				if ( ! in_array($value, $field))
-				{
-					return '';
-				}
-			}
-			elseif (($field == '' OR $value == '') OR $field !== $value)
-			{
-				return '';
-			}
-
-			return ' selected="selected"';
+			return '';
 		}
 
-		return $OBJ->set_select($field, $value, $default);
+		return ($input === $value) ? ' selected="selected"' : '';
 	}
 }
 
@@ -719,37 +719,33 @@
 	 */
 	function set_checkbox($field = '', $value = '', $default = FALSE)
 	{
-		$OBJ =& _get_validation_object();
+		$CI =& get_instance();
 
-		if ($OBJ === FALSE)
+		if (isset($CI->form_validation) && is_object($CI->form_validation) && $CI->form_validation->has_rule($field))
 		{
-			if ( ! isset($_POST[$field]))
+			return $CI->form_validation->set_checkbox($field, $value, $default);
+		}
+		elseif (($input = $CI->input->post($field, FALSE)) === NULL)
+		{
+			return ($default === TRUE) ? ' checked="checked"' : '';
+		}
+
+		$value = (string) $value;
+		if (is_array($input))
+		{
+			// Note: in_array('', array(0)) returns TRUE, do not use it
+			foreach ($input as &$v)
 			{
-				if (count($_POST) === 0 && $default === TRUE)
+				if ($value === $v)
 				{
 					return ' checked="checked"';
 				}
-				return '';
 			}
 
-			$field = $_POST[$field];
-
-			if (is_array($field))
-			{
-				if ( ! in_array($value, $field))
-				{
-					return '';
-				}
-			}
-			elseif (($field == '' OR $value == '') OR $field !== $value)
-			{
-				return '';
-			}
-
-			return ' checked="checked"';
+			return '';
 		}
 
-		return $OBJ->set_checkbox($field, $value, $default);
+		return ($input === $value) ? ' checked="checked"' : '';
 	}
 }
 
@@ -763,47 +759,25 @@
 	 * Let's you set the selected value of a radio field via info in the POST array.
 	 * If Form Validation is active it retrieves the info from the validation class
 	 *
-	 * @param	string
-	 * @param	string
-	 * @param	bool
+	 * @param	string	$field
+	 * @param	string	$value
+	 * @param	bool	$default
 	 * @return	string
 	 */
 	function set_radio($field = '', $value = '', $default = FALSE)
 	{
-		$OBJ =& _get_validation_object();
+		$CI =& get_instance();
 
-		if ($OBJ === FALSE)
+		if (isset($CI->form_validation) && is_object($CI->form_validation) && $CI->form_validation->has_rule($field))
 		{
-			if ( ! isset($_POST[$field]))
-			{
-				if (count($_POST) === 0 && $default === TRUE)
-				{
-					return ' checked="checked"';
-				}
-				return '';
-			}
-
-			$field = $_POST[$field];
-
-			if (is_array($field))
-			{
-				if ( ! in_array($value, $field))
-				{
-					return '';
-				}
-			}
-			else
-			{
-				if (($field == '' OR $value == '') OR $field !== $value)
-				{
-					return '';
-				}
-			}
-
-			return ' checked="checked"';
+			return $CI->form_validation->set_radio($field, $value, $default);
+		}
+		elseif (($input = $CI->input->post($field, FALSE)) === NULL)
+		{
+			return ($default === TRUE) ? ' checked="checked"' : '';
 		}
 
-		return $OBJ->set_radio($field, $value, $default);
+		return ($input === (string) $value) ? ' checked="checked"' : '';
 	}
 }
 
@@ -920,45 +894,24 @@
 	 * Helper function used by some of the form helpers
 	 *
 	 * @param	mixed
-	 * @param	bool
 	 * @return	string
 	 */
-	function _attributes_to_string($attributes, $formtag = FALSE)
+	function _attributes_to_string($attributes)
 	{
-		if (is_string($attributes) && strlen($attributes) > 0)
+		if (empty($attributes))
 		{
-			if ($formtag === TRUE && strpos($attributes, 'method=') === FALSE)
-			{
-				$attributes .= ' method="post"';
-			}
-
-			if ($formtag === TRUE && strpos($attributes, 'accept-charset=') === FALSE)
-			{
-				$attributes .= ' accept-charset="'.strtolower(config_item('charset')).'"';
-			}
-
-			return ' '.$attributes;
+			return '';
 		}
 
-		if (is_object($attributes) && count($attributes) > 0)
+		if (is_object($attributes))
 		{
 			$attributes = (array) $attributes;
 		}
 
-		if (is_array($attributes) && ($formtag === TRUE OR count($attributes) > 0))
+		if (is_array($attributes))
 		{
 			$atts = '';
 
-			if ( ! isset($attributes['method']) && $formtag === TRUE)
-			{
-				$atts .= ' method="post"';
-			}
-
-			if ( ! isset($attributes['accept-charset']) && $formtag === TRUE)
-			{
-				$atts .= ' accept-charset="'.strtolower(config_item('charset')).'"';
-			}
-
 			foreach ($attributes as $key => $val)
 			{
 				$atts .= ' '.$key.'="'.$val.'"';
@@ -966,6 +919,13 @@
 
 			return $atts;
 		}
+
+		if (is_string($attributes))
+		{
+			return ' '.$attributes;
+		}
+
+		return FALSE;
 	}
 }
 
@@ -988,7 +948,7 @@
 		// We set this as a variable since we're returning by reference.
 		$return = FALSE;
 
-		if (FALSE !== ($object = $CI->load->is_loaded('form_validation')))
+		if (FALSE !== ($object = $CI->load->is_loaded('Form_validation')))
 		{
 			if ( ! isset($CI->$object) OR ! is_object($CI->$object))
 			{
diff --git a/system/helpers/html_helper.php b/system/helpers/html_helper.php
index ece3958..988eee7 100644
--- a/system/helpers/html_helper.php
+++ b/system/helpers/html_helper.php
@@ -199,15 +199,13 @@
 		{
 			if ($k === 'src' && strpos($v, '://') === FALSE)
 			{
-				$CI =& get_instance();
-
 				if ($index_page === TRUE)
 				{
-					$img .= ' src="'.$CI->config->site_url($v).'"';
+					$img .= ' src="'.get_instance()->config->site_url($v).'"';
 				}
 				else
 				{
-					$img .= ' src="'.$CI->config->slash_item('base_url').$v.'"';
+					$img .= ' src="'.get_instance()->config->slash_item('base_url').$v.'"';
 				}
 			}
 			else
diff --git a/system/helpers/language_helper.php b/system/helpers/language_helper.php
index 4d571a7..d7aa8e6 100644
--- a/system/helpers/language_helper.php
+++ b/system/helpers/language_helper.php
@@ -52,8 +52,7 @@
 	 */
 	function lang($line, $for = '', $attributes = array())
 	{
-		$CI =& get_instance();
-		$line = $CI->lang->line($line);
+		$line = get_instance()->lang->line($line);
 
 		if ($for !== '')
 		{
diff --git a/system/helpers/security_helper.php b/system/helpers/security_helper.php
index 4bb94a2..7a6df54 100644
--- a/system/helpers/security_helper.php
+++ b/system/helpers/security_helper.php
@@ -49,8 +49,7 @@
 	 */
 	function xss_clean($str, $is_image = FALSE)
 	{
-		$CI =& get_instance();
-		return $CI->security->xss_clean($str, $is_image);
+		return get_instance()->security->xss_clean($str, $is_image);
 	}
 }
 
@@ -66,8 +65,7 @@
 	 */
 	function sanitize_filename($filename)
 	{
-		$CI =& get_instance();
-		return $CI->security->sanitize_filename($filename);
+		return get_instance()->security->sanitize_filename($filename);
 	}
 }
 
@@ -107,8 +105,7 @@
 	 */
 	function strip_image_tags($str)
 	{
-		$CI =& get_instance();
-		return $CI->security->strip_image_tags($str);
+		return get_instance()->security->strip_image_tags($str);
 	}
 }
 
diff --git a/system/helpers/text_helper.php b/system/helpers/text_helper.php
index b2351db..bda8446 100644
--- a/system/helpers/text_helper.php
+++ b/system/helpers/text_helper.php
@@ -127,7 +127,7 @@
 	function ascii_to_entities($str)
 	{
 		$out = '';
-		for ($i = 0, $s = strlen($str), $count = 1, $temp = array(); $i < $s; $i++)
+		for ($i = 0, $s = strlen($str) - 1, $count = 1, $temp = array(); $i <= $s; $i++)
 		{
 			$ordinal = ord($str[$i]);
 
@@ -164,6 +164,11 @@
 					$count = 1;
 					$temp = array();
 				}
+				// If this is the last iteration, just output whatever we have
+				elseif ($i === $s)
+				{
+					$out .= '&#'.implode(';', $temp).';';
+				}
 			}
 		}
 
@@ -329,25 +334,17 @@
 	 *
 	 * Highlights a phrase within a text string
 	 *
-	 * @param	string	the text string
-	 * @param	string	the phrase you'd like to highlight
-	 * @param	string	the openging tag to precede the phrase with
-	 * @param	string	the closing tag to end the phrase with
+	 * @param	string	$str		the text string
+	 * @param	string	$phrase		the phrase you'd like to highlight
+	 * @param	string	$tag_open	the openging tag to precede the phrase with
+	 * @param	string	$tag_close	the closing tag to end the phrase with
 	 * @return	string
 	 */
-	function highlight_phrase($str, $phrase, $tag_open = '<strong>', $tag_close = '</strong>')
+	function highlight_phrase($str, $phrase, $tag_open = '<mark>', $tag_close = '</mark>')
 	{
-		if ($str === '')
-		{
-			return '';
-		}
-
-		if ($phrase !== '')
-		{
-			return preg_replace('/('.preg_quote($phrase, '/').')/i', $tag_open.'\\1'.$tag_close, $str);
-		}
-
-		return $str;
+		return ($str !== '' && $phrase !== '')
+			? preg_replace('/('.preg_quote($phrase, '/').')/i', $tag_open.'\\1'.$tag_close, $str)
+			: $str;
 	}
 }
 
diff --git a/system/helpers/url_helper.php b/system/helpers/url_helper.php
index fbb4a1b..f9650cd 100644
--- a/system/helpers/url_helper.php
+++ b/system/helpers/url_helper.php
@@ -52,14 +52,7 @@
 	 */
 	function site_url($uri = '', $protocol = NULL)
 	{
-		$uri = get_instance()->config->site_url($uri);
-
-		if (isset($protocol))
-		{
-			return $protocol.substr($uri, strpos($uri, '://'));
-		}
-
-		return $uri;
+		return get_instance()->config->site_url($uri, $protocol);
 	}
 }
 
@@ -80,14 +73,7 @@
 	 */
 	function base_url($uri = '', $protocol = NULL)
 	{
-		$uri = get_instance()->config->base_url($uri);
-
-		if (isset($protocol))
-		{
-			return $protocol.substr($uri, strpos($uri, '://'));
-		}
-
-		return $uri;
+		return get_instance()->config->base_url($uri, $protocol);
 	}
 }
 
@@ -123,8 +109,7 @@
 	 */
 	function uri_string()
 	{
-		$CI =& get_instance();
-		return $CI->uri->uri_string();
+		return get_instance()->uri->uri_string();
 	}
 }
 
@@ -141,8 +126,7 @@
 	 */
 	function index_page()
 	{
-		$CI =& get_instance();
-		return $CI->config->item('index_page');
+		return get_instance()->config->item('index_page');
 	}
 }
 
@@ -548,11 +532,16 @@
 		}
 		elseif ($method !== 'refresh' && (empty($code) OR ! is_numeric($code)))
 		{
-			// Reference: http://en.wikipedia.org/wiki/Post/Redirect/Get
-			$code = (isset($_SERVER['REQUEST_METHOD'], $_SERVER['SERVER_PROTOCOL'])
-					&& $_SERVER['REQUEST_METHOD'] === 'POST'
-					&& $_SERVER['SERVER_PROTOCOL'] === 'HTTP/1.1')
-				? 303 : 302;
+			if (isset($_SERVER['SERVER_PROTOCOL'], $_SERVER['REQUEST_METHOD']) && $_SERVER['SERVER_PROTOCOL'] === 'HTTP/1.1')
+			{
+				$code = ($_SERVER['REQUEST_METHOD'] !== 'GET')
+					? 303	// reference: http://en.wikipedia.org/wiki/Post/Redirect/Get
+					: 307;
+			}
+			else
+			{
+				$code = 302;
+			}
 		}
 
 		switch ($method)
diff --git a/system/language/english/ftp_lang.php b/system/language/english/ftp_lang.php
index ae4086f..042ab55 100644
--- a/system/language/english/ftp_lang.php
+++ b/system/language/english/ftp_lang.php
@@ -26,18 +26,18 @@
  */
 defined('BASEPATH') OR exit('No direct script access allowed');
 
-$lang['ftp_no_connection']			= 'Unable to locate a valid connection ID. Please make sure you are connected before peforming any file routines.';
+$lang['ftp_no_connection']		= 'Unable to locate a valid connection ID. Please make sure you are connected before peforming any file routines.';
 $lang['ftp_unable_to_connect']		= 'Unable to connect to your FTP server using the supplied hostname.';
 $lang['ftp_unable_to_login']		= 'Unable to login to your FTP server. Please check your username and password.';
-$lang['ftp_unable_to_makdir']		= 'Unable to create the directory you have specified.';
+$lang['ftp_unable_to_mkdir']		= 'Unable to create the directory you have specified.';
 $lang['ftp_unable_to_changedir']	= 'Unable to change directories.';
-$lang['ftp_unable_to_chmod']		= 'Unable to set file permissions. Please check your path. Note: This feature is only available in PHP 5 or higher.';
+$lang['ftp_unable_to_chmod']		= 'Unable to set file permissions. Please check your path.';
 $lang['ftp_unable_to_upload']		= 'Unable to upload the specified file. Please check your path.';
 $lang['ftp_unable_to_download']		= 'Unable to download the specified file. Please check your path.';
-$lang['ftp_no_source_file']			= 'Unable to locate the source file. Please check your path.';
+$lang['ftp_no_source_file']		= 'Unable to locate the source file. Please check your path.';
 $lang['ftp_unable_to_rename']		= 'Unable to rename the file.';
 $lang['ftp_unable_to_delete']		= 'Unable to delete the file.';
-$lang['ftp_unable_to_move']			= 'Unable to move the file. Please make sure the destination directory exists.';
+$lang['ftp_unable_to_move']		= 'Unable to move the file. Please make sure the destination directory exists.';
 
 /* End of file ftp_lang.php */
 /* Location: ./system/language/english/ftp_lang.php */
\ No newline at end of file
diff --git a/system/libraries/Cache/Cache.php b/system/libraries/Cache/Cache.php
index e1089f7..2dffa35 100644
--- a/system/libraries/Cache/Cache.php
+++ b/system/libraries/Cache/Cache.php
@@ -106,7 +106,7 @@
 
 		isset($config['key_prefix']) && $this->key_prefix = $config['key_prefix'];
 
-		if (isset($config['backup']) && in_array('cache_'.$config['backup'], $this->valid_drivers))
+		if (isset($config['backup']) && in_array($config['backup'], $this->valid_drivers))
 		{
 			$this->_backup_driver = $config['backup'];
 		}
@@ -123,6 +123,7 @@
 			else
 			{
 				// Backup is supported. Set it to primary.
+				log_message('debug', 'Cache adapter "'.$this->_adapter.'" is unavailable. Falling back to "'.$this->_backup_driver.'" backup adapter.');
 				$this->_adapter = $this->_backup_driver;
 			}
 		}
@@ -149,14 +150,15 @@
 	/**
 	 * Cache Save
 	 *
-	 * @param	string	$id		Cache ID
-	 * @param	mixed	$data		Data to store
-	 * @param	int	$ttl = 60	Cache TTL (in seconds)
+	 * @param	string	$id	Cache ID
+	 * @param	mixed	$data	Data to store
+	 * @param	int	$ttl	Cache TTL (in seconds)
+	 * @param	bool	$raw	Whether to store the raw value
 	 * @return	bool	TRUE on success, FALSE on failure
 	 */
-	public function save($id, $data, $ttl = 60)
+	public function save($id, $data, $ttl = 60, $raw = FALSE)
 	{
-		return $this->{$this->_adapter}->save($this->key_prefix.$id, $data, $ttl);
+		return $this->{$this->_adapter}->save($this->key_prefix.$id, $data, $ttl, $raw);
 	}
 
 	// ------------------------------------------------------------------------
@@ -175,6 +177,34 @@
 	// ------------------------------------------------------------------------
 
 	/**
+	 * Increment a raw value
+	 *
+	 * @param	string	$id	Cache ID
+	 * @param	int	$offset	Step/value to add
+	 * @return	mixed	New value on success or FALSE on failure
+	 */
+	public function increment($id, $offset = 1)
+	{
+		return $this->{$this->_adapter}->increment($id, $offset);
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * Decrement a raw value
+	 *
+	 * @param	string	$id	Cache ID
+	 * @param	int	$offset	Step/value to reduce by
+	 * @return	mixed	New value on success or FALSE on failure
+	 */
+	public function decrement($id, $offset = 1)
+	{
+		return $this->{$this->_adapter}->decrement($id, $offset);
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
 	 * Clean the cache
 	 *
 	 * @return	bool	TRUE on success, FALSE on failure
diff --git a/system/libraries/Cache/drivers/Cache_apc.php b/system/libraries/Cache/drivers/Cache_apc.php
index 127a220..b5381dd 100644
--- a/system/libraries/Cache/drivers/Cache_apc.php
+++ b/system/libraries/Cache/drivers/Cache_apc.php
@@ -51,8 +51,14 @@
 		$success = FALSE;
 		$data = apc_fetch($id, $success);
 
-		return ($success === TRUE && is_array($data))
-			? unserialize($data[0]) : FALSE;
+		if ($success === TRUE)
+		{
+			return is_array($data)
+				? unserialize($data[0])
+				: $data;
+		}
+
+		return FALSE;
 	}
 
 	// ------------------------------------------------------------------------
@@ -60,16 +66,21 @@
 	/**
 	 * Cache Save
 	 *
-	 * @param	string	Unique Key
-	 * @param	mixed	Data to store
-	 * @param	int	Length of time (in seconds) to cache the data
-	 *
-	 * @return	bool	true on success/false on failure
+	 * @param	string	$id	Cache ID
+	 * @param	mixed	$data	Data to store
+	 * @param	int	$ttol	Length of time (in seconds) to cache the data
+	 * @param	bool	$raw	Whether to store the raw value
+	 * @return	bool	TRUE on success, FALSE on failure
 	 */
-	public function save($id, $data, $ttl = 60)
+	public function save($id, $data, $ttl = 60, $raw = FALSE)
 	{
 		$ttl = (int) $ttl;
-		return apc_store($id, array(serialize($data), time(), $ttl), $ttl);
+
+		return apc_store(
+			$id,
+			($raw === TRUE ? $data : array(serialize($data), time(), $ttl)),
+			$ttl
+		);
 	}
 
 	// ------------------------------------------------------------------------
@@ -88,6 +99,34 @@
 	// ------------------------------------------------------------------------
 
 	/**
+	 * Increment a raw value
+	 *
+	 * @param	string	$id	Cache ID
+	 * @param	int	$offset	Step/value to add
+	 * @return	mixed	New value on success or FALSE on failure
+	 */
+	public function increment($id, $offset = 1)
+	{
+		return apc_inc($id, $offset);
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * Decrement a raw value
+	 *
+	 * @param	string	$id	Cache ID
+	 * @param	int	$offset	Step/value to reduce by
+	 * @return	mixed	New value on success or FALSE on failure
+	 */
+	public function decrement($id, $offset = 1)
+	{
+		return apc_dec($id, $offset);
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
 	 * Clean the cache
 	 *
 	 * @return	bool	false on failure/true on success
@@ -150,7 +189,7 @@
 	{
 		if ( ! extension_loaded('apc') OR ! (bool) @ini_get('apc.enabled'))
 		{
-			log_message('error', 'The APC PHP extension must be loaded to use APC Cache.');
+			log_message('debug', 'The APC PHP extension must be loaded to use APC Cache.');
 			return FALSE;
 		}
 
diff --git a/system/libraries/Cache/drivers/Cache_dummy.php b/system/libraries/Cache/drivers/Cache_dummy.php
index d9af377..7e2b907 100644
--- a/system/libraries/Cache/drivers/Cache_dummy.php
+++ b/system/libraries/Cache/drivers/Cache_dummy.php
@@ -58,9 +58,10 @@
 	 * @param	string	Unique Key
 	 * @param	mixed	Data to store
 	 * @param	int	Length of time (in seconds) to cache the data
+	 * @param	bool	Whether to store the raw value
 	 * @return	bool	TRUE, Simulating success
 	 */
-	public function save($id, $data, $ttl = 60)
+	public function save($id, $data, $ttl = 60, $raw = FALSE)
 	{
 		return TRUE;
 	}
@@ -81,6 +82,34 @@
 	// ------------------------------------------------------------------------
 
 	/**
+	 * Increment a raw value
+	 *
+	 * @param	string	$id	Cache ID
+	 * @param	int	$offset	Step/value to add
+	 * @return	mixed	New value on success or FALSE on failure
+	 */
+	public function increment($id, $offset = 1)
+	{
+		return TRUE;
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * Decrement a raw value
+	 *
+	 * @param	string	$id	Cache ID
+	 * @param	int	$offset	Step/value to reduce by
+	 * @return	mixed	New value on success or FALSE on failure
+	 */
+	public function decrement($id, $offset = 1)
+	{
+		return TRUE;
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
 	 * Clean the cache
 	 *
 	 * @return	bool	TRUE, simulating success
diff --git a/system/libraries/Cache/drivers/Cache_file.php b/system/libraries/Cache/drivers/Cache_file.php
index 769bd5a..8c99c5e 100644
--- a/system/libraries/Cache/drivers/Cache_file.php
+++ b/system/libraries/Cache/drivers/Cache_file.php
@@ -62,25 +62,13 @@
 	/**
 	 * Fetch from cache
 	 *
-	 * @param	mixed	unique key id
-	 * @return	mixed	data on success/false on failure
+	 * @param	string	$id	Cache ID
+	 * @return	mixed	Data on success, FALSE on failure
 	 */
 	public function get($id)
 	{
-		if ( ! file_exists($this->_cache_path.$id))
-		{
-			return FALSE;
-		}
-
-		$data = unserialize(file_get_contents($this->_cache_path.$id));
-
-		if ($data['ttl'] > 0 && time() > $data['time'] + $data['ttl'])
-		{
-			unlink($this->_cache_path.$id);
-			return FALSE;
-		}
-
-		return $data['data'];
+		$data = $this->_get($id);
+		return is_array($data) ? $data['data'] : FALSE;
 	}
 
 	// ------------------------------------------------------------------------
@@ -88,13 +76,13 @@
 	/**
 	 * Save into cache
 	 *
-	 * @param	string	unique key
-	 * @param	mixed	data to store
-	 * @param	int	length of time (in seconds) the cache is valid
-	 *				- Default is 60 seconds
-	 * @return	bool	true on success/false on failure
+	 * @param	string	$id	Cache ID
+	 * @param	mixed	$data	Data to store
+	 * @param	int	$ttl	Time to live in seconds
+	 * @param	bool	$raw	Whether to store the raw value (unused)
+	 * @return	bool	TRUE on success, FALSE on failure
 	 */
-	public function save($id, $data, $ttl = 60)
+	public function save($id, $data, $ttl = 60, $raw = FALSE)
 	{
 		$contents = array(
 			'time'		=> time(),
@@ -127,6 +115,54 @@
 	// ------------------------------------------------------------------------
 
 	/**
+	 * Increment a raw value
+	 *
+	 * @param	string	$id	Cache ID
+	 * @param	int	$offset	Step/value to add
+	 * @return	New value on success, FALSE on failure
+	 */
+	public function increment($id, $offset = 1)
+	{
+		$data = $this->_get($id);
+
+		if ($data === FALSE OR ! is_int($data['data']))
+		{
+			return FALSE;
+		}
+
+		$new_value = $data['data'] + $offset;
+		return $this->save($id, $new_value, $data['ttl'])
+			? $new_value
+			: FALSE;
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * Decrement a raw value
+	 *
+	 * @param	string	$id	Cache ID
+	 * @param	int	$offset	Step/value to reduce by
+	 * @return	New value on success, FALSE on failure
+	 */
+	public function decrement($id, $offset = 1)
+	{
+		$data = $this->_get($id);
+
+		if ($data === FALSE OR ! is_int($data['data']))
+		{
+			return FALSE;
+		}
+
+		$new_value = $data['data'] - $offset;
+		return $this->save($id, $new_value, $data['ttl'])
+			? $new_value
+			: FALSE;
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
 	 * Clean the Cache
 	 *
 	 * @return	bool	false on failure/true on success
@@ -200,6 +236,34 @@
 		return is_really_writable($this->_cache_path);
 	}
 
+	// ------------------------------------------------------------------------
+
+	/**
+	 * Get all data
+	 *
+	 * Internal method to get all the relevant data about a cache item
+	 *
+	 * @param	string	$id	Cache ID
+	 * @return	mixed	Data array on success or FALSE on failure
+	 */
+	protected function _get($id)
+	{
+		if ( ! file_exists($this->_cache_path.$id))
+		{
+			return FALSE;
+		}
+
+		$data = unserialize(file_get_contents($this->_cache_path.$id));
+
+		if ($data['ttl'] > 0 && time() > $data['time'] + $data['ttl'])
+		{
+			unlink($this->_cache_path.$id);
+			return FALSE;
+		}
+
+		return $data;
+	}
+
 }
 
 /* End of file Cache_file.php */
diff --git a/system/libraries/Cache/drivers/Cache_memcached.php b/system/libraries/Cache/drivers/Cache_memcached.php
index 35d9104..d598477 100644
--- a/system/libraries/Cache/drivers/Cache_memcached.php
+++ b/system/libraries/Cache/drivers/Cache_memcached.php
@@ -60,14 +60,14 @@
 	/**
 	 * Fetch from cache
 	 *
-	 * @param	mixed	unique key id
-	 * @return	mixed	data on success/false on failure
+	 * @param	string	$id	Cache ID
+	 * @return	mixed	Data on success, FALSE on failure
 	 */
 	public function get($id)
 	{
 		$data = $this->_memcached->get($id);
 
-		return is_array($data) ? $data[0] : FALSE;
+		return is_array($data) ? $data[0] : $data;
 	}
 
 	// ------------------------------------------------------------------------
@@ -75,20 +75,26 @@
 	/**
 	 * Save
 	 *
-	 * @param	string	unique identifier
-	 * @param	mixed	data being cached
-	 * @param	int	time to live
-	 * @return	bool	true on success, false on failure
+	 * @param	string	$id	Cache ID
+	 * @param	mixed	$data	Data being cached
+	 * @param	int	$ttl	Time to live
+	 * @param	bool	$raw	Whether to store the raw value
+	 * @return	bool	TRUE on success, FALSE on failure
 	 */
-	public function save($id, $data, $ttl = 60)
+	public function save($id, $data, $ttl = 60, $raw = FALSE)
 	{
+		if ($raw !== TRUE)
+		{
+			$data = array($data, time(), $ttl);
+		}
+
 		if (get_class($this->_memcached) === 'Memcached')
 		{
-			return $this->_memcached->set($id, array($data, time(), $ttl), $ttl);
+			return $this->_memcached->set($id, $data, $ttl);
 		}
 		elseif (get_class($this->_memcached) === 'Memcache')
 		{
-			return $this->_memcached->set($id, array($data, time(), $ttl), 0, $ttl);
+			return $this->_memcached->set($id, $data, 0, $ttl);
 		}
 
 		return FALSE;
@@ -110,6 +116,34 @@
 	// ------------------------------------------------------------------------
 
 	/**
+	 * Increment a raw value
+	 *
+	 * @param	string	$id	Cache ID
+	 * @param	int	$offset	Step/value to add
+	 * @return	mixed	New value on success or FALSE on failure
+	 */
+	public function increment($id, $offset = 1)
+	{
+		return $this->_memcached->increment($id, $offset);
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * Decrement a raw value
+	 *
+	 * @param	string	$id	Cache ID
+	 * @param	int	$offset	Step/value to reduce by
+	 * @return	mixed	New value on success or FALSE on failure
+	 */
+	public function decrement($id, $offset = 1)
+	{
+		return $this->_memcached->decrement($id, $offset);
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
 	 * Clean the Cache
 	 *
 	 * @return	bool	false on failure/true on success
@@ -240,7 +274,7 @@
 	{
 		if ( ! extension_loaded('memcached') && ! extension_loaded('memcache'))
 		{
-			log_message('error', 'The Memcached Extension must be loaded to use Memcached Cache.');
+			log_message('debug', 'The Memcached Extension must be loaded to use Memcached Cache.');
 			return FALSE;
 		}
 
diff --git a/system/libraries/Cache/drivers/Cache_redis.php b/system/libraries/Cache/drivers/Cache_redis.php
index 484f284..b6fddf0 100644
--- a/system/libraries/Cache/drivers/Cache_redis.php
+++ b/system/libraries/Cache/drivers/Cache_redis.php
@@ -44,6 +44,7 @@
 	 * @var	array
 	 */
 	protected static $_default_config = array(
+		'socket_type' => 'tcp',
 		'host' => '127.0.0.1',
 		'password' => NULL,
 		'port' => 6379,
@@ -62,7 +63,7 @@
 	/**
 	 * Get cache
 	 *
-	 * @param	string	Cache key identifier
+	 * @param	string	Cache ID
 	 * @return	mixed
 	 */
 	public function get($key)
@@ -75,16 +76,17 @@
 	/**
 	 * Save cache
 	 *
-	 * @param	string	Cache key identifier
-	 * @param	mixed	Data to save
-	 * @param	int	Time to live
-	 * @return	bool
+	 * @param	string	$id	Cache ID
+	 * @param	mixed	$data	Data to save
+	 * @param	int	$ttl	Time to live in seconds
+	 * @param	bool	$raw	Whether to store the raw value (unused)
+	 * @return	bool	TRUE on success, FALSE on failure
 	 */
-	public function save($key, $value, $ttl = NULL)
+	public function save($id, $data, $ttl = 60, $raw = FALSE)
 	{
 		return ($ttl)
-			? $this->_redis->setex($key, $ttl, $value)
-			: $this->_redis->set($key, $value);
+			? $this->_redis->setex($id, $ttl, $data)
+			: $this->_redis->set($id, $data);
 	}
 
 	// ------------------------------------------------------------------------
@@ -103,6 +105,38 @@
 	// ------------------------------------------------------------------------
 
 	/**
+	 * Increment a raw value
+	 *
+	 * @param	string	$id	Cache ID
+	 * @param	int	$offset	Step/value to add
+	 * @return	mixed	New value on success or FALSE on failure
+	 */
+	public function increment($id, $offset = 1)
+	{
+		return $this->_redis->exists($id)
+			? $this->_redis->incr($id, $offset)
+			: FALSE;
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * Decrement a raw value
+	 *
+	 * @param	string	$id	Cache ID
+	 * @param	int	$offset	Step/value to reduce by
+	 * @return	mixed	New value on success or FALSE on failure
+	 */
+	public function decrement($id, $offset = 1)
+	{
+		return $this->_redis->exists($id)
+			? $this->_redis->decr($id, $offset)
+			: FALSE;
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
 	 * Clean cache
 	 *
 	 * @return	bool
@@ -163,12 +197,11 @@
 	{
 		if (extension_loaded('redis'))
 		{
-			$this->_setup_redis();
-			return TRUE;
+			return $this->_setup_redis();
 		}
 		else
 		{
-			log_message('error', 'The Redis extension must be loaded to use Redis cache.');
+			log_message('debug', 'The Redis extension must be loaded to use Redis cache.');
 			return FALSE;
 		}
 	}
@@ -200,17 +233,33 @@
 
 		try
 		{
-			$this->_redis->connect($config['host'], $config['port'], $config['timeout']);
+			if ($config['socket_type'] === 'unix')
+			{
+				$success = $this->_redis->connect($config['socket']);
+			}
+			else // tcp socket
+			{
+				$success = $this->_redis->connect($config['host'], $config['port'], $config['timeout']);
+			}
+
+			if ( ! $success)
+			{
+				log_message('debug', 'Cache: Redis connection refused. Check the config.');
+				return FALSE;
+			}
 		}
 		catch (RedisException $e)
 		{
-			show_error('Redis connection refused. ' . $e->getMessage());
+			log_message('debug', 'Cache: Redis connection refused ('.$e->getMessage().')');
+			return FALSE;
 		}
 
 		if (isset($config['password']))
 		{
 			$this->_redis->auth($config['password']);
 		}
+
+		return TRUE;
 	}
 
 	// ------------------------------------------------------------------------
diff --git a/system/libraries/Cache/drivers/Cache_wincache.php b/system/libraries/Cache/drivers/Cache_wincache.php
index d749978..25c18ab 100644
--- a/system/libraries/Cache/drivers/Cache_wincache.php
+++ b/system/libraries/Cache/drivers/Cache_wincache.php
@@ -46,8 +46,8 @@
 	 * Look for a value in the cache. If it exists, return the data,
 	 * if not, return FALSE
 	 *
-	 * @param	string
-	 * @return	mixed	value that is stored/FALSE on failure
+	 * @param	string	$id	Cache Ide
+	 * @return	mixed	Value that is stored/FALSE on failure
 	 */
 	public function get($id)
 	{
@@ -63,12 +63,13 @@
 	/**
 	 * Cache Save
 	 *
-	 * @param	string	Unique Key
-	 * @param	mixed	Data to store
-	 * @param	int	Length of time (in seconds) to cache the data
+	 * @param	string	$id	Cache ID
+	 * @param	mixed	$data	Data to store
+	 * @param	int	$ttl	Time to live (in seconds)
+	 * @param	bool	$raw	Whether to store the raw value (unused)
 	 * @return	bool	true on success/false on failure
 	 */
-	public function save($id, $data, $ttl = 60)
+	public function save($id, $data, $ttl = 60, $raw = FALSE)
 	{
 		return wincache_ucache_set($id, $data, $ttl);
 	}
@@ -89,6 +90,40 @@
 	// ------------------------------------------------------------------------
 
 	/**
+	 * Increment a raw value
+	 *
+	 * @param	string	$id	Cache ID
+	 * @param	int	$offset	Step/value to add
+	 * @return	mixed	New value on success or FALSE on failure
+	 */
+	public function increment($id, $offset = 1)
+	{
+		$success = FALSE;
+		$value = wincache_ucache_inc($id, $offset, $success);
+
+		return ($success === TRUE) ? $value : FALSE;
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * Decrement a raw value
+	 *
+	 * @param	string	$id	Cache ID
+	 * @param	int	$offset	Step/value to reduce by
+	 * @return	mixed	New value on success or FALSE on failure
+	 */
+	public function decrement($id, $offset = 1)
+	{
+		$success = FALSE;
+		$value = wincache_ucache_dec($id, $offset, $success);
+
+		return ($success === TRUE) ? $value : FALSE;
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
 	 * Clean the cache
 	 *
 	 * @return	bool	false on failure/true on success
@@ -150,7 +185,7 @@
 	{
 		if ( ! extension_loaded('wincache'))
 		{
-			log_message('error', 'The Wincache PHP extension must be loaded to use Wincache Cache.');
+			log_message('debug', 'The Wincache PHP extension must be loaded to use Wincache Cache.');
 			return FALSE;
 		}
 
diff --git a/system/libraries/Calendar.php b/system/libraries/Calendar.php
index 9c68c94..fc65999 100644
--- a/system/libraries/Calendar.php
+++ b/system/libraries/Calendar.php
@@ -96,6 +96,13 @@
 	public $next_prev_url		= '';
 
 	/**
+	 * Show days of other months
+	 *
+	 * @var bool
+	 */
+	public $show_other_days = FALSE;
+
+	/**
 	 * Class constructor
 	 *
 	 * Loads the calendar language file and sets the default time reference.
@@ -143,6 +150,12 @@
 				$this->$key = $val;
 			}
 		}
+
+		// Set the next_prev_url to the controller if required but not defined
+		if ($this->show_next_prev === TRUE && empty($this->next_prev_url))
+		{
+			$this->next_prev_url = $this->CI->config->site_url($this->CI->router->class.'/'.$this->CI->router->method);
+		}
 	}
 
 	// --------------------------------------------------------------------
@@ -261,10 +274,10 @@
 
 			for ($i = 0; $i < 7; $i++)
 			{
-				$out .= ($is_current_month === TRUE && $day == $cur_day) ? $this->temp['cal_cell_start_today'] : $this->temp['cal_cell_start'];
-
 				if ($day > 0 && $day <= $total_days)
 				{
+					$out .= ($is_current_month === TRUE && $day == $cur_day) ? $this->temp['cal_cell_start_today'] : $this->temp['cal_cell_start'];
+
 					if (isset($data[$day]))
 					{
 						// Cells with content
@@ -279,14 +292,34 @@
 								$this->temp['cal_cell_no_content_today'] : $this->temp['cal_cell_no_content'];
 						$out .= str_replace('{day}', $day, $temp);
 					}
+
+					$out .= ($is_current_month === TRUE && $day == $cur_day) ? $this->temp['cal_cell_end_today'] : $this->temp['cal_cell_end'];
+				}
+				elseif ($this->show_other_days === TRUE)
+				{
+					$out .= $this->temp['cal_cell_start_other'];
+
+					if ($day <= 0)
+					{
+						// Day of previous month
+						$prev_month = $this->adjust_date($month - 1, $year);
+						$prev_month_days = $this->get_total_days($prev_month['month'], $prev_month['year']);
+						$out .= str_replace('{day}', $prev_month_days + $day, $this->temp['cal_cell_other']);
+					}
+					else
+					{
+						// Day of next month
+						$out .= str_replace('{day}', $day - $total_days, $this->temp['cal_cell_other']);
+					}
+
+					$out .= $this->temp['cal_cell_end_other'];
 				}
 				else
 				{
 					// Blank cells
-					$out .= $this->temp['cal_cell_blank'];
+					$out .= $this->temp['cal_cell_start'].$this->temp['cal_cell_blank'].$this->temp['cal_cell_end'];
 				}
 
-				$out .= ($is_current_month === TRUE && $day == $cur_day) ? $this->temp['cal_cell_end_today'] : $this->temp['cal_cell_end'];
 				$day++;
 			}
 
@@ -457,13 +490,16 @@
 			'cal_row_start'				=> '<tr>',
 			'cal_cell_start'			=> '<td>',
 			'cal_cell_start_today'		=> '<td>',
+			'cal_cell_start_other'		=> '<td style="color: #666;">',
 			'cal_cell_content'			=> '<a href="{content}">{day}</a>',
 			'cal_cell_content_today'	=> '<a href="{content}"><strong>{day}</strong></a>',
 			'cal_cell_no_content'		=> '{day}',
 			'cal_cell_no_content_today'	=> '<strong>{day}</strong>',
 			'cal_cell_blank'			=> '&nbsp;',
+			'cal_cell_other'			=> '{day}',
 			'cal_cell_end'				=> '</td>',
 			'cal_cell_end_today'		=> '</td>',
+			'cal_cell_end_other'		=> '</td>',
 			'cal_row_end'				=> '</tr>',
 			'table_close'				=> '</table>'
 		);
@@ -490,7 +526,7 @@
 
 		$today = array('cal_cell_start_today', 'cal_cell_content_today', 'cal_cell_no_content_today', 'cal_cell_end_today');
 
-		foreach (array('table_open', 'table_close', 'heading_row_start', 'heading_previous_cell', 'heading_title_cell', 'heading_next_cell', 'heading_row_end', 'week_row_start', 'week_day_cell', 'week_row_end', 'cal_row_start', 'cal_cell_start', 'cal_cell_content', 'cal_cell_no_content', 'cal_cell_blank', 'cal_cell_end', 'cal_row_end', 'cal_cell_start_today', 'cal_cell_content_today', 'cal_cell_no_content_today', 'cal_cell_end_today') as $val)
+		foreach (array('table_open', 'table_close', 'heading_row_start', 'heading_previous_cell', 'heading_title_cell', 'heading_next_cell', 'heading_row_end', 'week_row_start', 'week_day_cell', 'week_row_end', 'cal_row_start', 'cal_cell_start', 'cal_cell_content', 'cal_cell_no_content', 'cal_cell_blank', 'cal_cell_end', 'cal_row_end', 'cal_cell_start_today', 'cal_cell_content_today', 'cal_cell_no_content_today', 'cal_cell_end_today', 'cal_cell_start_other', 'cal_cell_other', 'cal_cell_end_other') as $val)
 		{
 			if (preg_match('/\{'.$val.'\}(.*?)\{\/'.$val.'\}/si', $this->template, $match))
 			{
diff --git a/system/libraries/Email.php b/system/libraries/Email.php
index 46ffaa1..f4efff8 100644
--- a/system/libraries/Email.php
+++ b/system/libraries/Email.php
@@ -399,9 +399,9 @@
 		else
 		{
 			$this->_smtp_auth = ! ($this->smtp_user === '' && $this->smtp_pass === '');
-			$this->_safe_mode = (bool) @ini_get('safe_mode');
 		}
 
+		$this->_safe_mode = ( ! is_php('5.4') && (bool) @ini_get('safe_mode'));
 		$this->charset = strtoupper($this->charset);
 
 		log_message('debug', 'Email Class Initialized');
@@ -451,7 +451,6 @@
 		$this->clear();
 
 		$this->_smtp_auth = ! ($this->smtp_user === '' && $this->smtp_pass === '');
-		$this->_safe_mode = (bool) @ini_get('safe_mode');
 
 		return $this;
 	}
@@ -711,18 +710,42 @@
 	/**
 	 * Assign file attachments
 	 *
-	 * @param	string	$filename
+	 * @param	string	$file	Can be local path, URL or buffered content
 	 * @param	string	$disposition = 'attachment'
 	 * @param	string	$newname = NULL
 	 * @param	string	$mime = ''
 	 * @return	CI_Email
 	 */
-	public function attach($filename, $disposition = '', $newname = NULL, $mime = '')
+	public function attach($file, $disposition = '', $newname = NULL, $mime = '')
 	{
+		if ($mime === '')
+		{
+			if (strpos($file, '://') === FALSE && ! file_exists($file))
+			{
+				$this->_set_error_message('lang:email_attachment_missing', $file);
+				return FALSE;
+			}
+
+			if ( ! $fp = @fopen($file, FOPEN_READ))
+			{
+				$this->_set_error_message('lang:email_attachment_unreadable', $file);
+				return FALSE;
+			}
+
+			$file_content = stream_get_contents($fp);
+			$mime = $this->_mime_types(pathinfo($file, PATHINFO_EXTENSION));
+			fclose($fp);
+		}
+		else
+		{
+			$file_content =& $file; // buffered file
+		}
+
 		$this->_attachments[] = array(
-			'name'		=> array($filename, $newname),
+			'name'		=> array($file, $newname),
 			'disposition'	=> empty($disposition) ? 'attachment' : $disposition,  // Can also be 'inline'  Not sure if it matters
-			'type' 		=> $mime
+			'type'		=> $mime,
+			'content'	=> chunk_split(base64_encode($file_content))
 		);
 
 		return $this;
@@ -731,6 +754,35 @@
 	// --------------------------------------------------------------------
 
 	/**
+	 * Set and return attachment Content-ID
+	 *
+	 * Useful for attached inline pictures
+	 *
+	 * @param	string	$filename
+	 * @return	string
+	 */
+	public function attachment_cid($filename)
+	{
+		if ($this->multipart !== 'related')
+		{
+			$this->multipart = 'related'; // Thunderbird need this for inline images
+		}
+
+		for ($i = 0, $c = count($this->_attachments); $i < $c; $i++)
+		{
+			if ($this->_attachments[$i]['name'][0] === $filename)
+			{
+				$this->_attachments[$i]['cid'] = uniqid(basename($this->_attachments[$i]['name'][0]).'@');
+				return $this->_attachments[$i]['cid'];
+			}
+		}
+
+		return FALSE;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
 	 * Add a Header Item
 	 *
 	 * @param	string
@@ -1265,7 +1317,7 @@
 				}
 				else
 				{
-					$this->_finalbody = $hdr . $this->newline . $this->newline . $this->_body;
+					$this->_finalbody = $hdr.$this->newline.$this->newline.$this->_body;
 				}
 
 				return;
@@ -1275,11 +1327,11 @@
 				if ($this->send_multipart === FALSE)
 				{
 					$hdr .= 'Content-Type: text/html; charset='.$this->charset.$this->newline
-						.'Content-Transfer-Encoding: quoted-printable'.$this->newline.$this->newline;
+						.'Content-Transfer-Encoding: quoted-printable';
 				}
 				else
 				{
-					$hdr .= 'Content-Type: multipart/alternative; boundary="'.$this->_alt_boundary.'"'.$this->newline.$this->newline;
+					$hdr .= 'Content-Type: multipart/alternative; boundary="'.$this->_alt_boundary.'"';
 
 					$body .= $this->_get_mime_message().$this->newline.$this->newline
 						.'--'.$this->_alt_boundary.$this->newline
@@ -1300,7 +1352,7 @@
 				}
 				else
 				{
-					$this->_finalbody = $hdr.$this->_finalbody;
+					$this->_finalbody = $hdr.$this->newline.$this->newline.$this->_finalbody;
 				}
 
 				if ($this->send_multipart !== FALSE)
@@ -1312,25 +1364,25 @@
 
 			case 'plain-attach' :
 
-				$hdr .= 'Content-Type: multipart/'.$this->multipart.'; boundary="'.$this->_atc_boundary.'"'.$this->newline.$this->newline;
+				$hdr .= 'Content-Type: multipart/'.$this->multipart.'; boundary="'.$this->_atc_boundary.'"';
 
 				if ($this->_get_protocol() === 'mail')
 				{
 					$this->_header_str .= $hdr;
 				}
 
-				$body .= $this->_get_mime_message().$this->newline.$this->newline
+				$body .= $this->_get_mime_message().$this->newline
+					.$this->newline
 					.'--'.$this->_atc_boundary.$this->newline
-
 					.'Content-Type: text/plain; charset='.$this->charset.$this->newline
-					.'Content-Transfer-Encoding: '.$this->_get_encoding().$this->newline.$this->newline
-
+					.'Content-Transfer-Encoding: '.$this->_get_encoding().$this->newline
+					.$this->newline
 					.$this->_body.$this->newline.$this->newline;
 
 			break;
 			case 'html-attach' :
 
-				$hdr .= 'Content-Type: multipart/'.$this->multipart.'; boundary="'.$this->_atc_boundary.'"'.$this->newline.$this->newline;
+				$hdr .= 'Content-Type: multipart/'.$this->multipart.'; boundary="'.$this->_atc_boundary.'"';
 
 				if ($this->_get_protocol() === 'mail')
 				{
@@ -1362,45 +1414,22 @@
 			$filename = $this->_attachments[$i]['name'][0];
 			$basename = ($this->_attachments[$i]['name'][1] === NULL)
 				? basename($filename) : $this->_attachments[$i]['name'][1];
-			$ctype = $this->_attachments[$i]['type'];
-			$file_content = '';
-
-			if ($ctype === '')
-			{
-				if ( ! file_exists($filename))
-				{
-					$this->_set_error_message('lang:email_attachment_missing', $filename);
-					return FALSE;
-				}
-
-				$file = filesize($filename) +1;
-
-				if ( ! $fp = fopen($filename, FOPEN_READ))
-				{
-					$this->_set_error_message('lang:email_attachment_unreadable', $filename);
-					return FALSE;
-				}
-
-				$ctype = $this->_mime_types(pathinfo($filename, PATHINFO_EXTENSION));
-				$file_content = fread($fp, $file);
-				fclose($fp);
-			}
-			else
-			{
-				$file_content =& $this->_attachments[$i]['name'][0];
-			}
 
 			$attachment[$z++] = '--'.$this->_atc_boundary.$this->newline
-				.'Content-type: '.$ctype.'; '
+				.'Content-type: '.$this->_attachments[$i]['type'].'; '
 				.'name="'.$basename.'"'.$this->newline
 				.'Content-Disposition: '.$this->_attachments[$i]['disposition'].';'.$this->newline
-				.'Content-Transfer-Encoding: base64'.$this->newline;
+				.'Content-Transfer-Encoding: base64'.$this->newline
+				.(empty($this->_attachments[$i]['cid']) ? '' : 'Content-ID: <'.$this->_attachments[$i]['cid'].'>'.$this->newline);
 
-			$attachment[$z++] = chunk_split(base64_encode($file_content));
+			$attachment[$z++] = $this->_attachments[$i]['content'];
 		}
 
 		$body .= implode($this->newline, $attachment).$this->newline.'--'.$this->_atc_boundary.'--';
-		$this->_finalbody = ($this->_get_protocol() === 'mail') ? $body : $hdr.$body;
+		$this->_finalbody = ($this->_get_protocol() === 'mail')
+			? $body
+			: $hdr.$this->newline.$this->newline.$body;
+
 		return TRUE;
 	}
 
@@ -2068,7 +2097,16 @@
 	 */
 	protected function _send_data($data)
 	{
-		if ( ! fwrite($this->_smtp_connect, $data.$this->newline))
+		$data .= $this->newline;
+		for ($written = 0, $length = strlen($data); $written < $length; $written += $result)
+		{
+			if (($result = fwrite($this->_smtp_connect, substr($data, $written))) === FALSE)
+			{
+				break;
+			}
+		}
+
+		if ($result === FALSE)
 		{
 			$this->_set_error_message('lang:email_smtp_data_failure', $data);
 			return FALSE;
diff --git a/system/libraries/Form_validation.php b/system/libraries/Form_validation.php
index 40ba012..5848591 100644
--- a/system/libraries/Form_validation.php
+++ b/system/libraries/Form_validation.php
@@ -144,14 +144,16 @@
 	 * Set Rules
 	 *
 	 * This function takes an array of field names and validation
-	 * rules as input, validates the info, and stores it
+	 * rules as input, any custom error messages, validates the info, 
+	 * and stores it
 	 *
 	 * @param	mixed	$field
 	 * @param	string	$label
 	 * @param	mixed	$rules
+	 * @param	array	$errors
 	 * @return	CI_Form_validation
 	 */
-	public function set_rules($field, $label = '', $rules = '')
+	public function set_rules($field, $label = '', $rules = '', $errors = array())
 	{
 		// No reason to set rules if we have no POST data
 		// or a validation array has not been specified
@@ -175,8 +177,11 @@
 				// If the field label wasn't passed we use the field name
 				$label = isset($row['label']) ? $row['label'] : $row['field'];
 
+				// Add the custom error message array
+				$errors = (isset($row['errors']) && is_array($row['errors'])) ? $row['errors'] : array();
+
 				// Here we go!
-				$this->set_rules($row['field'], $label, $row['rules']);
+				$this->set_rules($row['field'], $label, $row['rules'], $errors);
 			}
 
 			return $this;
@@ -224,6 +229,7 @@
 			'field'		=> $field,
 			'label'		=> $label,
 			'rules'		=> $rules,
+			'errors'	=> $errors,
 			'is_array'	=> $is_array,
 			'keys'		=> $indexes,
 			'postdata'	=> NULL,
@@ -248,9 +254,9 @@
 	 * @param	array	$data
 	 * @return	void
 	 */
-	public function set_data($data = '')
+	public function set_data(array $data)
 	{
-		if ( ! empty($data) && is_array($data))
+		if ( ! empty($data))
 		{
 			$this->validation_data = $data;
 		}
@@ -304,12 +310,12 @@
 	 *
 	 * Gets the error message associated with a particular field
 	 *
-	 * @param	string	the field name
-	 * @param	string	the html start tag
-	 * @param 	strign	the html end tag
+	 * @param	string	$field	Field name
+	 * @param	string	$prefix	HTML start tag
+	 * @param 	string	$suffix	HTML end tag
 	 * @return	string
 	 */
-	public function error($field = '', $prefix = '', $suffix = '')
+	public function error($field, $prefix = '', $suffix = '')
 	{
 		if (empty($this->_field_data[$field]['error']))
 		{
@@ -414,17 +420,14 @@
 				return FALSE;
 			}
 
-			// Is there a validation rule for the particular URI being accessed?
-			$uri = ($group === '') ? trim($this->CI->uri->ruri_string(), '/') : $group;
+			if (empty($group))
+			{
+				// Is there a validation rule for the particular URI being accessed?
+				$group = trim($this->CI->uri->ruri_string(), '/');
+				isset($this->_config_rules[$group]) OR $group = $this->CI->router->class.'/'.$this->CI->router->method;
+			}
 
-			if ($uri !== '' && isset($this->_config_rules[$uri]))
-			{
-				$this->set_rules($this->_config_rules[$uri]);
-			}
-			else
-			{
-				$this->set_rules($this->_config_rules);
-			}
+			$this->set_rules(isset($this->_config_rules[$group]) ? $this->_config_rules[$group] : $this->_config_rules);
 
 			// Were we able to set the rules correctly?
 			if (count($this->_field_data) === 0)
@@ -583,7 +586,7 @@
 
 		// If the field is blank, but NOT required, no further tests are necessary
 		$callback = FALSE;
-		if ( ! in_array('required', $rules) && $postdata === NULL)
+		if ( ! in_array('required', $rules) && ($postdata === NULL OR $postdata === ''))
 		{
 			// Before we bail out, does the rule contain a callback?
 			if (preg_match('/(callback_\w+(\[.*?\])?)/', implode(' ', $rules), $match))
@@ -598,14 +601,19 @@
 		}
 
 		// Isset Test. Typically this rule will only apply to checkboxes.
-		if ($postdata === NULL && $callback === FALSE)
+		if (($postdata === NULL OR $postdata === '') && $callback === FALSE)
 		{
 			if (in_array('isset', $rules, TRUE) OR in_array('required', $rules))
 			{
 				// Set the message type
 				$type = in_array('required', $rules) ? 'required' : 'isset';
 
-				if (isset($this->_error_messages[$type]))
+				// Check if a custom message is defined
+				if (isset($this->_field_data[$row['field']]['errors'][$type]))
+				{
+					$line = $this->_field_data[$row['field']]['errors'][$type];
+				}
+				elseif (isset($this->_error_messages[$type]))
 				{
 					$line = $this->_error_messages[$type];
 				}
@@ -749,7 +757,12 @@
 			// Did the rule test negatively? If so, grab the error.
 			if ($result === FALSE)
 			{
-				if ( ! isset($this->_error_messages[$rule]))
+				// Check if a custom message is defined
+				if (isset($this->_field_data[$row['field']]['errors'][$rule]))
+				{
+					$line = $this->_field_data[$row['field']]['errors'][$rule];
+				}
+				elseif ( ! isset($this->_error_messages[$rule]))
 				{
 					if (FALSE === ($line = $this->CI->lang->line('form_validation_'.$rule))
 						// DEPRECATED support for non-prefixed keys
@@ -898,12 +911,19 @@
 		}
 
 		$field = $this->_field_data[$field]['postdata'];
+		$value = (string) $value;
 		if (is_array($field))
 		{
-			if ( ! in_array($value, $field))
+			// Note: in_array('', array(0)) returns TRUE, do not use it
+			foreach ($field as &$v)
 			{
-				return '';
+				if ($value === $v)
+				{
+					return ' selected="selected"';
+				}
 			}
+
+			return '';
 		}
 		elseif (($field === '' OR $value === '') OR ($field !== $value))
 		{
@@ -934,12 +954,19 @@
 		}
 
 		$field = $this->_field_data[$field]['postdata'];
+		$value = (string) $value;
 		if (is_array($field))
 		{
-			if ( ! in_array($value, $field))
+			// Note: in_array('', array(0)) returns TRUE, do not use it
+			foreach ($field as &$v)
 			{
-				return '';
+				if ($value === $v)
+				{
+					return ' checked="checked"';
+				}
 			}
+
+			return '';
 		}
 		elseif (($field === '' OR $value === '') OR ($field !== $value))
 		{
diff --git a/system/libraries/Ftp.php b/system/libraries/Ftp.php
index dc6bbd2..73a6844 100644
--- a/system/libraries/Ftp.php
+++ b/system/libraries/Ftp.php
@@ -214,12 +214,12 @@
 	 * Internally, this parameter is only used by the "mirror" function below.
 	 *
 	 * @param	string	$path
-	 * @param	bool	$supress_debug
+	 * @param	bool	$suppress_debug
 	 * @return	bool
 	 */
-	public function changedir($path = '', $supress_debug = FALSE)
+	public function changedir($path, $suppress_debug = FALSE)
 	{
-		if ($path === '' OR ! $this->_is_conn())
+		if ( ! $this->_is_conn())
 		{
 			return FALSE;
 		}
@@ -228,7 +228,7 @@
 
 		if ($result === FALSE)
 		{
-			if ($this->debug === TRUE && $supress_debug === FALSE)
+			if ($this->debug === TRUE && $suppress_debug === FALSE)
 			{
 				$this->_error('ftp_unable_to_changedir');
 			}
@@ -247,7 +247,7 @@
 	 * @param	int	$permissions
 	 * @return	bool
 	 */
-	public function mkdir($path = '', $permissions = NULL)
+	public function mkdir($path, $permissions = NULL)
 	{
 		if ($path === '' OR ! $this->_is_conn())
 		{
@@ -260,7 +260,7 @@
 		{
 			if ($this->debug === TRUE)
 			{
-				$this->_error('ftp_unable_to_makdir');
+				$this->_error('ftp_unable_to_mkdir');
 			}
 			return FALSE;
 		}
@@ -392,7 +392,7 @@
 		{
 			if ($this->debug === TRUE)
 			{
-				$this->_error('ftp_unable_to_' . ($move === FALSE ? 'rename' : 'move'));
+				$this->_error('ftp_unable_to_'.($move === FALSE ? 'rename' : 'move'));
 			}
 			return FALSE;
 		}
diff --git a/system/libraries/Javascript.php b/system/libraries/Javascript.php
index 090f4c9..26a1685 100644
--- a/system/libraries/Javascript.php
+++ b/system/libraries/Javascript.php
@@ -172,7 +172,7 @@
 	 */
 	public function focus($element = 'this', $js = '')
 	{
-		return $this->js->__add_event($element, $js);
+		return $this->js->_focus($element, $js);
 	}
 
 	// --------------------------------------------------------------------
@@ -189,7 +189,7 @@
 	 */
 	public function hover($element = 'this', $over = '', $out = '')
 	{
-		return $this->js->__hover($element, $over, $out);
+		return $this->js->_hover($element, $over, $out);
 	}
 
 	// --------------------------------------------------------------------
diff --git a/system/libraries/Javascript/Jquery.php b/system/libraries/Javascript/Jquery.php
index f5fa72d..ab78e8b 100644
--- a/system/libraries/Javascript/Jquery.php
+++ b/system/libraries/Javascript/Jquery.php
@@ -923,7 +923,6 @@
 		if (is_array($js))
 		{
 			$js = implode("\n\t\t", $js);
-
 		}
 
 		$event = "\n\t$(".$this->_prep_element($element).').'.$event."(function(){\n\t\t{$js}\n\t});\n";
@@ -937,7 +936,7 @@
 	 * Compile
 	 *
 	 * As events are specified, they are stored in an array
-	 * This funciton compiles them all for output on a page
+	 * This function compiles them all for output on a page
 	 *
 	 * @param	string	$view_var
 	 * @param	bool	$script_tags
diff --git a/system/libraries/Pagination.php b/system/libraries/Pagination.php
index 10fb29d..c6ffd03 100644
--- a/system/libraries/Pagination.php
+++ b/system/libraries/Pagination.php
@@ -354,7 +354,8 @@
 	public function create_links()
 	{
 		// If our item count or per-page total is zero there is no need to continue.
-		if ($this->total_rows === 0 OR $this->per_page === 0)
+		// Note: DO NOT change the operator to === here!
+		if ($this->total_rows == 0 OR $this->per_page == 0)
 		{
 			return '';
 		}
diff --git a/system/libraries/Parser.php b/system/libraries/Parser.php
index c1f1ad7..399131c 100644
--- a/system/libraries/Parser.php
+++ b/system/libraries/Parser.php
@@ -187,26 +187,34 @@
 	 */
 	protected function _parse_pair($variable, $data, $string)
 	{
-		if (FALSE === ($match = $this->_match_pair($string, $variable)))
+		if (FALSE === ($matches = $this->_match_pair($string, $variable)))
 		{
 			return $string;
 		}
 
 		$str = '';
-		foreach ($data as $row)
+		$search = $replace = array();
+		foreach ($matches as $match)
 		{
-			$temp = $match[1];
-			foreach ($row as $key => $val)
+			$str = '';
+			foreach ($data as $row)
 			{
-				$temp = is_array($val)
+				$temp = $match[1];
+				foreach ($row as $key => $val)
+				{
+					$temp = is_array($val)
 						? $this->_parse_pair($key, $val, $temp)
 						: $this->_parse_single($key, $val, $temp);
+				}
+
+				$str .= $temp;
 			}
 
-			$str .= $temp;
+			$search[] = $match[0];
+			$replace[] = $str;
 		}
 
-		return str_replace($match[0], $str, $string);
+		return str_replace($search, $replace, $string);
 	}
 
 	// --------------------------------------------------------------------
@@ -214,14 +222,14 @@
 	/**
 	 * Matches a variable pair
 	 *
-	 * @param	string
-	 * @param	string
+	 * @param	string	$string
+	 * @param	string	$variable
 	 * @return	mixed
 	 */
 	protected function _match_pair($string, $variable)
 	{
-		return preg_match('|'.preg_quote($this->l_delim).$variable.preg_quote($this->r_delim).'(.+?)'.preg_quote($this->l_delim).'/'.$variable.preg_quote($this->r_delim).'|s',
-					$string, $match)
+		return preg_match_all('|'.preg_quote($this->l_delim).$variable.preg_quote($this->r_delim).'(.+?)'.preg_quote($this->l_delim).'/'.$variable.preg_quote($this->r_delim).'|s',
+					$string, $match, PREG_SET_ORDER)
 			? $match : FALSE;
 	}
 
diff --git a/system/libraries/Profiler.php b/system/libraries/Profiler.php
index 9e9e7d0..4e556b2 100644
--- a/system/libraries/Profiler.php
+++ b/system/libraries/Profiler.php
@@ -278,6 +278,7 @@
 			}
 
 			$output .= "</table>\n</fieldset>";
+			$count++;
 		}
 
 		return $output;
@@ -307,10 +308,7 @@
 
 			foreach ($_GET as $key => $val)
 			{
-				if ( ! is_numeric($key))
-				{
-					$key = "'".$key."'";
-				}
+				is_int($key) OR $key = "'".$key."'";
 
 				$output .= '<tr><td style="width:50%;color:#000;background-color:#ddd;padding:5px;">&#36;_GET['
 					.$key.']&nbsp;&nbsp; </td><td style="width:50%;padding:5px;color:#cd6e00;font-weight:normal;background-color:#ddd;">'
@@ -338,7 +336,7 @@
 			."\n"
 			.'<legend style="color:#009900;">&nbsp;&nbsp;'.$this->CI->lang->line('profiler_post_data')."&nbsp;&nbsp;</legend>\n";
 
-		if (count($_POST) === 0)
+		if (count($_POST) === 0 && count($_FILES) === 0)
 		{
 			$output .= '<div style="color:#009900;font-weight:normal;padding:4px 0 4px 0;">'.$this->CI->lang->line('profiler_no_post').'</div>';
 		}
@@ -348,10 +346,7 @@
 
 			foreach ($_POST as $key => $val)
 			{
-				if ( ! is_numeric($key))
-				{
-					$key = "'".$key."'";
-				}
+				is_int($key) OR $key = "'".$key."'";
 
 				$output .= '<tr><td style="width:50%;padding:5px;color:#000;background-color:#ddd;">&#36;_POST['
 					.$key.']&nbsp;&nbsp; </td><td style="width:50%;padding:5px;color:#009900;font-weight:normal;background-color:#ddd;">';
@@ -368,6 +363,21 @@
 				$output .= "</td></tr>\n";
 			}
 
+			foreach ($_FILES as $key => $val)
+			{
+				is_int($key) OR $key = "'".$key."'";
+
+				$output .= '<tr><td style="width:50%;padding:5px;color:#000;background-color:#ddd;">&#36;_FILES['
+					.$key.']&nbsp;&nbsp; </td><td style="width:50%;padding:5px;color:#009900;font-weight:normal;background-color:#ddd;">';
+
+				if (is_array($val) OR is_object($val))
+				{
+					$output .= '<pre>'.htmlspecialchars(stripslashes(print_r($val, TRUE))).'</pre>';
+				}
+
+				$output .= "</td></tr>\n";
+			}
+
 			$output .= "</table>\n";
 		}
 
diff --git a/system/libraries/Session/Session.php b/system/libraries/Session/Session.php
index c7f6f82..ac97b94 100644
--- a/system/libraries/Session/Session.php
+++ b/system/libraries/Session/Session.php
@@ -60,11 +60,18 @@
 	public $params = array();
 
 	/**
+	 * Valid drivers list
+	 *
+	 * @var	array
+	 */
+	public $valid_drivers = array('native',	'cookie');
+
+	/**
 	 * Current driver in use
 	 *
 	 * @var	string
 	 */
-	protected $current = NULL;
+	public $current = NULL;
 
 	/**
 	 * User data
@@ -95,46 +102,36 @@
 	 */
 	public function __construct(array $params = array())
 	{
-		$CI =& get_instance();
+		$_config =& get_instance()->config;
 
 		// No sessions under CLI
-		if ($CI->input->is_cli_request())
+		if (is_cli())
 		{
 			return;
 		}
 
 		log_message('debug', 'CI_Session Class Initialized');
 
-		// Get valid drivers list
-		$this->valid_drivers = array(
-			'native',
-			'cookie'
-		);
-		$key = 'sess_valid_drivers';
-		$drivers = isset($params[$key]) ? $params[$key] : $CI->config->item($key);
-		if ($drivers)
+		// Add possible extra entries to our valid drivers list
+		$drivers = isset($params['sess_valid_drivers']) ? $params['sess_valid_drivers'] : $_config->item('sess_valid_drivers');
+		if ( ! empty($drivers))
 		{
-			// Add driver names to valid list
-			foreach ((array) $drivers as $driver)
-			{
-				if ( ! in_array(strtolower($driver), array_map('strtolower', $this->valid_drivers)))
-				{
-					$this->valid_drivers[] = $driver;
-				}
-			}
+			$drivers = array_map('strtolower', (array) $drivers);
+			$this->valid_drivers = array_merge($this->valid_drivers, array_diff($drivers, $this->valid_drivers));
 		}
 
 		// Get driver to load
-		$key = 'sess_driver';
-		$driver = isset($params[$key]) ? $params[$key] : $CI->config->item($key);
+		$driver = isset($params['sess_driver']) ? $params['sess_driver'] : $_config->item('sess_driver');
 		if ( ! $driver)
 		{
+			log_message('debug', "Session: No driver name is configured, defaulting to 'cookie'.");
 			$driver = 'cookie';
 		}
 
-		if ( ! in_array(strtolower($driver), array_map('strtolower', $this->valid_drivers)))
+		if ( ! in_array($driver, $this->valid_drivers))
 		{
-			$this->valid_drivers[] = $driver;
+			log_message('error', 'Session: Configured driver name is not valid, aborting.');
+			return;
 		}
 
 		// Save a copy of parameters in case drivers need access
@@ -291,7 +288,7 @@
 	 * @param	string	Item value or empty string
 	 * @return	void
 	 */
-	public function set_userdata($newdata = array(), $newval = '')
+	public function set_userdata($newdata, $newval = '')
 	{
 		// Wrap params as array if singular
 		if (is_string($newdata))
@@ -320,7 +317,7 @@
 	 * @param	mixed	Item name or array of item names
 	 * @return	void
 	 */
-	public function unset_userdata($newdata = array())
+	public function unset_userdata($newdata)
 	{
 		// Wrap single name as array
 		if (is_string($newdata))
@@ -363,7 +360,7 @@
 	 * @param	string	Item value or empty string
 	 * @return	void
 	 */
-	public function set_flashdata($newdata = array(), $newval = '')
+	public function set_flashdata($newdata, $newval = '')
 	{
 		// Wrap item as array if singular
 		if (is_string($newdata))
@@ -437,7 +434,7 @@
 	 * @param	int	Item lifetime in seconds or 0 for default
 	 * @return	void
 	 */
-	public function set_tempdata($newdata = array(), $newval = '', $expire = 0)
+	public function set_tempdata($newdata, $newval = '', $expire = 0)
 	{
 		// Set expiration time
 		$expire = time() + ($expire ? $expire : self::TEMP_EXP_DEF);
@@ -478,7 +475,7 @@
 	 * @param	mixed	Item name or array of item names
 	 * @return	void
 	 */
-	public function unset_tempdata($newdata = array())
+	public function unset_tempdata($newdata)
 	{
 		// Get expirations list
 		$expirations = $this->userdata(self::EXPIRATION_KEY);
diff --git a/system/libraries/Session/drivers/Session_cookie.php b/system/libraries/Session/drivers/Session_cookie.php
index d3d22d0..971dfea 100644
--- a/system/libraries/Session/drivers/Session_cookie.php
+++ b/system/libraries/Session/drivers/Session_cookie.php
@@ -165,6 +165,8 @@
 	 */
 	public $now;
 
+	// ------------------------------------------------------------------------
+
 	/**
 	 * Default userdata keys
 	 *
@@ -185,6 +187,15 @@
 	protected $data_dirty = FALSE;
 
 	/**
+	 * Standardize newlines flag
+	 *
+	 * @var	bool
+	 */
+	protected $_standardize_newlines;
+
+	// ------------------------------------------------------------------------
+
+	/**
 	 * Initialize session driver object
 	 *
 	 * @return	void
@@ -209,9 +220,11 @@
 			'sess_time_to_update',
 			'time_reference',
 			'cookie_prefix',
-			'encryption_key'
+			'encryption_key',
 		);
 
+		$this->_standardize_newlines = (bool) config_item('standardize_newlines');
+
 		foreach ($prefs as $key)
 		{
 			$this->$key = isset($this->_parent->params[$key])
@@ -397,7 +410,7 @@
 		}
 
 		// Unserialize the session array
-		$session = $this->_unserialize($session);
+		$session = @unserialize($session);
 
 		// Is the session data we unserialized an array with the correct format?
 		if ( ! is_array($session) OR ! isset($session['session_id'], $session['ip_address'], $session['user_agent'], $session['last_activity']))
@@ -472,7 +485,7 @@
 			$row = $query->row();
 			if ( ! empty($row->user_data))
 			{
-				$custom_data = $this->_unserialize($row->user_data);
+				$custom_data = unserialize(trim($row->user_data));
 
 				if (is_array($custom_data))
 				{
@@ -608,7 +621,7 @@
 			if ( ! empty($userdata))
 			{
 				// Serialize the custom data array so we can store it
-				$set['user_data'] = $this->_serialize($userdata);
+				$set['user_data'] = serialize($userdata);
 			}
 
 			// Reset query builder values.
@@ -695,8 +708,18 @@
 				? array_intersect_key($this->userdata, $this->defaults)
 				: $this->userdata;
 
+		// The Input class will do this and since we use HMAC verification,
+		// unless we standardize here as well, the hash won't match.
+		if ($this->_standardize_newlines)
+		{
+			foreach (array_keys($this->userdata) as $key)
+			{
+				$this->userdata[$key] = preg_replace('/(?:\r\n|[\r\n])/', PHP_EOL, $this->userdata[$key]);
+			}
+		}
+
 		// Serialize the userdata for the cookie
-		$cookie_data = $this->_serialize($cookie_data);
+		$cookie_data = serialize($cookie_data);
 
 		if ($this->sess_encrypt_cookie === TRUE)
 		{
@@ -737,93 +760,6 @@
 	// ------------------------------------------------------------------------
 
 	/**
-	 * Serialize an array
-	 *
-	 * This function first converts any slashes found in the array to a temporary
-	 * marker, so when it gets unserialized the slashes will be preserved
-	 *
-	 * @param	mixed	Data to serialize
-	 * @return	string	Serialized data
-	 */
-	protected function _serialize($data)
-	{
-		if (is_array($data))
-		{
-			array_walk_recursive($data, array(&$this, '_escape_slashes'));
-		}
-		elseif (is_string($data))
-		{
-			$data = str_replace('\\', '{{slash}}', $data);
-		}
-
-		return serialize($data);
-	}
-
-	// ------------------------------------------------------------------------
-
-	/**
-	 * Escape slashes
-	 *
-	 * This function converts any slashes found into a temporary marker
-	 *
-	 * @param	string	Value
-	 * @param	string	Key
-	 * @return	void
-	 */
-	protected function _escape_slashes(&$val, $key)
-	{
-		if (is_string($val))
-		{
-			$val = str_replace('\\', '{{slash}}', $val);
-		}
-	}
-
-	// ------------------------------------------------------------------------
-
-	/**
-	 * Unserialize
-	 *
-	 * This function unserializes a data string, then converts any
-	 * temporary slash markers back to actual slashes
-	 *
-	 * @param	mixed	Data to unserialize
-	 * @return	mixed	Unserialized data
-	 */
-	protected function _unserialize($data)
-	{
-		$data = @unserialize(trim($data));
-
-		if (is_array($data))
-		{
-			array_walk_recursive($data, array(&$this, '_unescape_slashes'));
-			return $data;
-		}
-
-		return is_string($data) ? str_replace('{{slash}}', '\\', $data) : $data;
-	}
-
-	// ------------------------------------------------------------------------
-
-	/**
-	 * Unescape slashes
-	 *
-	 * This function converts any slash markers back into actual slashes
-	 *
-	 * @param	string	Value
-	 * @param	string	Key
-	 * @return	void
-	 */
-	protected function _unescape_slashes(&$val, $key)
-	{
-		if (is_string($val))
-		{
-	 		$val = str_replace('{{slash}}', '\\', $val);
-		}
-	}
-
-	// ------------------------------------------------------------------------
-
-	/**
 	 * Garbage collection
 	 *
 	 * This deletes expired session rows from database
@@ -841,7 +777,7 @@
 		$probability = ini_get('session.gc_probability');
 		$divisor = ini_get('session.gc_divisor');
 
-		if ((mt_rand(0, $divisor) / $divisor) < $probability)
+		if (mt_rand(1, $divisor) <= $probability)
 		{
 			$expire = $this->now - $this->sess_expiration;
 			$this->CI->db->delete($this->sess_table_name, 'last_activity < '.$expire);
diff --git a/system/libraries/Unit_test.php b/system/libraries/Unit_test.php
index 7a67c72..e412b98 100644
--- a/system/libraries/Unit_test.php
+++ b/system/libraries/Unit_test.php
@@ -81,7 +81,15 @@
 	 *
 	 * @var	array
 	 */
-	protected $_test_items_visible	= array();
+	protected $_test_items_visible	= array(
+			'test_name',
+			'test_datatype',
+			'res_datatype',
+			'result',
+			'file',
+			'line',
+			'notes'
+	);
 
 	// --------------------------------------------------------------------
 
@@ -92,17 +100,6 @@
 	 */
 	public function __construct()
 	{
-		// These are the default items visible when a test is run.
-		$this->_test_items_visible = array (
-							'test_name',
-							'test_datatype',
-							'res_datatype',
-							'result',
-							'file',
-							'line',
-							'notes'
-						);
-
 		log_message('debug', 'Unit Testing Class Initialized');
 	}
 
@@ -113,10 +110,10 @@
 	 *
 	 * Runs the supplied tests
 	 *
-	 * @param	array
+	 * @param	array	$items
 	 * @return	void
 	 */
-	public function set_test_items($items = array())
+	public function set_test_items($items)
 	{
 		if ( ! empty($items) && is_array($items))
 		{
@@ -230,7 +227,7 @@
 	 *
 	 * Causes the evaluation to use === rather than ==
 	 *
-	 * @param	bool
+	 * @param	bool	$state
 	 * @return	void
 	 */
 	public function use_strict($state = TRUE)
@@ -288,6 +285,7 @@
 				{
 					$val = $line;
 				}
+
 				$temp[$CI->lang->line('ut_'.$key, FALSE)] = $val;
 			}
 
@@ -396,4 +394,4 @@
 }
 
 /* End of file Unit_test.php */
-/* Location: ./system/libraries/Unit_test.php */
+/* Location: ./system/libraries/Unit_test.php */
\ No newline at end of file
diff --git a/system/libraries/Upload.php b/system/libraries/Upload.php
index 8542804..525880f 100644
--- a/system/libraries/Upload.php
+++ b/system/libraries/Upload.php
@@ -234,6 +234,13 @@
 	public $xss_clean		= FALSE;
 
 	/**
+	 * Apache mod_mime fix flag
+	 *
+	 * @var	bool
+	 */
+	public $mod_mime_fix		= TRUE;
+
+	/**
 	 * Temporary filename prefix
 	 *
 	 * @var	string
@@ -256,6 +263,13 @@
 	 */
 	protected $_file_name_override	= '';
 
+	/**
+	 * CI Singleton
+	 *
+	 * @var	object
+	 */
+	protected $CI;
+
 	// --------------------------------------------------------------------
 
 	/**
@@ -272,6 +286,7 @@
 		}
 
 		$this->mimes =& get_mimes();
+		$this->CI =& get_instance();
 
 		log_message('debug', 'Upload Class Initialized');
 	}
@@ -314,6 +329,7 @@
 					'remove_spaces'			=> TRUE,
 					'detect_mime'			=> TRUE,
 					'xss_clean'			=> FALSE,
+					'mod_mime_fix'			=> TRUE,
 					'temp_prefix'			=> 'temp_file_',
 					'client_name'			=> ''
 				);
@@ -463,7 +479,7 @@
 		}
 
 		// Are the image dimensions within the allowed size?
-		// Note: This can fail if the server has an open_basdir restriction.
+		// Note: This can fail if the server has an open_basedir restriction.
 		if ( ! $this->is_allowed_dimensions())
 		{
 			$this->set_error('upload_invalid_dimensions');
@@ -471,8 +487,7 @@
 		}
 
 		// Sanitize the file name for security
-		$CI =& get_instance();
-		$this->file_name = $CI->security->sanitize_filename($this->file_name);
+		$this->file_name = $this->CI->security->sanitize_filename($this->file_name);
 
 		// Truncate the file name if it's too long
 		if ($this->max_filename > 0)
@@ -1073,8 +1088,7 @@
 			return FALSE;
 		}
 
-		$CI =& get_instance();
-		return $CI->security->xss_clean($data, TRUE);
+		return $this->CI->security->xss_clean($data, TRUE);
 	}
 
 	// --------------------------------------------------------------------
@@ -1087,17 +1101,13 @@
 	 */
 	public function set_error($msg)
 	{
-		$CI =& get_instance();
-		$CI->lang->load('upload');
+		$this->CI->lang->load('upload');
 
-		if ( ! is_array($msg))
-		{
-			$msg = array($msg);
-		}
+		is_array($msg) OR $msg = array($msg);
 
 		foreach ($msg as $val)
 		{
-			$msg = ($CI->lang->line($val) === FALSE) ? $val : $CI->lang->line($val);
+			$msg = ($this->CI->lang->line($val) === FALSE) ? $val : $this->CI->lang->line($val);
 			$this->error_msg[] = $msg;
 			log_message('error', $msg);
 		}
@@ -1148,7 +1158,7 @@
 	 */
 	protected function _prep_filename($filename)
 	{
-		if (strpos($filename, '.') === FALSE OR $this->allowed_types === '*')
+		if ($this->mod_mime_fix === FALSE OR $this->allowed_types === '*' OR strpos($filename, '.') === FALSE)
 		{
 			return $filename;
 		}
@@ -1245,7 +1255,7 @@
 				}
 			}
 
-			if ( (bool) @ini_get('safe_mode') === FALSE && function_usable('shell_exec'))
+			if ((bool) @ini_get('safe_mode') === FALSE && function_usable('shell_exec'))
 			{
 				$mime = @shell_exec($cmd);
 				if (strlen($mime) > 0)
diff --git a/system/libraries/User_agent.php b/system/libraries/User_agent.php
index 2f6f819..1dfa3e7 100644
--- a/system/libraries/User_agent.php
+++ b/system/libraries/User_agent.php
@@ -145,6 +145,15 @@
 	public $robot = '';
 
 	/**
+	 * HTTP Referer
+	 *
+	 * @var	mixed
+	 */
+	public $referer;
+
+	// --------------------------------------------------------------------
+
+	/**
 	 * Constructor
 	 *
 	 * Sets the User Agent and runs the compilation routine
@@ -282,7 +291,7 @@
 		{
 			foreach ($this->browsers as $key => $val)
 			{
-				if (preg_match('|'.preg_quote($key).'.*?([0-9\.]+)|i', $this->agent, $match))
+				if (preg_match('|'.$key.'.*?([0-9\.]+)|i', $this->agent, $match))
 				{
 					$this->is_browser = TRUE;
 					$this->version = $match[1];
@@ -358,7 +367,7 @@
 	{
 		if ((count($this->languages) === 0) && ! empty($_SERVER['HTTP_ACCEPT_LANGUAGE']))
 		{
-			$this->languages = explode(',', preg_replace('/(;q=[0-9\.]+)/i', '', strtolower(trim($_SERVER['HTTP_ACCEPT_LANGUAGE']))));
+			$this->languages = explode(',', preg_replace('/(;\s?q=[0-9\.]+)|\s/i', '', strtolower(trim($_SERVER['HTTP_ACCEPT_LANGUAGE']))));
 		}
 
 		if (count($this->languages) === 0)
@@ -378,7 +387,7 @@
 	{
 		if ((count($this->charsets) === 0) && ! empty($_SERVER['HTTP_ACCEPT_CHARSET']))
 		{
-			$this->charsets = explode(',', preg_replace('/(;q=.+)/i', '', strtolower(trim($_SERVER['HTTP_ACCEPT_CHARSET']))));
+			$this->charsets = explode(',', preg_replace('/(;\s?q=.+)|\s/i', '', strtolower(trim($_SERVER['HTTP_ACCEPT_CHARSET']))));
 		}
 
 		if (count($this->charsets) === 0)
@@ -471,13 +480,22 @@
 	 */
 	public function is_referral()
 	{
-		if (empty($_SERVER['HTTP_REFERER']))
+		if ( ! isset($this->referer))
 		{
-			return FALSE;
+			if (empty($_SERVER['HTTP_REFERER']))
+			{
+				$this->referer = FALSE;
+			}
+			else
+			{
+				$referer_host = @parse_url($_SERVER['HTTP_REFERER'], PHP_URL_HOST);
+				$own_host = parse_url(config_item('base_url'), PHP_URL_HOST);
+
+				$this->referer = ($referer_host && $referer_host !== $own_host);
+			}
 		}
 
-		$referer = parse_url($_SERVER['HTTP_REFERER']);
-		return ! (empty($referer['host']) && strpos(config_item('base_url'), $referer['host']) !== FALSE);
+		return $this->referer;
 	}
 
 	// --------------------------------------------------------------------
@@ -623,6 +641,34 @@
 		return in_array(strtolower($charset), $this->charsets(), TRUE);
 	}
 
+	// --------------------------------------------------------------------
+
+	/**
+	 * Parse a custom user-agent string
+	 *
+	 * @param	string	$string
+	 * @return	void
+	 */
+	public function parse($string)
+	{
+		// Reset values
+		$this->is_browser = FALSE;
+		$this->is_robot = FALSE;
+		$this->is_mobile = FALSE;
+		$this->browser = '';
+		$this->version = '';
+		$this->mobile = '';
+		$this->robot = '';
+
+		// Set the new user-agent string and parse it, unless empty
+		$this->agent = $string;
+
+		if ( ! empty($string))
+		{
+			$this->_compile_data();
+		}
+	}
+
 }
 
 /* End of file User_agent.php */
diff --git a/system/libraries/Xmlrpc.php b/system/libraries/Xmlrpc.php
index 16c5b0e..d0f6d83 100644
--- a/system/libraries/Xmlrpc.php
+++ b/system/libraries/Xmlrpc.php
@@ -348,6 +348,11 @@
 
 		$parts = parse_url($url);
 
+		if (isset($parts['user'], $parts['pass']))
+		{
+			$parts['host'] = $parts['user'].':'.$parts['pass'].'@'.$parts['host'];
+		}
+
 		$path = isset($parts['path']) ? $parts['path'] : '/';
 
 		if ( ! empty($parts['query']))
@@ -569,6 +574,21 @@
 	public $port			= 80;
 
 	/**
+	 *
+	 * Server username
+	 *
+	 * @var	string
+	 */
+	public $username;
+
+	/**
+	 * Server password
+	 *
+	 * @var	string
+	 */
+	public $password;
+
+	/**
 	 * Proxy hostname
 	 *
 	 * @var	string
@@ -626,8 +646,16 @@
 	{
 		parent::__construct();
 
+		$url = parse_url('http://'.$server);
+
+		if (isset($url['user'], $url['pass']))
+		{
+			$this->username = $url['user'];
+			$this->password = $url['pass'];
+		}
+
 		$this->port = $port;
-		$this->server = $server;
+		$this->server = $url['host'];
 		$this->path = $path;
 		$this->proxy = $proxy;
 		$this->proxy_port = $proxy_port;
@@ -691,11 +719,20 @@
 		$op = 'POST '.$this->path.' HTTP/1.0'.$r
 			.'Host: '.$this->server.$r
 			.'Content-Type: text/xml'.$r
+			.(isset($this->username, $this->password) ? 'Authorization: Basic '.base64_encode($this->username.':'.$this->password).$r : '')
 			.'User-Agent: '.$this->xmlrpcName.$r
 			.'Content-Length: '.strlen($msg->payload).$r.$r
 			.$msg->payload;
 
-		if ( ! fwrite($fp, $op, strlen($op)))
+		for ($written = 0, $length = strlen($op); $written < $length; $written += $result)
+		{
+			if (($result = fwrite($fp, substr($op, $written))) === FALSE)
+			{
+				break;
+			}
+		}
+
+		if ($result === FALSE)
 		{
 			error_log($this->xmlrpcstr['http_error']);
 			return new XML_RPC_Response(0, $this->xmlrpcerr['http_error'], $this->xmlrpcstr['http_error']);
@@ -855,10 +892,10 @@
 	/**
 	 * Decode
 	 *
-	 * @param	mixed
+	 * @param	mixed	$array
 	 * @return	array
 	 */
-	public function decode($array = FALSE)
+	public function decode($array = NULL)
 	{
 		$CI =& get_instance();
 
@@ -870,9 +907,9 @@
 				{
 					$array[$key] = $this->decode($array[$key]);
 				}
-				else
+				elseif ($this->xss_clean)
 				{
-					$array[$key] = ($this->xss_clean) ? $CI->security->xss_clean($array[$key]) : $array[$key];
+					$array[$key] = $CI->security->xss_clean($array[$key]);
 				}
 			}
 
@@ -885,9 +922,9 @@
 		{
 			$result = $this->decode($result);
 		}
-		else
+		elseif ($this->xss_clean)
 		{
-			$result = ($this->xss_clean) ? $CI->security->xss_clean($result) : $result;
+			$result = $CI->security->xss_clean($result);
 		}
 
 		return $result;
@@ -1084,15 +1121,15 @@
 		//-------------------------------------
 
 		$parser = xml_parser_create($this->xmlrpc_defencoding);
-
-		$this->xh[$parser] = array(
-						'isf'		=> 0,
-						'ac'		=> '',
-						'headers'	=> array(),
-						'stack'		=> array(),
-						'valuestack'	=> array(),
-						'isf_reason'	=> 0
-					);
+		$pname = (string) $parser;
+		$this->xh[$pname] = array(
+			'isf'		=> 0,
+			'ac'		=> '',
+			'headers'	=> array(),
+			'stack'		=> array(),
+			'valuestack'	=> array(),
+			'isf_reason'	=> 0
+		);
 
 		xml_set_object($parser, $this);
 		xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, TRUE);
@@ -1108,7 +1145,7 @@
 			{
 				break;
 			}
-			$this->xh[$parser]['headers'][] = $line;
+			$this->xh[$pname]['headers'][] = $line;
 		}
 		$data = implode("\r\n", $lines);
 
@@ -1126,18 +1163,18 @@
 		xml_parser_free($parser);
 
 		// Got ourselves some badness, it seems
-		if ($this->xh[$parser]['isf'] > 1)
+		if ($this->xh[$pname]['isf'] > 1)
 		{
 			if ($this->debug === TRUE)
 			{
-				echo "---Invalid Return---\n".$this->xh[$parser]['isf_reason']."---Invalid Return---\n\n";
+				echo "---Invalid Return---\n".$this->xh[$pname]['isf_reason']."---Invalid Return---\n\n";
 			}
 
-			return new XML_RPC_Response(0, $this->xmlrpcerr['invalid_return'], $this->xmlrpcstr['invalid_return'].' '.$this->xh[$parser]['isf_reason']);
+			return new XML_RPC_Response(0, $this->xmlrpcerr['invalid_return'], $this->xmlrpcstr['invalid_return'].' '.$this->xh[$pname]['isf_reason']);
 		}
-		elseif ( ! is_object($this->xh[$parser]['value']))
+		elseif ( ! is_object($this->xh[$pname]['value']))
 		{
-			return new XML_RPC_Response(0, $this->xmlrpcerr['invalid_return'], $this->xmlrpcstr['invalid_return'].' '.$this->xh[$parser]['isf_reason']);
+			return new XML_RPC_Response(0, $this->xmlrpcerr['invalid_return'], $this->xmlrpcstr['invalid_return'].' '.$this->xh[$pname]['isf_reason']);
 		}
 
 		// Display XML content for debugging
@@ -1145,10 +1182,10 @@
 		{
 			echo '<pre>';
 
-			if (count($this->xh[$parser]['headers'] > 0))
+			if (count($this->xh[$pname]['headers'] > 0))
 			{
 				echo "---HEADERS---\n";
-				foreach ($this->xh[$parser]['headers'] as $header)
+				foreach ($this->xh[$pname]['headers'] as $header)
 				{
 					echo $header."\n";
 				}
@@ -1156,13 +1193,13 @@
 			}
 
 			echo "---DATA---\n".htmlspecialchars($data)."\n---END DATA---\n\n---PARSED---\n";
-			var_dump($this->xh[$parser]['value']);
+			var_dump($this->xh[$pname]['value']);
 			echo "\n---END PARSED---</pre>";
 		}
 
 		// Send response
-		$v = $this->xh[$parser]['value'];
-		if ($this->xh[$parser]['isf'])
+		$v = $this->xh[$pname]['value'];
+		if ($this->xh[$pname]['isf'])
 		{
 			$errno_v = $v->me['struct']['faultCode'];
 			$errstr_v = $v->me['struct']['faultString'];
@@ -1181,7 +1218,7 @@
 			$r = new XML_RPC_Response($v);
 		}
 
-		$r->headers = $this->xh[$parser]['headers'];
+		$r->headers = $this->xh[$pname]['headers'];
 		return $r;
 	}
 
@@ -1212,6 +1249,8 @@
 	 */
 	public function open_tag($the_parser, $name)
 	{
+		$the_parser = (string) $the_parser;
+
 		// If invalid nesting, then return
 		if ($this->xh[$the_parser]['isf'] > 1) return;
 
@@ -1311,6 +1350,8 @@
 	 */
 	public function closing_tag($the_parser, $name)
 	{
+		$the_parser = (string) $the_parser;
+
 		if ($this->xh[$the_parser]['isf'] > 1) return;
 
 		// Remove current element from stack and set variable
@@ -1443,6 +1484,8 @@
 	 */
 	public function character_data($the_parser, $data)
 	{
+		$the_parser = (string) $the_parser;
+
 		if ($this->xh[$the_parser]['isf'] > 1) return; // XML Fault found already
 
 		// If a value has not been found
@@ -1480,14 +1523,14 @@
 	/**
 	 * Output parameters
 	 *
-	 * @param	array
+	 * @param	array	$array
 	 * @return	array
 	 */
-	public function output_parameters($array = FALSE)
+	public function output_parameters(array $array = array())
 	{
 		$CI =& get_instance();
 
-		if (is_array($array))
+		if ( ! empty($array))
 		{
 			while (list($key) = each($array))
 			{
@@ -1495,11 +1538,11 @@
 				{
 					$array[$key] = $this->output_parameters($array[$key]);
 				}
-				else
+				elseif ($key !== 'bits' && $this->xss_clean)
 				{
 					// 'bits' is for the MetaWeblog API image bits
 					// @todo - this needs to be made more general purpose
-					$array[$key] = ($key === 'bits' OR $this->xss_clean === FALSE) ? $array[$key] : $CI->security->xss_clean($array[$key]);
+					$array[$key] = $CI->security->xss_clean($array[$key]);
 				}
 			}
 
@@ -1684,7 +1727,7 @@
 	{
 		if ($this->mytype !== 0)
 		{
-			echo '<strong>XML_RPC_Values</strong>: already initialized as a [' . $this->kindOf() . ']<br />';
+			echo '<strong>XML_RPC_Values</strong>: already initialized as a ['.$this->kindOf().']<br />';
 			return 0;
 		}
 
@@ -1705,7 +1748,7 @@
 	{
 		if ($this->mytype !== 0)
 		{
-			echo '<strong>XML_RPC_Values</strong>: already initialized as a [' . $this->kindOf() . ']<br />';
+			echo '<strong>XML_RPC_Values</strong>: already initialized as a ['.$this->kindOf().']<br />';
 			return 0;
 		}
 		$this->mytype = $this->xmlrpcTypes['struct'];
diff --git a/system/libraries/Xmlrpcs.php b/system/libraries/Xmlrpcs.php
index d263d78..50ff423 100644
--- a/system/libraries/Xmlrpcs.php
+++ b/system/libraries/Xmlrpcs.php
@@ -384,17 +384,13 @@
 			{
 				return call_user_func(array($this, $method_parts[1]), $m);
 			}
+			elseif ($this->object === FALSE)
+			{
+				return get_instance()->$method_parts[1]($m);
+			}
 			else
 			{
-				if ($this->object === FALSE)
-				{
-					$CI =& get_instance();
-					return $CI->$method_parts[1]($m);
-				}
-				else
-				{
-					return $this->object->$method_parts[1]($m);
-				}
+				return $this->object->$method_parts[1]($m);
 			}
 		}
 		else
diff --git a/system/libraries/Zip.php b/system/libraries/Zip.php
index 6608f05..b10b0bb 100644
--- a/system/libraries/Zip.php
+++ b/system/libraries/Zip.php
@@ -103,12 +103,12 @@
 	 *
 	 * Lets you add a virtual directory into which you can place files.
 	 *
-	 * @param	mixed	the directory name. Can be string or array
+	 * @param	mixed	$directory	the directory name. Can be string or array
 	 * @return	void
 	 */
 	public function add_dir($directory)
 	{
-		foreach ( (array) $directory as $dir)
+		foreach ((array) $directory as $dir)
 		{
 			if ( ! preg_match('|.+/$|', $dir))
 			{
@@ -127,7 +127,7 @@
 	 *
 	 * If this is a newly created file/dir, we will set the time to 'now'
 	 *
-	 * @param	string	path to file
+	 * @param	string	$dir	path to file
 	 * @return	array	filemtime/filemdate
 	 */
 	protected function _get_mod_time($dir)
@@ -146,9 +146,9 @@
 	/**
 	 * Add Directory
 	 *
-	 * @param	string	the directory name
-	 * @param	int
-	 * @param	int
+	 * @param	string	$dir	the directory name
+	 * @param	int	$file_mtime
+	 * @param	int	$file_mdate
 	 * @return	void
 	 */
 	protected function _add_dir($dir, $file_mtime, $file_mdate)
@@ -199,8 +199,8 @@
 	 * in the filename it will be placed within a directory. Make
 	 * sure you use add_dir() first to create the folder.
 	 *
-	 * @param	mixed
-	 * @param	string
+	 * @param	mixed	$filepath	A single filepath or an array of file => data pairs
+	 * @param	string	$data		Single file contents
 	 * @return	void
 	 */
 	public function add_data($filepath, $data = NULL)
@@ -225,10 +225,10 @@
 	/**
 	 * Add Data to Zip
 	 *
-	 * @param	string	the file name/path
-	 * @param	string	the data to be encoded
-	 * @param	int
-	 * @param	int
+	 * @param	string	$filepath	the file name/path
+	 * @param	string	$data	the data to be encoded
+	 * @param	int	$file_mtime
+	 * @param	int	$file_mdate
 	 * @return	void
 	 */
 	protected function _add_data($filepath, $data, $file_mtime, $file_mdate)
@@ -278,23 +278,26 @@
 	/**
 	 * Read the contents of a file and add it to the zip
 	 *
-	 * @param	string
-	 * @param	bool
+	 * @param	string	$path
+	 * @param	bool	$archive_filepath
 	 * @return	bool
 	 */
-	public function read_file($path, $preserve_filepath = FALSE)
+	public function read_file($path, $archive_filepath = FALSE)
 	{
-		if ( ! file_exists($path))
+		if (file_exists($path) && FALSE !== ($data = file_get_contents($path)))
 		{
-			return FALSE;
-		}
-
-		if (FALSE !== ($data = file_get_contents($path)))
-		{
-			$name = str_replace('\\', '/', $path);
-			if ($preserve_filepath === FALSE)
+			if (is_string($archive_filepath))
 			{
-				$name = preg_replace('|.*/(.+)|', '\\1', $name);
+				$name = str_replace('\\', '/', $archive_filepath);
+			}
+			else
+			{
+				$name = str_replace('\\', '/', $path);
+
+				if ($preserve_filepath === FALSE)
+				{
+					$name = preg_replace('|.*/(.+)|', '\\1', $name);
+				}
 			}
 
 			$this->add_data($name, $data);
@@ -313,9 +316,9 @@
 	 * sub-folders) and creates a zip based on it. Whatever directory structure
 	 * is in the original file path will be recreated in the zip file.
 	 *
-	 * @param	string	path to source
-	 * @param	bool
-	 * @param	bool
+	 * @param	string	$path	path to source directory
+	 * @param	bool	$preserve_filepath
+	 * @param	string	$root_path
 	 * @return	bool
 	 */
 	public function read_dir($path, $preserve_filepath = TRUE, $root_path = NULL)
@@ -389,7 +392,7 @@
 	 *
 	 * Lets you write a file
 	 *
-	 * @param	string	the file name
+	 * @param	string	$filepath	the file name
 	 * @return	bool
 	 */
 	public function archive($filepath)
@@ -400,11 +403,19 @@
 		}
 
 		flock($fp, LOCK_EX);
-		fwrite($fp, $this->get_zip());
+
+		for ($written = 0, $data = $this->get_zip(), $length = strlen($data); $written < $length; $written += $result)
+		{
+			if (($result = fwrite($fp, substr($data, $written))) === FALSE)
+			{
+				break;
+			}
+		}
+
 		flock($fp, LOCK_UN);
 		fclose($fp);
 
-		return TRUE;
+		return is_int($result);
 	}
 
 	// --------------------------------------------------------------------
@@ -412,7 +423,7 @@
 	/**
 	 * Download
 	 *
-	 * @param	string	the file name
+	 * @param	string	$filename	the file name
 	 * @return	void
 	 */
 	public function download($filename = 'backup.zip')
@@ -422,8 +433,7 @@
 			$filename .= '.zip';
 		}
 
-		$CI =& get_instance();
-		$CI->load->helper('download');
+		get_instance()->load->helper('download');
 		$get_zip = $this->get_zip();
 		$zip_content =& $get_zip;
 
diff --git a/tests/codeigniter/core/Benchmark_test.php b/tests/codeigniter/core/Benchmark_test.php
index a239ba5..7fd0727 100644
--- a/tests/codeigniter/core/Benchmark_test.php
+++ b/tests/codeigniter/core/Benchmark_test.php
@@ -27,10 +27,34 @@
 		$this->assertEmpty($this->benchmark->elapsed_time('undefined_point'));
 
 		$this->benchmark->mark('code_start');
-		sleep(1);
 		$this->benchmark->mark('code_end');
 
+		// Override values, because time isn't testable, but make sure the markers were set
+		if (isset($this->benchmark->marker['code_start']) && is_float($this->benchmark->marker['code_start']))
+		{
+			$this->benchmark->marker['code_start'] = 1389956144.1944;
+		}
+
+		if (isset($this->benchmark->marker['code_end']) && is_float($this->benchmark->marker['code_end']))
+		{
+			$this->benchmark->marker['code_end'] = 1389956145.1946;
+		}
+
+		$this->assertEquals('1', $this->benchmark->elapsed_time('code_start', 'code_end', 0));
 		$this->assertEquals('1.0', $this->benchmark->elapsed_time('code_start', 'code_end', 1));
+		$this->assertEquals('1.00', $this->benchmark->elapsed_time('code_start', 'code_end', 2));
+		$this->assertEquals('1.000', $this->benchmark->elapsed_time('code_start', 'code_end', 3));
+		$this->assertEquals('1.0002', $this->benchmark->elapsed_time('code_start', 'code_end', 4));
+		$this->assertEquals('1.0002', $this->benchmark->elapsed_time('code_start', 'code_end'));
+
+		// Test with non-existing 2nd marker, but again - we need to override the value
+		$this->benchmark->elapsed_time('code_start', 'code_end2');
+		if (isset($this->benchmark->marker['code_end2']) && is_float($this->benchmark->marker['code_end2']))
+		{
+			$this->benchmark->marker['code_end2'] = 1389956146.2046;
+		}
+
+		$this->assertEquals('2.0102', $this->benchmark->elapsed_time('code_start', 'code_end2'));
 	}
 
 	// --------------------------------------------------------------------
diff --git a/tests/codeigniter/core/Config_test.php b/tests/codeigniter/core/Config_test.php
index e3be8a3..ba9a2c0 100644
--- a/tests/codeigniter/core/Config_test.php
+++ b/tests/codeigniter/core/Config_test.php
@@ -24,18 +24,18 @@
 		$this->assertEquals($this->cfg['base_url'], $this->config->item('base_url'));
 
 		// Bad Config value
-		$this->assertFalse($this->config->item('no_good_item'));
+		$this->assertNull($this->config->item('no_good_item'));
 
 		// Index
-		$this->assertFalse($this->config->item('no_good_item', 'bad_index'));
-		$this->assertFalse($this->config->item('no_good_item', 'default'));
+		$this->assertNull($this->config->item('no_good_item', 'bad_index'));
+		$this->assertNull($this->config->item('no_good_item', 'default'));
 	}
 
 	// --------------------------------------------------------------------
 
 	public function test_set_item()
 	{
-		$this->assertFalse($this->config->item('not_yet_set'));
+		$this->assertNull($this->config->item('not_yet_set'));
 
 		$this->config->set_item('not_yet_set', 'is set');
 		$this->assertEquals('is set', $this->config->item('not_yet_set'));
@@ -46,7 +46,7 @@
 	public function test_slash_item()
 	{
 		// Bad Config value
-		$this->assertFalse($this->config->slash_item('no_good_item'));
+		$this->assertNull($this->config->slash_item('no_good_item'));
 
 		$this->assertEquals($this->cfg['base_url'], $this->config->slash_item('base_url'));
 		$this->assertEquals($this->cfg['subclass_prefix'].'/', $this->config->slash_item('subclass_prefix'));
diff --git a/tests/codeigniter/core/Input_test.php b/tests/codeigniter/core/Input_test.php
index 5cf25fe..95833fc 100644
--- a/tests/codeigniter/core/Input_test.php
+++ b/tests/codeigniter/core/Input_test.php
@@ -82,11 +82,21 @@
 
 	// --------------------------------------------------------------------
 
-	public function test_get_post()
+	public function test_post_get()
 	{
 		$_SERVER['REQUEST_METHOD'] = 'POST';
 		$_POST['foo'] = 'bar';
 
+		$this->assertEquals('bar', $this->input->post_get('foo'));
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_get_post()
+	{
+		$_SERVER['REQUEST_METHOD'] = 'GET';
+		$_GET['foo'] = 'bar';
+
 		$this->assertEquals('bar', $this->input->get_post('foo'));
 	}
 
@@ -128,13 +138,24 @@
 
 	public function test_valid_ip()
 	{
-		$ip_v4 = '192.18.0.1';
-		$this->assertTrue($this->input->valid_ip($ip_v4));
+		$this->assertTrue($this->input->valid_ip('192.18.0.1'));
+		$this->assertTrue($this->input->valid_ip('192.18.0.1', 'ipv4'));
+		$this->assertFalse($this->input->valid_ip('555.0.0.0'));
+		$this->assertFalse($this->input->valid_ip('2001:db8:0:85a3::ac1f:8001', 'ipv4'));
 
-		$ip_v6 = array('2001:0db8:0000:85a3:0000:0000:ac1f:8001', '2001:db8:0:85a3:0:0:ac1f:8001', '2001:db8:0:85a3::ac1f:8001');
+		// v6 tests
+		$this->assertFalse($this->input->valid_ip('192.18.0.1', 'ipv6'));
+
+		$ip_v6 = array(
+			'2001:0db8:0000:85a3:0000:0000:ac1f:8001',
+			'2001:db8:0:85a3:0:0:ac1f:8001',
+			'2001:db8:0:85a3::ac1f:8001'
+		);
+
 		foreach ($ip_v6 as $ip)
 		{
 			$this->assertTrue($this->input->valid_ip($ip));
+			$this->assertTrue($this->input->valid_ip($ip, 'ipv6'));
 		}
 	}
 
@@ -161,4 +182,34 @@
 		$this->assertTrue($this->input->is_ajax_request());
 	}
 
+	// --------------------------------------------------------------------
+
+	public function test_input_stream()
+	{
+		$this->markTestSkipped('TODO: Find a way to test input://');
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_set_cookie()
+	{
+		$this->markTestSkipped('TODO: Find a way to test HTTP headers');
+	}
+
+	public function test_ip_address()
+	{
+		// 127.0.0.1 is set in our Bootstrap file
+		$this->assertEquals('127.0.0.1', $this->input->ip_address());
+
+		// Invalid
+		$_SERVER['REMOTE_ADDR'] = 'invalid_ip_address';
+		$this->input->ip_address = FALSE; // reset cached value
+		$this->assertEquals('0.0.0.0', $this->input->ip_address());
+
+		// TODO: Add proxy_ips tests
+
+		// Back to reality
+		$_SERVER['REMOTE_ADDR'] = '127.0.0.1'; // back to reality
+	}
+
 }
\ No newline at end of file
diff --git a/tests/codeigniter/core/Loader_test.php b/tests/codeigniter/core/Loader_test.php
index ac2656e..799bcd9 100644
--- a/tests/codeigniter/core/Loader_test.php
+++ b/tests/codeigniter/core/Loader_test.php
@@ -28,18 +28,15 @@
 		$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));
+		$this->assertFalse($this->load->is_loaded(ucfirst($lib)));
 
 		// Test loading as an array.
-		$this->assertNull($this->load->library(array($lib)));
+		$this->assertInstanceOf('CI_Loader', $this->load->library(array($lib)));
 		$this->assertTrue(class_exists($class), $class.' does not exist');
 		$this->assertAttributeInstanceOf($class, $lib, $this->ci_obj);
 
-		// Test no lib given
-		$this->assertNull($this->load->library());
-
 		// Test a string given to params
-		$this->assertNull($this->load->library($lib, ' '));
+		$this->assertInstanceOf('CI_Loader', $this->load->library($lib, ' '));
 
 		// Create library w/o class
 		$lib = 'bad_test_lib';
@@ -50,7 +47,7 @@
 			'RuntimeException',
 			'CI Error: Unable to load the requested class: '.ucfirst($lib)
 		);
-		$this->assertNull($this->load->library($lib));
+		$this->assertInstanceOf('CI_Loader', $this->load->library($lib));
 	}
 
 	// --------------------------------------------------------------------
@@ -66,7 +63,7 @@
 		$this->ci_vfs_create($ext, '<?php class '.$ext.' extends '.$class.' { }', $this->ci_app_root, 'libraries');
 
 		// Test loading with extension
-		$this->assertNull($this->load->library($lib));
+		$this->assertInstanceOf('CI_Loader', $this->load->library($lib));
 		$this->assertTrue(class_exists($class), $class.' does not exist');
 		$this->assertTrue(class_exists($ext), $ext.' does not exist');
 		$this->assertAttributeInstanceOf($class, $name, $this->ci_obj);
@@ -74,13 +71,13 @@
 
 		// Test reloading with object name
 		$obj = 'exttest';
-		$this->assertNull($this->load->library($lib, NULL, $obj));
+		$this->assertInstanceOf('CI_Loader', $this->load->library($lib, NULL, $obj));
 		$this->assertAttributeInstanceOf($class, $obj, $this->ci_obj);
 		$this->assertAttributeInstanceOf($ext, $obj, $this->ci_obj);
 
 		// Test reloading
 		unset($this->ci_obj->$name);
-		$this->assertNull($this->load->library($lib));
+		$this->assertInstanceOf('CI_Loader', $this->load->library($lib));
 		$this->assertObjectNotHasAttribute($name, $this->ci_obj);
 
 		// Create baseless library
@@ -94,7 +91,7 @@
 			'RuntimeException',
 			'CI Error: Unable to load the requested class: '.$lib
 		);
-		$this->assertNull($this->load->library($lib));
+		$this->assertInstanceOf('CI_Loader', $this->load->library($lib));
 	}
 
 	// --------------------------------------------------------------------
@@ -117,13 +114,13 @@
 
 		// Test object name and config
 		$obj = 'testy';
-		$this->assertNull($this->load->library($lib, NULL, $obj));
+		$this->assertInstanceOf('CI_Loader', $this->load->library($lib, NULL, $obj));
 		$this->assertTrue(class_exists($class), $class.' does not exist');
 		$this->assertAttributeInstanceOf($class, $obj, $this->ci_obj);
 		$this->assertEquals($cfg, $this->ci_obj->$obj->config);
 
 		// Test is_loaded
-		$this->assertEquals($obj, $this->load->is_loaded($lib));
+		$this->assertEquals($obj, $this->load->is_loaded(ucfirst($lib)));
 	}
 
 	// --------------------------------------------------------------------
@@ -136,7 +133,7 @@
 		$this->ci_vfs_create(ucfirst($lib), '<?php class '.$class.' { }', $this->ci_app_root, 'libraries');
 
 		// Load library
-		$this->assertNull($this->load->library($lib));
+		$this->assertInstanceOf('CI_Loader', $this->load->library($lib));
 
 		// Was the model class instantiated.
 		$this->assertTrue(class_exists($class), $class.' does not exist');
@@ -158,20 +155,17 @@
 		$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)));
+		$this->assertInstanceOf('CI_Loader', $this->load->driver(array($driver)));
 		$this->assertTrue(class_exists($class), $class.' does not exist');
 		$this->assertAttributeInstanceOf($class, $driver, $this->ci_obj);
 
 		// Test loading as a library with a name
 		$obj = 'testdrive';
-		$this->assertNull($this->load->library($driver, NULL, $obj));
+		$this->assertInstanceOf('CI_Loader', $this->load->library($driver, NULL, $obj));
 		$this->assertAttributeInstanceOf($class, $obj, $this->ci_obj);
 
-		// Test no driver given
-		$this->assertFalse($this->load->driver());
-
 		// Test a string given to params
-		$this->assertNull($this->load->driver($driver, ' '));
+		$this->assertInstanceOf('CI_Loader', $this->load->driver($driver, ' '));
 	}
 
 	// --------------------------------------------------------------------
@@ -181,19 +175,19 @@
 		$this->ci_set_core_class('model', 'CI_Model');
 
 		// Create model in VFS
-		$model = 'unit_test_model';
-		$class = ucfirst($model);
-		$content = '<?php class '.$class.' extends CI_Model {} ';
+		$model = 'Unit_test_model';
+		$content = '<?php class '.$model.' extends CI_Model {} ';
 		$this->ci_vfs_create($model, $content, $this->ci_app_root, 'models');
 
 		// Load model
-		$this->assertNull($this->load->model($model));
+		$this->assertInstanceOf('CI_Loader', $this->load->model($model));
 
 		// Was the model class instantiated.
-		$this->assertTrue(class_exists($class));
+		$this->assertTrue(class_exists($model));
+		$this->assertObjectHasAttribute($model, $this->ci_obj);
 
 		// Test no model given
-		$this->assertNull($this->load->model(''));
+		$this->assertInstanceOf('CI_Loader', $this->load->model(''));
 	}
 
 	// --------------------------------------------------------------------
@@ -204,22 +198,21 @@
 		$this->ci_core_class('model');
 
 		// Create modelin VFS
-		$model = 'test_sub_model';
+		$model = 'Test_sub_model';
 		$base = 'CI_Model';
-		$class = ucfirst($model);
 		$subdir = 'cars';
-		$this->ci_vfs_create($model, '<?php class '.$class.' extends '.$base.' { }', $this->ci_app_root,
+		$this->ci_vfs_create($model, '<?php class '.$model.' extends '.$base.' { }', $this->ci_app_root,
 			array('models', $subdir));
 
 		// Load model
 		$name = 'testors';
-		$this->assertNull($this->load->model($subdir.'/'.$model, $name));
+		$this->assertInstanceOf('CI_Loader', $this->load->model($subdir.'/'.$model, $name));
 
 		// Was the model class instantiated?
-		$this->assertTrue(class_exists($class));
+		$this->assertTrue(class_exists($model));
 		$this->assertObjectHasAttribute($name, $this->ci_obj);
 		$this->assertAttributeInstanceOf($base, $name, $this->ci_obj);
-		$this->assertAttributeInstanceOf($class, $name, $this->ci_obj);
+		$this->assertAttributeInstanceOf($model, $name, $this->ci_obj);
 
 		// Test name conflict
 		$obj = 'conflict';
@@ -237,7 +230,7 @@
 	{
 		$this->setExpectedException(
 			'RuntimeException',
-			'CI Error: Unable to locate the model you have specified: ci_test_nonexistent_model.php'
+			'CI Error: Unable to locate the model you have specified: Ci_test_nonexistent_model.php'
 		);
 
 		$this->load->model('ci_test_nonexistent_model.php');
@@ -247,8 +240,8 @@
 
 	// public function testDatabase()
 	// {
-	// 	$this->assertNull($this->load->database());
-	// 	$this->assertNull($this->load->dbutil());
+	// 	$this->assertInstanceOf('CI_Loader', $this->load->database());
+	// 	$this->assertInstanceOf('CI_Loader', $this->load->dbutil());
 	// }
 
 	// --------------------------------------------------------------------
@@ -272,7 +265,7 @@
 		$this->ci_instance_var('output', $output);
 
 		// Test view output
-		$this->assertNull($this->load->view($view, array($var => $value)));
+		$this->assertInstanceOf('CI_Loader', $this->load->view($view, array($var => $value)));
 	}
 
 	// --------------------------------------------------------------------
@@ -318,8 +311,8 @@
 		$val1 = 'bar';
 		$key2 = 'boo';
 		$val2 = 'hoo';
-		$this->assertNull($this->load->vars(array($key1 => $val1)));
-		$this->assertNull($this->load->vars($key2, $val2));
+		$this->assertInstanceOf('CI_Loader', $this->load->vars(array($key1 => $val1)));
+		$this->assertInstanceOf('CI_Loader', $this->load->vars($key2, $val2));
 		$this->assertEquals($val1, $this->load->get_var($key1));
 		$this->assertEquals(array($key1 => $val1, $key2 => $val2), $this->load->get_vars());
 	}
@@ -340,7 +333,7 @@
 		$this->ci_vfs_create($this->prefix.$helper.'_helper', $content, $this->ci_app_root, 'helpers');
 
 		// Load helper
-		$this->assertNull($this->load->helper($helper));
+		$this->assertInstanceOf('CI_Loader', $this->load->helper($helper));
 		$this->assertTrue(function_exists($func), $func.' does not exist');
 		$this->assertTrue(function_exists($exfunc), $exfunc.' does not exist');
 
@@ -385,7 +378,7 @@
 		$this->ci_vfs_create($files, NULL, $this->ci_base_root, 'helpers');
 
 		// Load helpers
-		$this->assertNull($this->load->helpers($helpers));
+		$this->assertInstanceOf('CI_Loader', $this->load->helpers($helpers));
 
 		// Verify helper existence
 		foreach ($funcs as $func) {
@@ -402,7 +395,7 @@
 		$lang = $this->getMock('CI_Lang', array('load'));
 		$lang->expects($this->once())->method('load')->with($file);
 		$this->ci_instance_var('lang', $lang);
-		$this->assertNull($this->load->language($file));
+		$this->assertInstanceOf('CI_Loader', $this->load->language($file));
 	}
 
 	// --------------------------------------------------------------------
@@ -420,24 +413,24 @@
 
 		// Add path and verify
 		$path = APPPATH.$dir.'/';
-		$this->assertNull($this->load->add_package_path($path));
+		$this->assertInstanceOf('CI_Loader', $this->load->add_package_path($path));
 		$this->assertContains($path, $this->load->get_package_paths(TRUE));
 
 		// Test successful load
-		$this->assertNull($this->load->library($lib));
+		$this->assertInstanceOf('CI_Loader', $this->load->library($lib));
 		$this->assertTrue(class_exists($class), $class.' does not exist');
 
 		// Add another path
 		$path2 = APPPATH.'another/';
-		$this->assertNull($this->load->add_package_path($path2));
+		$this->assertInstanceOf('CI_Loader', $this->load->add_package_path($path2));
 		$this->assertContains($path2, $this->load->get_package_paths(TRUE));
 
 		// Remove last path
-		$this->assertNull($this->load->remove_package_path());
+		$this->assertInstanceOf('CI_Loader', $this->load->remove_package_path());
 		$this->assertNotContains($path2, $this->load->get_package_paths(TRUE));
 
 		// Remove path and verify restored paths
-		$this->assertNull($this->load->remove_package_path($path));
+		$this->assertInstanceOf('CI_Loader', $this->load->remove_package_path($path));
 		$this->assertEquals($paths, $this->load->get_package_paths(TRUE));
 
 		// Test failed load without path
@@ -481,9 +474,8 @@
 		// Create model in VFS package path
 		$dir = 'testdir';
 		$path = APPPATH.$dir.'/';
-		$model = 'automod';
-		$mod_class = ucfirst($model);
-		$this->ci_vfs_create($model, '<?php class '.$mod_class.' { }', $this->ci_app_root, array($dir, 'models'));
+		$model = 'Automod';
+		$this->ci_vfs_create($model, '<?php class '.$model.' { }', $this->ci_app_root, array($dir, 'models'));
 
 		// Create autoloader config
 		$cfg = array(
@@ -513,8 +505,8 @@
 		$this->assertAttributeInstanceOf($drv_class, $drv, $this->ci_obj);
 
 		// Verify model
-		$this->assertTrue(class_exists($mod_class), $mod_class.' does not exist');
-		$this->assertAttributeInstanceOf($mod_class, $model, $this->ci_obj);
+		$this->assertTrue(class_exists($model), $model.' does not exist');
+		$this->assertAttributeInstanceOf($model, $model, $this->ci_obj);
 
 		// Verify config calls
 		$this->assertEquals($cfg['config'], $this->ci_obj->config->loaded);
diff --git a/tests/codeigniter/core/Model_test.php b/tests/codeigniter/core/Model_test.php
new file mode 100644
index 0000000..80dc97b
--- /dev/null
+++ b/tests/codeigniter/core/Model_test.php
@@ -0,0 +1,37 @@
+<?php
+
+class Model_test extends CI_TestCase {
+
+	private $ci_obj;
+
+	public function set_up()
+	{
+		$loader = $this->ci_core_class('loader');
+		$this->load = new $loader();
+		$this->ci_obj = $this->ci_instance();
+		$this->ci_set_core_class('model', 'CI_Model');
+
+		$model_code =<<<MODEL
+<?php
+class Test_model extends CI_Model {
+
+	public \$property = 'foo';
+
+}
+MODEL;
+
+		$this->ci_vfs_create('Test_model', $model_code, $this->ci_app_root, 'models');
+		$this->load->model('test_model');
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test__get()
+	{
+		$this->assertEquals('foo', $this->ci_obj->test_model->property);
+
+		$this->ci_obj->controller_property = 'bar';
+		$this->assertEquals('bar', $this->ci_obj->test_model->controller_property);
+	}
+
+}
\ No newline at end of file
diff --git a/tests/codeigniter/core/Security_test.php b/tests/codeigniter/core/Security_test.php
index 3f6e3b0..433ad31 100644
--- a/tests/codeigniter/core/Security_test.php
+++ b/tests/codeigniter/core/Security_test.php
@@ -5,7 +5,7 @@
 	public function set_up()
 	{
 		// Set cookie for security test
-		$_COOKIE['ci_csrf_cookie'] = md5(uniqid(rand(), TRUE));
+		$_COOKIE['ci_csrf_cookie'] = md5(uniqid(mt_rand(), TRUE));
 
 		// Set config for Security class
 		$this->ci_set_config('csrf_protection', TRUE);
diff --git a/tests/codeigniter/core/URI_test.php b/tests/codeigniter/core/URI_test.php
index 7fa0e62..6589c1f 100644
--- a/tests/codeigniter/core/URI_test.php
+++ b/tests/codeigniter/core/URI_test.php
@@ -26,6 +26,10 @@
 
 	// --------------------------------------------------------------------
 
+	/*
+
+		This has been moved to the constructor
+
 	public function test_fetch_uri_string()
 	{
 		define('SELF', 'index.php');
@@ -86,9 +90,14 @@
 		// uri_protocol: REQUEST_URI
 		// uri_protocol: CLI
 	}
+	*/
 
 	// --------------------------------------------------------------------
 
+	/*
+
+		This has been moved into _set_uri_string()
+
 	public function test_explode_segments()
 	{
 		// Let's test the function's ability to clean up this mess
@@ -107,16 +116,15 @@
 			$this->assertEquals($a, $this->uri->segments);
 		}
 	}
-
+	*/
 	// --------------------------------------------------------------------
 
 	public function test_filter_uri()
 	{
-		$this->uri->config->set_item('enable_query_strings', FALSE);
-		$this->uri->config->set_item('permitted_uri_chars', 'a-z 0-9~%.:_\-');
+		$this->uri->_set_permitted_uri_chars('a-z 0-9~%.:_\-');
 
 		$str_in = 'abc01239~%.:_-';
-		$str = $this->uri->_filter_uri($str_in);
+		$str = $this->uri->filter_uri($str_in);
 
 		$this->assertEquals($str, $str_in);
 	}
@@ -126,11 +134,9 @@
 	public function test_filter_uri_escaping()
 	{
 		// ensure escaping even if dodgey characters are permitted
+		$this->uri->_set_permitted_uri_chars('a-z 0-9~%.:_\-()$');
 
-		$this->uri->config->set_item('enable_query_strings', FALSE);
-		$this->uri->config->set_item('permitted_uri_chars', 'a-z 0-9~%.:_\-()$');
-
-		$str = $this->uri->_filter_uri('$destroy_app(foo)');
+		$str = $this->uri->filter_uri('$destroy_app(foo)');
 
 		$this->assertEquals($str, '&#36;destroy_app&#40;foo&#41;');
 	}
@@ -142,25 +148,8 @@
 		$this->setExpectedException('RuntimeException');
 
 		$this->uri->config->set_item('enable_query_strings', FALSE);
-		$this->uri->config->set_item('permitted_uri_chars', 'a-z 0-9~%.:_\-');
-		$this->uri->_filter_uri('$this()');
-	}
-
-	// --------------------------------------------------------------------
-
-	public function test_remove_url_suffix()
-	{
-		$this->uri->config->set_item('url_suffix', '.html');
-
-		$this->uri->uri_string = 'controller/method/index.html';
-		$this->uri->_remove_url_suffix();
-
-		$this->assertEquals($this->uri->uri_string, 'controller/method/index');
-
-		$this->uri->uri_string = 'controller/method/index.htmlify.html';
-		$this->uri->_remove_url_suffix();
-
-		$this->assertEquals($this->uri->uri_string, 'controller/method/index.htmlify');
+		$this->uri->_set_permitted_uri_chars('a-z 0-9~%.:_\-');
+		$this->uri->filter_uri('$this()');
 	}
 
 	// --------------------------------------------------------------------
diff --git a/tests/codeigniter/core/Utf8_test.php b/tests/codeigniter/core/Utf8_test.php
index caa7b69..7129913 100644
--- a/tests/codeigniter/core/Utf8_test.php
+++ b/tests/codeigniter/core/Utf8_test.php
@@ -11,10 +11,15 @@
 
 	public function test_convert_to_utf8()
 	{
-		$this->assertEquals(
-			$this->utf8->convert_to_utf8('òåñò', 'WINDOWS-1251'),
-			'тест'
-		);
+		$this->assertEquals('тест', $this->utf8->convert_to_utf8('òåñò', 'WINDOWS-1251'));
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_is_ascii()
+	{
+		$this->assertTrue($this->utf8->is_ascii_test('foo bar'));
+		$this->assertFalse($this->utf8->is_ascii_test('тест'));
 	}
 
 }
\ No newline at end of file
diff --git a/tests/codeigniter/helpers/text_helper_test.php b/tests/codeigniter/helpers/text_helper_test.php
index d75d262..7a7dc0a 100644
--- a/tests/codeigniter/helpers/text_helper_test.php
+++ b/tests/codeigniter/helpers/text_helper_test.php
@@ -106,17 +106,19 @@
 	public function test_highlight_phrase()
 	{
 		$strs = array(
-			'this is a phrase'			=> '<strong>this is</strong> a phrase',
-			'this is another'			=> '<strong>this is</strong> another',
-			'Gimme a test, Sally'		=> 'Gimme a test, Sally',
-			'Or tell me what this is'	=> 'Or tell me what <strong>this is</strong>',
-			''							=> ''
+			'this is a phrase'          => '<mark>this is</mark> a phrase',
+			'this is another'           => '<mark>this is</mark> another',
+			'Gimme a test, Sally'       => 'Gimme a test, Sally',
+			'Or tell me what this is'   => 'Or tell me what <mark>this is</mark>',
+			''                          => ''
 		);
 
 		foreach ($strs as $str => $expect)
 		{
 			$this->assertEquals($expect, highlight_phrase($str, 'this is'));
 		}
+
+		$this->assertEquals('<strong>this is</strong> a strong test', highlight_phrase('this is a strong test', 'this is', '<strong>', '</strong>'));
 	}
 
 	// ------------------------------------------------------------------------
diff --git a/tests/codeigniter/libraries/Calendar_test.php b/tests/codeigniter/libraries/Calendar_test.php
index 952e8a8..768bc85 100644
--- a/tests/codeigniter/libraries/Calendar_test.php
+++ b/tests/codeigniter/libraries/Calendar_test.php
@@ -169,30 +169,33 @@
 		$this->assertEquals(31, $this->calendar->get_total_days(12, 2012));
 	}
 
-	function test_default_template()
+	public function test_default_template()
 	{
 		$array = array(
-			'table_open'				=> '<table border="0" cellpadding="4" cellspacing="0">',
-			'heading_row_start'			=> '<tr>',
+			'table_open'			=> '<table border="0" cellpadding="4" cellspacing="0">',
+			'heading_row_start'		=> '<tr>',
 			'heading_previous_cell'		=> '<th><a href="{previous_url}">&lt;&lt;</a></th>',
 			'heading_title_cell'		=> '<th colspan="{colspan}">{heading}</th>',
-			'heading_next_cell'			=> '<th><a href="{next_url}">&gt;&gt;</a></th>',
-			'heading_row_end'			=> '</tr>',
-			'week_row_start'			=> '<tr>',
-			'week_day_cell'				=> '<td>{week_day}</td>',
-			'week_row_end'				=> '</tr>',
-			'cal_row_start'				=> '<tr>',
-			'cal_cell_start'			=> '<td>',
+			'heading_next_cell'		=> '<th><a href="{next_url}">&gt;&gt;</a></th>',
+			'heading_row_end'		=> '</tr>',
+			'week_row_start'		=> '<tr>',
+			'week_day_cell'			=> '<td>{week_day}</td>',
+			'week_row_end'			=> '</tr>',
+			'cal_row_start'			=> '<tr>',
+			'cal_cell_start'		=> '<td>',
 			'cal_cell_start_today'		=> '<td>',
-			'cal_cell_content'			=> '<a href="{content}">{day}</a>',
+			'cal_cell_content'		=> '<a href="{content}">{day}</a>',
 			'cal_cell_content_today'	=> '<a href="{content}"><strong>{day}</strong></a>',
 			'cal_cell_no_content'		=> '{day}',
 			'cal_cell_no_content_today'	=> '<strong>{day}</strong>',
-			'cal_cell_blank'			=> '&nbsp;',
-			'cal_cell_end'				=> '</td>',
+			'cal_cell_blank'		=> '&nbsp;',
+			'cal_cell_end'			=> '</td>',
 			'cal_cell_end_today'		=> '</td>',
-			'cal_row_end'				=> '</tr>',
-			'table_close'				=> '</table>'
+			'cal_row_end'			=> '</tr>',
+			'table_close'			=> '</table>',
+			'cal_cell_start_other'		=> '<td style="color: #666;">',
+			'cal_cell_other'		=> '{day}',
+			'cal_cell_end_other'		=> '</td>'
 		);
 
 		$this->assertEquals($array, $this->calendar->default_template());
diff --git a/tests/codeigniter/libraries/Parser_test.php b/tests/codeigniter/libraries/Parser_test.php
index 394c226..3755cf1 100644
--- a/tests/codeigniter/libraries/Parser_test.php
+++ b/tests/codeigniter/libraries/Parser_test.php
@@ -33,7 +33,7 @@
 
 	// --------------------------------------------------------------------
 
-	public function test_parse_simple_string()
+	public function test_parse_string()
 	{
 		$data = array(
 			'title' => 'Page Title',
@@ -69,16 +69,12 @@
 	{
 		$data = array(
 			'title'		=> 'Super Heroes',
-			'powers'	=> array(
-					array(
-						'invisibility'	=> 'yes',
-						'flying'		=> 'no'),
-			)
+			'powers'	=> array(array('invisibility' => 'yes', 'flying' => 'no'))
 		);
 
-		$template = "{title}\n{powers}{invisibility}\n{flying}{/powers}";
+		$template = "{title}\n{powers}{invisibility}\n{flying}{/powers}\nsecond:{powers} {invisibility} {flying}{/powers}";
 
-		$this->assertEquals("Super Heroes\nyes\nno", $this->parser->parse_string($template, $data, TRUE));
+		$this->assertEquals("Super Heroes\nyes\nno\nsecond: yes no", $this->parser->parse_string($template, $data, TRUE));
 	}
 
 	// --------------------------------------------------------------------
@@ -87,11 +83,7 @@
 	{
 		$data = array(
 			'title'		=> 'Super Heroes',
-			'powers'	=> array(
-					array(
-						'invisibility'	=> 'yes',
-						'flying'		=> 'no'),
-			)
+			'powers'	=> array(array('invisibility' => 'yes', 'flying' => 'no'))
 		);
 
 		$template = "{title}\n{powers}{invisibility}\n{flying}";
diff --git a/tests/codeigniter/libraries/Useragent_test.php b/tests/codeigniter/libraries/Useragent_test.php
index e372655..aed38b8 100644
--- a/tests/codeigniter/libraries/Useragent_test.php
+++ b/tests/codeigniter/libraries/Useragent_test.php
@@ -11,9 +11,7 @@
 		$_SERVER['HTTP_USER_AGENT'] = $this->_user_agent;
 
 		$this->ci_vfs_clone('application/config/user_agents.php');
-
 		$this->agent = new Mock_Libraries_UserAgent();
-
 		$this->ci_instance_var('agent', $this->agent);
 	}
 
@@ -40,12 +38,27 @@
 
 	// --------------------------------------------------------------------
 
-	public function test_util_is_functions()
+	public function test_is_functions()
 	{
 		$this->assertTrue($this->agent->is_browser());
+		$this->assertTrue($this->agent->is_browser('Safari'));
+		$this->assertFalse($this->agent->is_browser('Firefox'));
 		$this->assertFalse($this->agent->is_robot());
 		$this->assertFalse($this->agent->is_mobile());
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_referrer()
+	{
+		$_SERVER['HTTP_REFERER'] = 'http://codeigniter.com/user_guide/';
+		$this->assertTrue($this->agent->is_referral());
+		$this->assertEquals('http://codeigniter.com/user_guide/', $this->agent->referrer());
+
+		$this->agent->referer = NULL;
+		unset($_SERVER['HTTP_REFERER']);
 		$this->assertFalse($this->agent->is_referral());
+		$this->assertEquals('', $this->agent->referrer());
 	}
 
 	// --------------------------------------------------------------------
@@ -63,7 +76,6 @@
 		$this->assertEquals('Safari', $this->agent->browser());
 		$this->assertEquals('533.20.27', $this->agent->version());
 		$this->assertEquals('', $this->agent->robot());
-		$this->assertEquals('', $this->agent->referrer());
 	}
 
 	// --------------------------------------------------------------------
@@ -71,14 +83,43 @@
 	public function test_charsets()
 	{
 		$_SERVER['HTTP_ACCEPT_CHARSET'] = 'utf8';
+		$this->agent->charsets = array();
+		$this->agent->charsets();
+		$this->assertTrue($this->agent->accept_charset('utf8'));
+		$this->assertFalse($this->agent->accept_charset('foo'));
+		$this->assertEquals('utf8', $this->agent->charsets[0]);
 
-		$charsets = $this->agent->charsets();
+		$_SERVER['HTTP_ACCEPT_CHARSET'] = '';
+		$this->agent->charsets = array();
+		$this->assertFalse($this->agent->accept_charset());
+		$this->assertEquals('Undefined', $this->agent->charsets[0]);
 
-		$this->assertEquals('utf8', $charsets[0]);
+		$_SERVER['HTTP_ACCEPT_CHARSET'] = 'iso-8859-5, unicode-1-1; q=0.8';
+		$this->agent->charsets = array();
+		$this->assertTrue($this->agent->accept_charset('iso-8859-5'));
+		$this->assertTrue($this->agent->accept_charset('unicode-1-1'));
+		$this->assertFalse($this->agent->accept_charset('foo'));
+		$this->assertEquals('iso-8859-5', $this->agent->charsets[0]);
+		$this->assertEquals('unicode-1-1', $this->agent->charsets[1]);
 
 		unset($_SERVER['HTTP_ACCEPT_CHARSET']);
+	}
 
-		$this->assertFalse($this->agent->accept_charset());
+	public function test_parse()
+	{
+		$new_agent = 'Mozilla/5.0 (Android; Mobile; rv:13.0) Gecko/13.0 Firefox/13.0';
+		$this->agent->parse($new_agent);
+
+		$this->assertEquals('Android', $this->agent->platform());
+		$this->assertEquals('Firefox', $this->agent->browser());
+		$this->assertEquals('13.0', $this->agent->version());
+		$this->assertEquals('', $this->agent->robot());
+		$this->assertEquals('Android', $this->agent->mobile());
+		$this->assertEquals($new_agent, $this->agent->agent_string());
+		$this->assertTrue($this->agent->is_browser());
+		$this->assertFalse($this->agent->is_robot());
+		$this->assertTrue($this->agent->is_mobile());
+		$this->assertTrue($this->agent->is_mobile('android'));
 	}
 
 }
\ No newline at end of file
diff --git a/tests/mocks/autoloader.php b/tests/mocks/autoloader.php
index 3d216da..cc0a2e2 100644
--- a/tests/mocks/autoloader.php
+++ b/tests/mocks/autoloader.php
@@ -89,21 +89,7 @@
 
 	if ( ! file_exists($file))
 	{
-		$trace = debug_backtrace();
-
-		if ($trace[2]['function'] === 'class_exists' OR $trace[2]['function'] === 'file_exists')
-		{
-			// If the autoload call came from `class_exists` or `file_exists`,
-			// we skipped and return FALSE
-			return FALSE;
-		}
-		elseif (($autoloader = spl_autoload_functions()) && end($autoloader) !== __FUNCTION__)
-		{
-			// If there was other custom autoloader, passed away
-			return FALSE;
-		}
-
-		throw new InvalidArgumentException("Unable to load {$class}.");
+    return FALSE;
 	}
 
 	include_once($file);
diff --git a/tests/mocks/core/common.php b/tests/mocks/core/common.php
index 0ccfe1e..b073f23 100644
--- a/tests/mocks/core/common.php
+++ b/tests/mocks/core/common.php
@@ -178,7 +178,7 @@
 
 if ( ! function_exists('log_message'))
 {
-	function log_message($level, $message, $php_error = FALSE)
+	function log_message($level, $message)
 	{
 		return TRUE;
 	}
@@ -190,4 +190,13 @@
 	{
 		return TRUE;
 	}
+}
+
+if ( ! function_exists('is_cli'))
+{
+	// In order to test HTTP functionality, we need to lie about this
+	function is_cli()
+	{
+		return FALSE;
+	}
 }
\ No newline at end of file
diff --git a/tests/mocks/core/uri.php b/tests/mocks/core/uri.php
index 94f75df..96ec5af 100644
--- a/tests/mocks/core/uri.php
+++ b/tests/mocks/core/uri.php
@@ -10,17 +10,23 @@
 		// set predictable config values
 		$test->ci_set_config(array(
 			'index_page'		=> 'index.php',
-			'base_url'			=> 'http://example.com/',
-			'subclass_prefix'	=> 'MY_'
+			'base_url'		=> 'http://example.com/',
+			'subclass_prefix'	=> 'MY_',
+			'enable_query_strings'	=> FALSE,
+			'permitted_uri_chars'	=> 'a-z 0-9~%.:_\-'
 		));
 
 		$this->config = new $cls;
 
+		if ($this->config->item('enable_query_strings') !== TRUE OR is_cli())
+		{
+			$this->_permitted_uri_chars = $this->config->item('permitted_uri_chars');
+		}
 	}
 
-	protected function _is_cli_request()
+	public function _set_permitted_uri_chars($value)
 	{
-		return FALSE;
+		$this->_permitted_uri_chars = $value;
 	}
 
 }
\ No newline at end of file
diff --git a/tests/mocks/core/utf8.php b/tests/mocks/core/utf8.php
index 068e74a..a43138f 100644
--- a/tests/mocks/core/utf8.php
+++ b/tests/mocks/core/utf8.php
@@ -23,4 +23,9 @@
 		}
 	}
 
+	public function is_ascii_test($str)
+	{
+		return $this->_is_ascii($str);
+	}
+
 }
\ No newline at end of file
diff --git a/user_guide_src/source/_themes/eldocs/static/asset/css/common.css b/user_guide_src/source/_themes/eldocs/static/asset/css/common.css
index d5b0e21..962380b 100644
--- a/user_guide_src/source/_themes/eldocs/static/asset/css/common.css
+++ b/user_guide_src/source/_themes/eldocs/static/asset/css/common.css
@@ -143,7 +143,7 @@
 a:hover,
 a:active{ color: #742CAC; }
 
-a.headerlink{ visibility: hidden; }
+a.headerlink{ visibility: hidden; margin-left: 0.4em; }
 
 	:hover > a.headerlink { visibility: visible; }
 
@@ -277,7 +277,7 @@
 		background-color: #FFFFFF;
 		border: 1px solid;
 		border-color: #033861 #13598F #13598F #033861;
-		font-size: inherit;
+		font: inherit;
 		margin-right: 5px;
 		padding: 5px;
 		width: 175px;
@@ -290,8 +290,9 @@
 		border: 1px solid #033861;
 		color: #094776;
 		cursor: pointer;
+		font: inherit;
 		font-weight: bold;
-		padding: 5px 10px 4px;
+		padding: 5px 10px;
 		text-transform: uppercase;
 	}
 
@@ -360,6 +361,4 @@
 	h3,h4,h5,h6{ font-size: 14px; }
 }
 
-@media screen and (-webkit-min-device-pixel-ratio:0){
-	#header input[type="submit"]{ padding-bottom: 7px; }
-}
+#header input[type="submit"], x:-moz-any-link{ padding: 4px 10px; }
diff --git a/user_guide_src/source/changelog.rst b/user_guide_src/source/changelog.rst
index ba980d8..cd1998b 100644
--- a/user_guide_src/source/changelog.rst
+++ b/user_guide_src/source/changelog.rst
@@ -19,10 +19,12 @@
 -  General Changes
 
    -  PHP 5.1.6 is no longer supported. CodeIgniter now requires PHP 5.2.4.
+   -  Changed filenaming convention (class file names now must be Ucfirst and everything else in lowercase).
+   -  Changed the default database driver to 'mysqli' (the old 'mysql' driver is DEPRECATED).
    -  ``$_SERVER['CI_ENV']`` can now be set to control the ``ENVIRONMENT`` constant.
    -  Added an optional backtrace to php-error template.
    -  Added Android to the list of user agents.
-   -  Added Windows 7, Windows 8, Android, Blackberry, iOS and PlayStation 3 to the list of user platforms.
+   -  Added Windows 7, Windows 8, Windows 8.1, Android, Blackberry, iOS and PlayStation 3 to the list of user platforms.
    -  Added Fennec (Firefox for mobile) to the list of mobile user agents.
    -  Ability to log certain error types, not all under a threshold.
    -  Added support for pem, p10, p12, p7a, p7c, p7m, p7r, p7s, crt, crl, der, kdb, rsa, cer, sst, csr Certs to mimes.php.
@@ -54,8 +56,10 @@
    -  Changed environment defaults to report all errors in *development* and only fatal ones in *testing*, *production* but only display them in *development*.
    -  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 support non-HTML error templates for CLI applications.
    -  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']``.
+   -  Added support for turning newline standardization on/off via ``$config['standardize_newlines']``.
 
 -  Helpers
 
@@ -73,10 +77,9 @@
       - :func:`url_title()` will now trim extra dashes from beginning and end.
       - :func:`anchor_popup()` will now fill the *href* attribute with the URL and its JS code will return FALSE instead.
       - Added JS window name support to the :func:`anchor_popup()` function.
-      - Added support (auto-detection) for HTTP/1.1 response code 303 in :func:`redirect()`.
+      - Added support (auto-detection) for HTTP/1.1 response codes 303, 307 in :func:`redirect()`.
       - Changed :func:`redirect()` to choose the **refresh** method only on IIS servers, instead of all servers on Windows (when **auto** is used).
       - Changed :func:`anchor()`, :func:`anchor_popup()`, and :func:`redirect()` to support protocol-relative URLs (e.g. *//ellislab.com/codeigniter*).
-      - Added an optional second parameter to both :func:`base_url()` and :func:`site_url()` that allows enforcing of a protocol different than the one in the *base_url* configuration setting.
 
    -  :doc:`HTML Helper <helpers/html_helper>` changes include:
 
@@ -127,13 +130,17 @@
 
       - Added *word_length* and *pool* options to allow customization of the generated word.
       - Added *colors* configuration to allow customization for the *background*, *border*, *text* and *grid* colors.
+      - Added *filename* to the returned array elements.
 
    -  :doc:`Directory Helper <helpers/directory_helper>` :func:`directory_map()` will now append ``DIRECTORY_SEPARATOR`` to directory names in the returned array.
+   -  :doc:`Array Helper <helpers/array_helper>` :func:`element()` and :php:func:`elements()` now return NULL instead of FALSE when the required elements don't exist.
    -  :doc:`Language Helper <helpers/language_helper>` :func:`lang()` now accepts an optional list of additional HTML attributes.
+   -  Changed the default tag for use in :doc:`Text Helper <helpers/text_helper>` :func:`highlight_phrase()` to ``<mark>`` (formerly ``<strong>``).
    -  Deprecated the :doc:`Email Helper <helpers/email_helper>` as its ``valid_email()``, ``send_email()`` functions are now only aliases for PHP native functions ``filter_var()`` and ``mail()`` respectively.
 
 -  Database
 
+   -  DEPRECATED the 'mysql', 'sqlite', 'mssql' and 'pdo/dblib' (also known as 'pdo/mssql' or 'pdo/sybase') drivers.
    -  Added **dsn** configuration setting for drivers that support DSN strings (PDO, PostgreSQL, Oracle, ODBC, CUBRID).
    -  Added **schema** configuration setting (defaults to *public*) for drivers that might need it (currently used by PostgreSQL and ODBC).
    -  Added subdrivers support (currently only used by PDO).
@@ -153,6 +160,7 @@
    -  Added support for SQLite3 database driver.
    -  Added Interbase/Firebird database support via the *ibase* driver.
    -  Added ODBC support for ``create_database()``, ``drop_database()`` and ``drop_table()`` in :doc:`Database Forge <database/forge>`.
+   -  Added **save_queries** configuration setting to *application/config/database.php* (defaults to ``TRUE``).
 
    -  :doc:`Query Builder <database/query_builder>` changes include:
 
@@ -162,6 +170,7 @@
       - Added an optional parameter that allows to disable escaping (useful for custom fields) for methods ``join()``, ``order_by()``, ``where_in()``, ``or_where_in()``, ``where_not_in()``, ``or_where_not_in()``, ``insert()``, ``insert_batch()``.
       - Added support for ``join()`` with multiple conditions.
       - Added support for *USING* in ``join()``.
+      - Added support for *EXISTS* in ``where()``.
       - Added seed values support for random ordering with ``order_by(seed, 'RANDOM')``.
       - Changed ``limit()`` to ignore NULL values instead of always casting to integer.
       - Changed ``offset()`` to ignore empty values instead of always casting to integer.
@@ -179,6 +188,7 @@
       - Server version checking is now done via ``mysqli::$server_info`` instead of running an SQL query.
       - Added persistent connections support for PHP >= 5.3.
       - Added support for ``backup()`` in :doc:`Database Utilities <database/utilities>`.
+      - Changed methods ``trans_begin()``, ``trans_commit()`` and ``trans_rollback()`` to use the PHP API instead of sending queries.
 
    -  Improved support of the PDO driver, including:
 
@@ -196,6 +206,7 @@
       - Removed ``limit()`` and ``order_by()`` support for *UPDATE* and *DELETE* queries as PostgreSQL does not support those features.
       - Added a work-around for dead persistent connections to be re-created after a database restart.
       - Changed ``db_connect()`` to include the (new) **schema** value into Postgre's **search_path** session variable.
+      - ``pg_escape_literal()`` is now used for escaping strings, if available.
 
    -  Improved support of the CUBRID driver, including:
 
@@ -269,8 +280,14 @@
       -  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()``.
       -  Added **file_ext_tolower** config setting.
+      -  Added **mod_mime_fix** option to disable suffixing multiple file extensions with an underscore.
 
-   -  :doc:`Cart library <libraries/cart>` changes include:
+   -  :doc:`Calendar Library <libraries/calendar>` changes include:
+
+      -  Added configuration to generate days of other months instead of blank cells.
+      -  Auto set *next_prev_url* if it is empty and *show_prev_next* is set to TRUE.
+
+   -  :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.
@@ -278,7 +295,7 @@
       -  Added method ``get_item()`` to enable retrieving data for a single cart item.
       -  Added unicode support for product names.
 
-   -  :doc:`Image Manipulation library <libraries/image_lib>` changes include:
+   -  :doc:`Image Manipulation Library <libraries/image_lib>` changes include:
 
       -  The ``initialize()`` method now only sets existing class properties.
       -  Added support for 3-length hex color values for *wm_font_color* and *wm_shadow_color* properties, as well as validation for them.
@@ -287,7 +304,7 @@
       -  Property *maintain_ratio* is now taken into account when resizing images using ImageMagick library.
       -  Added support for maintaining transparency for PNG images in method ``text_watermark()``.
 
-   -  :doc:`Form Validation library <libraries/form_validation>` changes include:
+   -  :doc:`Form Validation Library <libraries/form_validation>` changes include:
 
       -  Added method ``error_array()`` to return all error messages as an array.
       -  Added method ``set_data()`` to set an alternative data array to be validated instead of the default ``$_POST``.
@@ -303,19 +320,25 @@
       -  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 custom error messages per field rule.
 
    -  :doc:`Caching Library <libraries/caching>` changes include:
 
       -  Added Wincache driver.
       -  Added Redis driver.
       -  Added a *key_prefix* option for cache IDs.
+      -  Updated driver ``is_supported()`` methods to log at the "debug" level.
+      -  Added option to store raw values instead of CI-formatted ones (APC, Memcache).
+      -  Added atomic increment/decrement feature via ``increment()``, ``decrement()``.
 
-   -  :doc:`Email library <libraries/email>` changes include:
+   -  :doc:`Email Library <libraries/email>` changes include:
 
-      -  Added custom filename to ``Email::attach()`` as ``$this->email->attach($filename, $disposition, $newname)``.
-      -  Added possibility to send attachment as buffer string in ``Email::attach()`` as ``$this->email->attach($buffer, $disposition, $newname, $mime)``.
+      -  Added a custom filename parameter to ``attach()`` as ``$this->email->attach($filename, $disposition, $newname)``.
+      -  Added possibility to send attachment as buffer string in ``attach()`` as ``$this->email->attach($buffer, $disposition, $newname, $mime)``.
+      -  Added possibility to attach remote files by passing a URL.
+      -  Added method ``attachment_cid()`` to enable embedding inline attachments into HTML.
       -  Added dsn (delivery status notification) option.
-      -  Renamed method _set_header() to set_header() and made it public to enable adding custom headers in the :doc:`Email Library <libraries/email>`.
+      -  Renamed method ``_set_header()`` to ``set_header()`` and made it public to enable adding custom headers.
       -  Successfully sent emails will automatically clear the parameters.
       -  Added a *return_path* parameter to the ``from()`` method.
       -  Removed the second parameter (character limit) from internal method ``_prep_quoted_printable()`` as it is never used.
@@ -324,7 +347,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``.
+      -  Added SMTP keepalive option to avoid opening the connection for each ``send()`` call. Accessible as ``$smtp_keepalive``.
       -  Public method ``set_header()`` now filters the input by removing all "\\r" and "\\n" characters.
 
    -  :doc:`Pagination Library <libraries/pagination>` changes include:
@@ -334,7 +357,6 @@
       -  Deprecated usage of the "anchor_class" setting (use the new "attributes" setting instead).
       -  Added $config['reuse_query_string'] to allow automatic repopulation of query string arguments, combined with normal URI segments.
       -  Removed the default ``&nbsp;`` from a number of the configuration variables.
-      -  Added the ability to use a proxy with the :doc:`XML-RPC Library <libraries/xmlrpc>`.
 
    -  :doc:`Encryption Library <libraries/encryption>` changes include:
 
@@ -346,34 +368,64 @@
       -  Database object names are now being displayed.
       -  The sum of all queries running times in seconds is now being displayed.
       -  Added support for displaying the HTTP DNT ("Do Not Track") header.
+      -  Added support for displaying ``$_FILES``.
 
    -  :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.
 
-   -  :doc:`User Agent Library <libraries/user_agent>` will now check if robots are pretending to be mobile clients (helps with e.g. Google indexing mobile website versions).
+   -  :doc:`XML-RPC Library <libraries/xmlrpc>` changes include:
+
+      -  Added the ability to use a proxy.
+      -  Added Basic HTTP authentication support.
+
+   -  :doc:`User Agent Library <libraries/user_agent>` changes include:
+
+      - Added check to detect if robots are pretending to be mobile clients (helps with e.g. Google indexing mobile website versions).
+      - Added method ``parse()`` to allow parsing a custom user-agent string, different from the current visitor's.
+
    -  Added support for setting :doc:`Table <libraries/table>` class defaults in a config file.
+   -  :doc:`Zip Library <libraries/zip>` method ``read_file()`` can now also alter the original file path/name while adding files to an archive.
 
 -  Core
 
+   -  :doc:`Routing <general/routing>` changes include:
+
+      -  Added support for multiple levels of controller directories.
+      -  Added support for per-directory *default_controller* and *404_override* classes.
+      -  Added possibility to route requests using HTTP verbs.
+      -  Added possibility to route requests using callbacks.
+      -  Added a new reserved route (*translate_uri_dashes*) to allow usage of dashes in the controller and method URI segments.
+      -  Deprecated methods ``fetch_directory()``, ``fetch_class()`` and ``fetch_method()`` in favor of their respective public properties.
+      -  Removed method ``_set_overrides()`` and moved its logic to the class constructor.
+
    -  :doc:`URI Library <libraries/uri>` changes include:
 
+      -  Added conditional PCRE UTF-8 support to the "invalid URI characters" check and removed the ``preg_quote()`` call from it to allow more flexibility.
+      -  Renamed method ``_filter_uri()`` to ``filter_uri()``.
       -  Changed private methods to protected so that MY_URI can override them.
       -  Renamed internal method ``_parse_cli_args()`` to ``_parse_argv()``.
       -  Renamed internal method ``_detect_uri()`` to ``_parse_request_uri()``.
       -  Changed ``_parse_request_uri()`` to accept absolute URIs for compatibility with HTTP/1.1 as per `RFC2616 <http://www.ietf.org/rfc/rfc2616.txt>`.
       -  Added protected method ``_parse_query_string()`` to URI paths in the the **QUERY_STRING** value, like ``_parse_request_uri()`` does.
       -  Changed ``_fetch_uri_string()`` to try the **PATH_INFO** variable first when auto-detecting.
+      -  Removed methods ``_remove_url_suffix()``, ``_explode_segments()`` and moved their logic into ``_set_uri_string()``.
+      -  Removed method ``_fetch_uri_string()`` and moved its logic into the class constructor.
+      -  Removed method ``_reindex_segments()``.
 
    -  :doc:`Loader Library <libraries/loader>` changes include:
 
+      -  Added method chaining support.
       -  Added method ``get_vars()`` to the Loader to retrieve all variables loaded with ``$this->load->vars()``.
       -  ``_ci_autoloader()`` is now a protected method.
       -  Added autoloading of drivers with ``$autoload['drivers']``.
       -  ``$config['rewrite_short_tags']`` now has no effect when using PHP 5.4 as ``<?=`` will always be available.
       -  Changed method ``config()`` to return whatever ``CI_Config::load()`` returns instead of always being void.
-      -  Added support for model aliasing on autoload.
+      -  Added support for library and model aliasing on autoload.
+      -  Changed method ``is_loaded()`` to ask for the (case sensitive) library name instead of its instance name.
+      -  Removed ``$_base_classes`` property and unified all class data in ``$_ci_classes`` instead.
+      -  Added method ``clear_vars()`` to allow clearing the cached variables for views.
 
    -  :doc:`Input Library <libraries/input>` changes include:
 
@@ -383,7 +435,11 @@
       -  Changed method ``valid_ip()`` to use PHP's native ``filter_var()`` function.
       -  Changed internal method ``_sanitize_globals()`` to skip enforcing reversal of *register_globals* in PHP 5.4+, where this functionality no longer exists.
       -  Changed methods ``get()``, ``post()``, ``get_post()``, ``cookie()``, ``server()``, ``user_agent()`` to return NULL instead of FALSE when no value is found.
+      -  Changed default value of the ``$xss_clean`` parameter to NULL for all methods that utilize it, the default value is now determined by the ``$config['global_xss_filtering']`` setting.
+      -  Added method ``post_get()`` and changed ``get_post()`` to search in GET data first. Both methods' names now properly match their GET/POST data search priorities.
       -  Changed method ``_fetch_from_array()`` to parse array notation in field name.
+      -  Added an option for ``_clean_input_keys()`` to return FALSE instead of terminating the whole script.
+      -  Deprecated the ``is_cli_request()`` method, it is now an alias for the new :php:func:`is_cli()` common function.
 
    -  :doc:`Common functions <general/common_functions>` changes include:
 
@@ -392,42 +448,46 @@
       -  Removed redundant conditional to determine HTTP server protocol in :func:`set_status_header()`.
       -  Changed ``_exception_handler()`` to respect php.ini *display_errors* setting.
       -  Added function :func:`is_https()` to check if a secure connection is used.
+      -  Added function :func:`is_cli()` to replace the ``CI_Input::is_cli_request()`` method.
       -  Added function :func:`function_usable()` to check if a function exists and is not disabled by `Suhosin <http://www.hardened-php.net/suhosin/>`.
+      -  Removed the third (`$php_error`) from function :func:`log_message()`.
 
    -  :doc:`Output Library <libraries/output>` changes include:
 
       -  Added a second argument to method ``set_content_type()`` that allows setting the document charset as well.
       -  Added methods ``get_content_type()`` and ``get_header()``.
       -  Added method ``delete_cache()``.
+      -  Changed caching behavior to compress the output before storing it, if ``$config['compress_output']`` is enabled.
 
    -  :doc:`Config Library <libraries/config>` changes include:
 
       -  Changed ``site_url()`` method  to accept an array as well.
       -  Removed internal method ``_assign_to_config()`` and moved its implementation to *CodeIgniter.php* instead.
+      -  ``item()`` now returns NULL instead of FALSE when the required config item doesn't exist.
+      -  Added an optional second parameter to both ``base_url()`` and ``site_url()`` that allows enforcing of a protocol different than the one in the *base_url* configuration setting.
 
    -  :doc:`Security Library <libraries/security>` changes include:
 
       -  Added method ``strip_image_tags()``.
       -  Added ``$config['csrf_regeneration']``, which makes token regeneration optional.
       -  Added ``$config['csrf_exclude_uris']``, which allows you list URIs which will not have the CSRF validation methods run.
-
-   -  :doc:`URI Routing <general/routing>` changes include:
-
-      -  Added possibility to route requests using callbacks.
-      -  Added a new reserved route (*translate_uri_dashes*) to allow usage of dashes in the controller and method URI segments.
-      -  Deprecated methods ``fetch_directory()``, ``fetch_class()`` and ``fetch_method()`` in favor of their respective public properties.
+      -  Modified method ``sanitize_filename()`` to read a public ``$filename_bad_chars`` property for getting the invalid characters list.
 
    -  :doc:`Language Library <libraries/language>` changes include:
 
-      -  Changed method ``load()`` to filter the language name with ``ctype_digit()``.
+      -  Changed method ``load()`` to filter the language name with ``ctype_alpha()``.
       -  Added an optional second parameter to method ``line()`` to disable error login for line keys that were not found.
       -  Language files are now loaded in a cascading style with the one in **system/** always loaded and overriden afterwards, if another one is found.
 
+   -  :doc:`Hooks Library <general/hooks>` changes include:
+      -  Renamed method ``_call_hook()`` to ``call_hook()``.
+      -  Class instances are now stored in order to maintain their state.
+
    -  Removed ``CI_CORE`` boolean constant from *CodeIgniter.php* (no longer Reactor and Core versions).
    -  Log Library will now try to create the **log_path** directory if it doesn't exist.
    -  Added support for HTTP-Only cookies with new config option *cookie_httponly* (default FALSE).
-   -  Renamed method ``_call_hook()`` to ``call_hook()`` in the :doc:`Hooks Library <general/hooks>`.
    -  ``$config['time_reference']`` now supports all timezone strings supported by PHP.
+   -  Fatal PHP errors are now also passed to ``_exception_handler()``, so they can be logged.
 
 
 Bug fixes for 3.0
@@ -456,7 +516,7 @@
 -  Fixed a possible bug in ``CI_Input::is_ajax_request()`` where some clients might not send the X-Requested-With HTTP header value exactly as 'XmlHttpRequest'.
 -  Fixed a bug (#1039) - MySQL's _backup() method failed due to a table name not being escaped.
 -  Fixed a bug (#1070) - CI_DB_driver::initialize() didn't set a character set if a database is not selected.
--  Fixed a bug (#177) - CI_Form_validation::set_value() didn't set the default value if POST data is NULL.
+-  Fixed a bug (#177) - ``CI_Form_validation::set_value()`` didn't set the default value if POST data is NULL.
 -  Fixed a bug (#68, #414) - Oracle's escape_str() didn't properly escape LIKE wild characters.
 -  Fixed a bug (#81) - ODBC's list_fields() and field_data() methods skipped the first column due to odbc_field_*() functions' index starting at 1 instead of 0.
 -  Fixed a bug (#129) - ODBC's num_rows() returned -1 in some cases, due to not all subdrivers supporting the odbc_num_rows() function.
@@ -584,7 +644,7 @@
 -  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.
 -  Fixed a bug (#2298) - :doc:`Database Results <database/results>` method ``next_row()`` kept returning the last row, allowing for infinite loops.
--  Fixed a bug (#2236) - :doc:`Form Helper <helpers/form_helper>` function ``set_value()`` didn't parse array notation for keys if the rule was not present in the :doc:`Form Validation Library <libraries/form_validation>`.
+-  Fixed a bug (#2236, #2639) - :doc:`Form Helper <helpers/form_helper>` functions :func:`set_value()`, :func:`set_select()`, :func:`set_radio()`, :func:`set_checkbox()` didn't parse array notation for keys if the rule was not present in the :doc:`Form Validation Library <libraries/form_validation>`.
 -  Fixed a bug (#2353) - :doc:`Query Builder <database/query_builder>` erroneously prefixed literal strings with **dbprefix**.
 -  Fixed a bug (#78) - :doc:`Cart Library <libraries/cart>` didn't allow non-English letters in product names.
 -  Fixed a bug (#77) - :doc:`Database Class <database/index>` didn't properly handle the transaction "test mode" flag.
@@ -595,6 +655,33 @@
 -  Fixed a bug (#2490) - :doc:`Database Class <database/queries>` method ``query()`` returning boolean instead of a result object for PostgreSQL-specific *INSERT INTO ... RETURNING* statements.
 -  Fixed a bug (#249) - :doc:`Cache Library <libraries/caching>` didn't properly handle Memcache(d) configurations with missing options.
 -  Fixed a bug (#180) - :func:`config_item()` didn't take into account run-time configuration changes.
+-  Fixed a bug (#2551) - :doc:`Loader Library <libraries/loader>` method ``library()`` didn't properly check if a class that is being loaded already exists.
+-  Fixed a bug (#2560) - :doc:`Form Helper <helpers/form_helper>` function :php:func:`form_open()` set the 'method="post"' attribute only if the passed attributes equaled an empty string.
+-  Fixed a bug (#2585) - :doc:`Query Builder <database/query_builder>` methods ``min()``, ``max()``, ``avg()``, ``sum()`` didn't escape field names.
+-  Fixed an edge case (#2583) in the :doc:`Email Library <libraries/email>` where `Suhosin <http://www.hardened-php.net/suhosin/>` blocked messages sent via ``mail()`` due to trailing newspaces in headers.
+-  Fixed a bug (#2590) - :php:func:`log_message()` didn't actually cache the ``CI_Log`` class instance.
+-  Fixed a bug (#2609) - :php:func:`get_config()` optional argument was only effective on first function call. Also, it can now add items, in addition to updating existing items.
+-  Fixed a bug in the 'postgre' :doc:`database <database/index>` driver where the connection ID wasn't passed to ``pg_escape_string()``.
+-  Fixed a bug (#33) - Script execution was terminated when an invalid cookie key was encountered.
+-  Fixed a bug (#2681) - ``CI_Security::entity_decode()`` used the `PREG_REPLACE_EVAL` flag, which is deprecated since PHP 5.5.
+-  Fixed a bug (#2691) - nested transactions could end in a deadlock when an error is encountered with *db_debug* set to TRUE.
+-  Fixed a bug (#2515) - ``_exception_handler()`` used to send the 200 "OK" HTTP status code and didn't stop script exection even on fatal errors.
+-  Fixed a bug - Redis :doc:`Caching <libraries/caching>` driver didn't handle connection failures properly.
+-  Fixed a bug (#2756) - :doc:`Database Class <database/index>` executed the MySQL-specific `SET SESSION sql_mode` query for all drivers when the 'stricton' option is set.
+-  Fixed a bug (#2579) - :doc:`Query Builder <database/query_builder>` "no escape" functionality didn't work properly with query cache.
+-  Fixed a bug (#2237) - :doc:`Parser Library <libraries/parser>` failed if the same tag pair is used more than once within a template.
+-  Fixed a bug (#2268) - :doc:`Security Library <libraries/security>` didn't properly match JavaScript events.
+-  Fixed a bug (#2143) - :doc:`Form Validation Library <libraries/form_validation>` didn't check for rule groups named in a *controller/method* manner when trying to load from a config file.
+-  Fixed a bug (#2762) - :doc:`Hooks Class <general/hooks>` didn't properly check if the called class/function exists.
+-  Fixed a bug (#148) - while sanitizing input data, ``CI_Input::_clean_input_data()`` assumed that it is URL-encoded, stripping certain character sequences from it.
+-  Fixed a bug (#346) - with ``$config['global_xss_filtering']`` turned on, the ``$_GET``, ``$_POST``, ``$_COOKIE`` and ``$_SERVER`` superglobals were overwritten during initialization time, resulting in XSS filtering being either performed twice or there was no possible way to get the original data, even though options for this do exist.
+-  Fixed an edge case (#555) - incorrect browser version was reported for Opera 10+ due to a non-standard user-agent string.
+-  Fixed a bug (#133) - :doc:`Text Helper <helpers/text_helper>` :func:`ascii_to_entities()` stripped the last character if it happens to be in the extended ASCII group.
+-  Fixed a bug (#2822) - ``fwrite()`` was used incorrectly throughout the whole framework, allowing incomplete writes when writing to a network stream and possibly a few other edge cases.
+-  Fixed a bug where :doc:`User Agent Library <libraries/user_agent>` methods ``accept_charset()`` and ``accept_lang()`` didn't properly parse HTTP headers that contain spaces.
+-  Fixed a bug where *default_controller* was called instad of triggering a 404 error if the current route is in a controller directory.
+-  Fixed a bug (#2737) - :doc:`XML-RPC Library <libraries/xmlrpc>` used objects as array keys, which triggered E_NOTICE messages.
+-  Fixed a bug (#2729) - ``CI_Securty::_validate_entities()`` used overly-intrusive ``preg_replace()`` patterns that produced false-positives.
 
 Version 2.1.4
 =============
@@ -751,7 +838,6 @@
    but the requested method did not.
 -  Fixed a bug (Reactor #89) where MySQL export would fail if the table
    had hyphens or other non alphanumeric/underscore characters.
--  Fixed a bug (#200) where MySQL queries would be malformed after calling $this->db->count_all() then $this->db->get()
 -  Fixed a bug (#105) that stopped query errors from being logged unless database debugging was enabled
 -  Fixed a bug (#160) - Removed unneeded array copy in the file cache
    driver.
@@ -772,7 +858,7 @@
 -  Fixed a bug (#537) - Support for all wav type in browser.
 -  Fixed a bug (#576) - Using ini_get() function to detect if apc is enabled or not.
 -  Fixed invalid date time format in :doc:`Date helper <helpers/date_helper>` and :doc:`XMLRPC library <libraries/xmlrpc>`.
--  Fixed a bug (#200) - MySQL queries would be malformed after calling count_all() then db->get().
+-  Fixed a bug (#200) - MySQL queries would be malformed after calling db->count_all() then db->get().
 
 Version 2.0.3
 =============
diff --git a/user_guide_src/source/database/helpers.rst b/user_guide_src/source/database/helpers.rst
index e8a5ac8..77bf1b5 100644
--- a/user_guide_src/source/database/helpers.rst
+++ b/user_guide_src/source/database/helpers.rst
@@ -3,7 +3,7 @@
 ######################
 
 $this->db->insert_id()
-=======================
+======================
 
 The insert ID number when performing database inserts.
 
@@ -12,7 +12,7 @@
 	appropriate sequence to check for the insert id.
 
 $this->db->affected_rows()
-===========================
+==========================
 
 Displays the number of affected rows, when doing "write" type queries
 (insert, update, etc.).
@@ -22,8 +22,8 @@
 	affected rows. By default this hack is enabled but it can be turned off
 	in the database driver file.
 
-$this->db->count_all();
-========================
+$this->db->count_all()
+======================
 
 Permits you to determine the number of rows in a particular table.
 Submit the table name in the first parameter. Example::
@@ -47,8 +47,8 @@
 
 	echo $this->db->version();
 
-$this->db->last_query();
-=========================
+$this->db->last_query()
+=======================
 
 Returns the last query that was run (the query string, not the result).
 Example::
@@ -57,11 +57,12 @@
 	
 	// Produces:  SELECT * FROM sometable....
 
-The following two functions help simplify the process of writing
-database INSERTs and UPDATEs.
 
-$this->db->insert_string();
-============================
+.. note:: Disabling the **save_queries** setting in your database
+	configuration will render this function useless.
+
+$this->db->insert_string()
+==========================
 
 This function simplifies the process of writing database inserts. It
 returns a correctly formatted SQL insert string. Example::
@@ -77,8 +78,8 @@
 
 .. note:: Values are automatically escaped, producing safer queries.
 
-$this->db->update_string();
-============================
+$this->db->update_string()
+==========================
 
 This function simplifies the process of writing database updates. It
 returns a correctly formatted SQL update string. Example::
@@ -95,4 +96,4 @@
 
 	 UPDATE table_name SET name = 'Rick', email = 'rick@example.com', url = 'example.com' WHERE author_id = 1 AND status = 'active'
 
-.. note:: Values are automatically escaped, producing safer queries.
+.. note:: Values are automatically escaped, producing safer queries.
\ No newline at end of file
diff --git a/user_guide_src/source/database/query_builder.rst b/user_guide_src/source/database/query_builder.rst
index 65609c1..5bfdfdb 100644
--- a/user_guide_src/source/database/query_builder.rst
+++ b/user_guide_src/source/database/query_builder.rst
@@ -68,7 +68,7 @@
 	// Produces string: SELECT * FROM mytable
 
 The second parameter enables you to set whether or not the query builder query
-will be reset (by default it will be&mdash;just like `$this->db->get()`)::
+will be reset (by default it will be reset, just like when using `$this->db->get()`)::
 
 	echo $this->db->limit(10,20)->get_compiled_select('mytable', FALSE);
 	// Produces string: SELECT * FROM mytable LIMIT 20, 10
@@ -76,7 +76,7 @@
 
 	echo $this->db->select('title, content, date')->get_compiled_select();
 
-	// Produces string: SELECT title, content, date FROM mytable
+	// Produces string: SELECT title, content, date FROM mytable LIMIT 20, 10
 
 The key thing to notice in the above example is that the second query did not
 utilize `$this->db->from()`_ and did not pass a table name into the first
@@ -665,10 +665,12 @@
 	// Produces string: INSERT INTO mytable (title, content) VALUES ('My Title', 'My Content')
 
 The key thing to notice in the above example is that the second query did not
-utlize `$this->db->from()`_ nor did it pass a table name into the first
+utlize `$this->db->from()` nor did it pass a table name into the first
 parameter. The reason this worked is because the query has not been executed
-using `$this->db->insert()`_ which resets values or reset directly using
-`$this->db->reset_query()`_.
+using `$this->db->insert()` which resets values or reset directly using
+`$this->db->reset_query()`.
+
+.. note:: This method doesn't work for batched inserts.
 
 $this->db->insert_batch()
 =========================
@@ -886,8 +888,9 @@
 This works exactly the same way as ``$this->db->get_compiled_insert()`` except
 that it produces an UPDATE SQL string instead of an INSERT SQL string.
 
-For more information view documentation for `$this->db->get_compiled_insert()`_.
+For more information view documentation for `$this->db->get_compiled_insert()`.
 
+.. note:: This method doesn't work for batched updates.
 
 *************
 Deleting Data
@@ -1055,4 +1058,9 @@
 	$data = $this->db->get()->result_array();
 
 	// Would execute and return an array of results of the following query:
-	// SELECT field1, field1 from mytable where field3 = 5;
\ No newline at end of file
+	// SELECT field1, field1 from mytable where field3 = 5;
+
+.. note:: Double calls to ``get_compiled_select()`` while you're using the
+	Query Builder Caching functionality and NOT resetting your queries
+	will results in the cache being merged twice. That in turn will
+	i.e. if you're caching a ``select()`` - select the same field twice.
\ No newline at end of file
diff --git a/user_guide_src/source/general/caching.rst b/user_guide_src/source/general/caching.rst
index 48385d6..f499f6e 100644
--- a/user_guide_src/source/general/caching.rst
+++ b/user_guide_src/source/general/caching.rst
@@ -45,6 +45,9 @@
 	caching will only work if you are generating display for your
 	controller with a :doc:`view <./views>`.
 
+.. important:: If you change configuration options that might affect
+	your output, you have to manually delete your cache files.
+
 .. note:: Before the cache files can be written you must set the file
 	permissions on your *application/cache/* directory such that
 	it is writable.
diff --git a/user_guide_src/source/general/cli.rst b/user_guide_src/source/general/cli.rst
index 998d2a9..4f3b07d 100644
--- a/user_guide_src/source/general/cli.rst
+++ b/user_guide_src/source/general/cli.rst
@@ -23,7 +23,7 @@
 
 -  Run your cron-jobs without needing to use *wget* or *curl*
 -  Make your cron-jobs inaccessible from being loaded in the URL by
-   checking for ``$this->input->is_cli_request()``
+   checking the return value of :func:`is_cli()`.
 -  Make interactive "tasks" that can do things like set permissions,
    prune cache folders, run backups, etc.
 -  Integrate with other applications in other languages. For example, a
@@ -33,7 +33,7 @@
 ==========================
 
 Let's create a simple controller so you can see it in action. Using your
-text editor, create a file called tools.php, and put the following code
+text editor, create a file called Tools.php, and put the following code
 in it::
 
 	<?php
diff --git a/user_guide_src/source/general/common_functions.rst b/user_guide_src/source/general/common_functions.rst
index 8c51663..65ca026 100644
--- a/user_guide_src/source/general/common_functions.rst
+++ b/user_guide_src/source/general/common_functions.rst
@@ -13,7 +13,7 @@
 
   <div class="custom-index container"></div>
 
-.. function:: is_php($version = '5.3.0')
+.. function:: is_php([$version = '5.3.0'])
 
 	:param	string	$version: Version number
 	:returns:	bool
@@ -66,7 +66,7 @@
 	to retrieve single keys. See :doc:`Config Library <../libraries/config>`
 	documentation for more information.
 
-.. :noindex: function:: show_error($message, $status_code, $heading = 'An Error Was Encountered')
+.. :noindex: function:: show_error($message, $status_code[, $heading = 'An Error Was Encountered'])
 
 	:param	mixed	$message: Error message
 	:param	int	$status_code: HTTP Response status code
@@ -76,7 +76,7 @@
 	This function calls ``CI_Exception::show_error()``. For more info,
 	please see the :doc:`Error Handling <errors>` documentation.
 
-.. :noindex: function:: show_404($page = '', $log_error = TRUE)
+.. :noindex: function:: show_404([$page = ''[, $log_error = TRUE]])
 
 	:param	string	$page: URI string
 	:param	bool	$log_error: Whether to log the error
@@ -85,17 +85,16 @@
 	This function calls ``CI_Exception::show_404()``. For more info,
 	please see the :doc:`Error Handling <errors>` documentation.
 
-.. :noindex: function:: log_message($level, $message, $php_error = FALSE)
+.. :noindex: function:: log_message($level, $message)
 
 	:param	string	$level: Log level: 'error', 'debug' or 'info'
 	:param	string	$message: Message to log
-	:param	bool	$php_error: Whether we're logging a native PHP error message
 	:returns:	void
 
 	This function is an alias for ``CI_Log::write_log()``. For more info,
 	please see the :doc:`Error Handling <errors>` documentation.
 
-.. function:: set_status_header($code, $text = '')
+.. function:: set_status_header($code[, $text = ''])
 
 	:param	int	$code: HTTP Reponse status code
 	:param	string	$text: A custom message to set with the status code
@@ -109,7 +108,7 @@
 	`See here <http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html>`_ for
 	a full list of headers.
 
-.. function:: remove_invisible_characters($str, $url_encoded = TRUE)
+.. function:: remove_invisible_characters($str[, $url_encoded = TRUE])
 
 	:param	string	$str: Input string
 	:param	bool	$url_encoded: Whether to remove URL-encoded characters as well
@@ -147,8 +146,15 @@
 	Returns TRUE if a secure (HTTPS) connection is used and FALSE
 	in any other case (including non-HTTP requests).
 
-function_usable()
-=================
+.. function:: is_cli()
+
+	:returns:	bool
+
+	Returns TRUE if the application is run through the command line
+	and FALSE if not.
+
+	.. note:: This function checks both if the ``PHP_SAPI`` value is 'cli'
+		or if the ``STDIN`` constant is defined.
 
 .. function:: function_usable($function_name)
 
diff --git a/user_guide_src/source/general/controllers.rst b/user_guide_src/source/general/controllers.rst
index 04f2327..d8ef824 100644
--- a/user_guide_src/source/general/controllers.rst
+++ b/user_guide_src/source/general/controllers.rst
@@ -18,7 +18,7 @@
 	example.com/index.php/blog/
 
 In the above example, CodeIgniter would attempt to find a controller
-named blog.php and load it.
+named Blog.php and load it.
 
 **When a controller's name matches the first segment of a URI, it will
 be loaded.**
@@ -27,7 +27,7 @@
 ==========================
 
 Let's create a simple controller so you can see it in action. Using your
-text editor, create a file called blog.php, and put the following code
+text editor, create a file called Blog.php, and put the following code
 in it::
 
 	<?php
@@ -41,6 +41,8 @@
 
 Then save the file to your *application/controllers/* directory.
 
+.. important:: The file must be called 'Blog.php', with a capital 'B'.
+
 Now visit the your site using a URL similar to this::
 
 	example.com/index.php/blog/
@@ -136,7 +138,7 @@
 To specify a default controller, open your **application/config/routes.php**
 file and set this variable::
 
-	$route['default_controller'] = 'blog';
+	$route['default_controller'] = 'Blog';
 
 Where Blog is the name of the controller class you want used. If you now
 load your main index.php file without specifying any URI segments you'll
@@ -272,7 +274,7 @@
 	specify the folder. For example, let's say you have a controller located
 	here::
 
-		application/controllers/products/shoes.php
+		application/controllers/products/Shoes.php
 
 	To call the above controller your URI will look something like this::
 
diff --git a/user_guide_src/source/general/creating_libraries.rst b/user_guide_src/source/general/creating_libraries.rst
index 4fc8ed7..4beb600 100644
--- a/user_guide_src/source/general/creating_libraries.rst
+++ b/user_guide_src/source/general/creating_libraries.rst
@@ -42,8 +42,7 @@
 The Class File
 ==============
 
-Classes should have this basic prototype (Note: We are using the name
-Someclass purely as an example)::
+Classes should have this basic prototype::
 
 	<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); 
 
@@ -56,6 +55,8 @@
 
 	/* End of file Someclass.php */
 
+.. note:: We are using the name Someclass purely as an example.
+
 Using Your Class
 ================
 
@@ -81,7 +82,7 @@
 
 	$params = array('type' => 'large', 'color' => 'red');
 
-	$this->load->library('Someclass', $params);
+	$this->load->library('someclass', $params);
 
 If you use this feature you must set up your class constructor to expect
 data::
diff --git a/user_guide_src/source/general/libraries.rst b/user_guide_src/source/general/libraries.rst
index 6e1c8b6..9bbda51 100644
--- a/user_guide_src/source/general/libraries.rst
+++ b/user_guide_src/source/general/libraries.rst
@@ -29,4 +29,4 @@
 ===========================
 
 Please read the section of the user guide that discusses how to
-:doc:`create your own libraries <creating_libraries>`.
+:doc:`create your own libraries <creating_libraries>`.
\ No newline at end of file
diff --git a/user_guide_src/source/general/models.rst b/user_guide_src/source/general/models.rst
index a028a95..c4fd124 100644
--- a/user_guide_src/source/general/models.rst
+++ b/user_guide_src/source/general/models.rst
@@ -84,8 +84,7 @@
 the first letter capitalized with the rest of the name lowercase. Make
 sure your class extends the base Model class.
 
-The file name will be a lower case version of your class name. For
-example, if your class is this::
+The file name must match the class name. For example, if this is your class::
 
 	class User_model extends CI_Model {
 
@@ -98,7 +97,7 @@
 
 Your file will be this::
 
-	application/models/user_model.php
+	application/models/User_model.php
 
 Loading a Model
 ===============
@@ -111,7 +110,7 @@
 
 If your model is located in a sub-directory, 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::
+*application/models/blog/Queries.php* you'll load it using::
 
 	$this->load->model('blog/queries');
 
@@ -181,4 +180,4 @@
 	$config['pconnect'] = FALSE;
 	$config['db_debug'] = TRUE;
 
-	$this->load->model('Model_name', '', $config);
\ No newline at end of file
+	$this->load->model('model_name', '', $config);
\ No newline at end of file
diff --git a/user_guide_src/source/general/profiling.rst b/user_guide_src/source/general/profiling.rst
index 6dbd0be..f29af81 100644
--- a/user_guide_src/source/general/profiling.rst
+++ b/user_guide_src/source/general/profiling.rst
@@ -80,4 +80,8 @@
 **session_data**        Data stored in the current session                                  TRUE
 **query_toggle_count**  The number of queries after which the query block will default to   25
                         hidden.
-======================= =================================================================== ========
\ No newline at end of file
+======================= =================================================================== ========
+
+.. note:: Disabling the **save_queries** setting in your database configuration
+	will also effectively disable profiling for database queries and render
+	the 'queries' setting above useless.
\ No newline at end of file
diff --git a/user_guide_src/source/general/routing.rst b/user_guide_src/source/general/routing.rst
index 5520f59..0b91d3f 100644
--- a/user_guide_src/source/general/routing.rst
+++ b/user_guide_src/source/general/routing.rst
@@ -142,6 +142,29 @@
 		return 'catalog/product_edit/' . strtolower($product_type) . '/' . $id;
 	};
 
+Using HTTP verbs in routes
+==========================
+
+It is possible to use HTTP verbs (request method) to define your routing rules.
+This is particularly useful when building RESTful applications. You can use standard HTTP
+verbs (GET, PUT, POST, DELETE, PATCH) or a custom one such (e.g. PURGE). HTTP verb rules
+are case-insensitive. All you need to do is to add the verb as an array key to your route.
+Example::
+
+	$route['products']['put'] = 'product/insert';
+
+In the above example, a PUT request to URI "products" would call the ``Product::insert()``
+controller method.
+
+::
+
+	$route['products/(:num)']['DELETE'] = 'product/delete/$1';
+
+A DELETE request to URL with "products" as first the segment and a number in the second will be
+mapped to the ``Product::delete()`` method, passing the numeric value as the first parameter.
+
+Using HTTP verbs is of course, optional.
+
 Reserved Routes
 ===============
 
diff --git a/user_guide_src/source/general/styleguide.rst b/user_guide_src/source/general/styleguide.rst
index 144b362..5613eab 100644
--- a/user_guide_src/source/general/styleguide.rst
+++ b/user_guide_src/source/general/styleguide.rst
@@ -71,13 +71,42 @@
 
 	echo "Here's my code!";
 
-	/* End of file myfile.php */
+	/* End of file Myfile.php */
 	/* Location: ./system/modules/mymodule/myfile.php */
 
 .. note:: There should be no empty line or newline character(s) following
 	the closing comments. If you happen to see one when
 	submitting a pull request, please check your IDE settings and fix it.
 
+File Naming
+===========
+
+Class files must be named in a Ucfirst-like manner, while any other file name
+(configurations, views, generic scripts, etc.) should be in all lowercase.
+
+**INCORRECT**::
+
+	somelibrary.php
+	someLibrary.php
+	SOMELIBRARY.php
+	Some_Library.php
+
+	Application_config.php
+	Application_Config.php
+	applicationConfig.php
+
+**CORRECT**::
+
+	Somelibrary.php
+	Some_library.php
+
+	applicationconfig.php
+	application_config.php
+
+Furthermore, class file names should match the name of the class itself.
+For example, if you have a class named `Myclass`, then its filename must
+be **Myclass.php**.
+
 Class and Method Naming
 =======================
 
diff --git a/user_guide_src/source/general/views.rst b/user_guide_src/source/general/views.rst
index 4b1ab3c..2fc0cb2 100644
--- a/user_guide_src/source/general/views.rst
+++ b/user_guide_src/source/general/views.rst
@@ -45,7 +45,7 @@
 .. note:: The .php file extension does not need to be specified
 	unless you use something other than .php.
 
-Now, open the controller file you made earlier called blog.php, and
+Now, open the controller file you made earlier called Blog.php, and
 replace the echo statement with the view loading method::
 
 	<?php
diff --git a/user_guide_src/source/helpers/form_helper.rst b/user_guide_src/source/helpers/form_helper.rst
index 8ad8f7d..dcb5bee 100644
--- a/user_guide_src/source/helpers/form_helper.rst
+++ b/user_guide_src/source/helpers/form_helper.rst
@@ -28,7 +28,7 @@
 .. function:: form_open([$action = ''[, $attributes = ''[, $hidden = array()]]])
 
 	:param	string	$action: Form action/target URI string
-	:param	string	$attributes: HTML attributes
+	:param	array	$attributes: HTML attributes
 	:param	array	$hidden: An array of hidden fields' definitions
 	:returns:	string
 
@@ -85,7 +85,7 @@
 .. function:: form_open_multipart([$action = ''[, $attributes = array()[, $hidden = array()]])
 
 	:param	string	$action: Form action/target URI string
-	:param	string	$attributes: HTML attributes
+	:param	array	$attributes: HTML attributes
 	:param	array	$hidden: An array of hidden fields' definitions
 	:returns:	string
 
diff --git a/user_guide_src/source/helpers/smiley_helper.rst b/user_guide_src/source/helpers/smiley_helper.rst
index 0601f02..077c56a 100644
--- a/user_guide_src/source/helpers/smiley_helper.rst
+++ b/user_guide_src/source/helpers/smiley_helper.rst
@@ -158,8 +158,7 @@
 	Example::
 
 		$str = 'Here are some smileys: :-)  ;-)';
-		$str = parse_smileys($str, "http://example.com/images/smileys/");
+		$str = parse_smileys($str, 'http://example.com/images/smileys/');
 		echo $str;
 
-
 .. |smile!| image:: ../images/smile.gif
\ No newline at end of file
diff --git a/user_guide_src/source/installation/downloads.rst b/user_guide_src/source/installation/downloads.rst
index 8d47ba3..93c5cc2 100644
--- a/user_guide_src/source/installation/downloads.rst
+++ b/user_guide_src/source/installation/downloads.rst
@@ -3,35 +3,37 @@
 #######################
 
 -  `CodeIgniter v3.0.0 (Current version) <http://ellislab.com/codeigniter/download>`_
--  `CodeIgniter v2.1.4 <http://ellislab.com/asset/ci_download_files/CodeIgniter_2.1.4.zip>`_
--  `CodeIgniter v2.1.3 <http://ellislab.com/asset/ci_download_files/CodeIgniter_2.1.3.zip>`_
--  `CodeIgniter v2.1.2 <http://ellislab.com/asset/ci_download_files/CodeIgniter_2.1.2.zip>`_
--  `CodeIgniter v2.1.1 <http://ellislab.com/asset/ci_download_files/CodeIgniter_2.1.1.zip>`_
--  `CodeIgniter v2.1.0 <http://ellislab.com/asset/ci_download_files/CodeIgniter_2.1.0.zip>`_
--  `CodeIgniter v2.0.3 <http://ellislab.com/asset/ci_download_files/CodeIgniter_2.0.3.zip>`_
--  `CodeIgniter v2.0.2 <http://ellislab.com/asset/ci_download_files/CodeIgniter_2.0.2.zip>`_
--  `CodeIgniter v2.0.1 <http://ellislab.com/asset/ci_download_files/CodeIgniter_2.0.1.zip>`_
--  `CodeIgniter v2.0.0 <http://ellislab.com/asset/ci_download_files/CodeIgniter_2.0.0.zip>`_
--  `CodeIgniter v1.7.3 <http://ellislab.com/asset/ci_download_files/CodeIgniter_1.7.3.zip>`_
--  `CodeIgniter v1.7.2 <http://ellislab.com/asset/ci_download_files/CodeIgniter_1.7.2.zip>`_
--  `CodeIgniter v1.7.1 <http://ellislab.com/asset/ci_download_files/CodeIgniter_1.7.1.zip>`_
--  `CodeIgniter v1.7.0 <http://ellislab.com/asset/ci_download_files/CodeIgniter_1.7.0.zip>`_
--  `CodeIgniter v1.6.3 <http://ellislab.com/asset/ci_download_files/CodeIgniter_1.6.3.zip>`_
--  `CodeIgniter v1.6.2 <http://ellislab.com/asset/ci_download_files/CodeIgniter_1.6.2.zip>`_
--  `CodeIgniter v1.6.1 <http://ellislab.com/asset/ci_download_files/CodeIgniter_1.6.1.zip>`_
--  `CodeIgniter v1.6.0 <http://ellislab.com/asset/ci_download_files/CodeIgniter_1.6.0.zip>`_
--  `CodeIgniter v1.5.4 <http://ellislab.com/asset/ci_download_files/CodeIgniter_1.5.4.zip>`_
--  `CodeIgniter v1.5.3 <http://ellislab.com/asset/ci_download_files/CodeIgniter_1.5.3.zip>`_
--  `CodeIgniter v1.5.2 <http://ellislab.com/asset/ci_download_files/CodeIgniter_1.5.2.zip>`_
--  `CodeIgniter v1.5.1 <http://ellislab.com/asset/ci_download_files/CodeIgniter_1.5.1.zip>`_
--  `CodeIgniter v1.4.1 <http://ellislab.com/asset/ci_download_files/CodeIgniter_1.4.1.zip>`_
--  `CodeIgniter v1.3.3 <http://ellislab.com/asset/ci_download_files/CodeIgniter_1.3.3.zip>`_
--  `CodeIgniter v1.3.2 <http://ellislab.com/asset/ci_download_files/CodeIgniter_1.3.2.zip>`_
--  `CodeIgniter v1.3.1 <http://ellislab.com/asset/ci_download_files/CodeIgniter_1.3.1.zip>`_
--  `CodeIgniter v1.3 <http://ellislab.com/asset/ci_download_files/CodeIgniter_1.3.zip>`_
--  `CodeIgniter v1.2 <http://ellislab.com/asset/ci_download_files/CodeIgniter_1.2.zip>`_
--  `CodeIgniter v1.1 <http://ellislab.com/asset/ci_download_files/CodeIgniter_1.1b.zip>`_
--  `CodeIgniter v1.0 <http://ellislab.com/asset/ci_download_files/CodeIgniter_1.0b.zip>`_
+-  `CodeIgniter v2.1.4 <http://ellislab.com/asset/ci_download_files/CodeIgniter_2.1.4.zip>`_ (MD5 Checksum: e74a296c1d412a855c025b9cd468a513)
+-  `CodeIgniter v2.1.3 <http://ellislab.com/asset/ci_download_files/CodeIgniter_2.1.3.zip>`_ (MD5 Checksum: 781d06be06eaa36f10759ef82c8594d5)
+-  `CodeIgniter v2.1.2 <http://ellislab.com/asset/ci_download_files/CodeIgniter_2.1.2.zip>`_ (MD5 Checksum: c7a2980dff2774c97bd38bfbf450d8d5)
+-  `CodeIgniter v2.1.1 <http://ellislab.com/asset/ci_download_files/CodeIgniter_2.1.1.zip>`_ (MD5 Checksum: c4aa5f188f4ff16f919607b46a16c76c)
+-  `CodeIgniter v2.1.0 <http://ellislab.com/asset/ci_download_files/CodeIgniter_2.1.0.zip>`_ (MD5 Checksum: 8cb676b0f831114935d7dd1ae2e0d490)
+-  `CodeIgniter v2.0.3 <http://ellislab.com/asset/ci_download_files/CodeIgniter_2.0.3.zip>`_ (MD5 Checksum: 910475d50daf088bdd949c3d35b444d9)
+-  `CodeIgniter v2.0.2 <http://ellislab.com/asset/ci_download_files/CodeIgniter_2.0.2.zip>`_ (MD5 Checksum: e75bab8cf27d2fb2483c5bb61b85a524)
+-  `CodeIgniter v2.0.1 <http://ellislab.com/asset/ci_download_files/CodeIgniter_2.0.1.zip>`_ (MD5 Checksum: 675aa95896bfb16467436c0484f15f1f)
+-  `CodeIgniter v2.0.0 <http://ellislab.com/asset/ci_download_files/CodeIgniter_2.0.0.zip>`_ (MD5 Checksum: bd657863de45dbb397f3b3dbc4f13abb)
+-  `CodeIgniter v1.7.3 <http://ellislab.com/asset/ci_download_files/CodeIgniter_1.7.3.zip>`_ (MD5 Checksum: 16f50e7df4f44c1defe18355131049e9)
+-  `CodeIgniter v1.7.2 <http://ellislab.com/asset/ci_download_files/CodeIgniter_1.7.2.zip>`_ (MD5 Checksum: ff2f4d1b3ab921f91e006f38b3ae6540)
+-  `CodeIgniter v1.7.1 <http://ellislab.com/asset/ci_download_files/CodeIgniter_1.7.1.zip>`_ (MD5 Checksum: deca9709cf21b26dc0e4ec040b37e866)
+-  `CodeIgniter v1.7.0 <http://ellislab.com/asset/ci_download_files/CodeIgniter_1.7.0.zip>`_ (MD5 Checksum: 28037f2071f940d8756864460d949045)
+-  `CodeIgniter v1.6.3 <http://ellislab.com/asset/ci_download_files/CodeIgniter_1.6.3.zip>`_ (MD5 Checksum: 5ffab52b39b235ed6bd08ee5dd64d2f6)
+-  `CodeIgniter v1.6.2 <http://ellislab.com/asset/ci_download_files/CodeIgniter_1.6.2.zip>`_ (MD5 Checksum: 0922830f96dfd40874b39ad018a49206)
+-  `CodeIgniter v1.6.1 <http://ellislab.com/asset/ci_download_files/CodeIgniter_1.6.1.zip>`_ (MD5 Checksum: cc3f0b566e3654d351fa067aeee9bced)
+-  `CodeIgniter v1.6.0 <http://ellislab.com/asset/ci_download_files/CodeIgniter_1.6.0.zip>`_ (MD5 Checksum: 89efabb8c1d57bb51071e6a20bb5590d)
+-  `CodeIgniter v1.5.4 <http://ellislab.com/asset/ci_download_files/CodeIgniter_1.5.4.zip>`_ (MD5 Checksum: 0d6cc66b01d5ddecde483b3d5f51e4f8)
+-  `CodeIgniter v1.5.3 <http://ellislab.com/asset/ci_download_files/CodeIgniter_1.5.3.zip>`_ (MD5 Checksum: f44dd21d34a2842bd052879ca5de6630)
+-  `CodeIgniter v1.5.2 <http://ellislab.com/asset/ci_download_files/CodeIgniter_1.5.2.zip>`_ (MD5 Checksum: 78e7106b271f75af48e626f6e923c1aa)
+-  `CodeIgniter v1.5.1 <http://ellislab.com/asset/ci_download_files/CodeIgniter_1.5.1.zip>`_ (MD5 Checksum: 9dfd0dbed4f283a42a817e1e88f97481)
+-  `CodeIgniter v1.5.0 <http://ellislab.com/asset/ci_download_files/CodeIgniter_1.5.0.zip>`_ (MD5 Checksum: 116b805eae4b7e78ddd43a8aee733632)
+-  `CodeIgniter v1.4.1 <http://ellislab.com/asset/ci_download_files/CodeIgniter_1.4.1.zip>`_ (MD5 Checksum: 470005a83772e9d2e99dec2b4058e584)
+-  `CodeIgniter v1.4.0 <http://ellislab.com/asset/ci_download_files/CodeIgniter_1.4.0.zip>`_ (MD5 Checksum: 43ca6ff3447d6b5681f98a328b386338)
+-  `CodeIgniter v1.3.3 <http://ellislab.com/asset/ci_download_files/CodeIgniter_1.3.3.zip>`_ (MD5 Checksum: 55692ba4b55b53b58e4514e310288981)
+-  `CodeIgniter v1.3.2 <http://ellislab.com/asset/ci_download_files/CodeIgniter_1.3.2.zip>`_ (MD5 Checksum: 7dace6e1d6245b569943e8df952c7637)
+-  `CodeIgniter v1.3.1 <http://ellislab.com/asset/ci_download_files/CodeIgniter_1.3.1.zip>`_ (MD5 Checksum: f6c6f00830c60d7f98b948269ee81069)
+-  `CodeIgniter v1.3 <http://ellislab.com/asset/ci_download_files/CodeIgniter_1.3.zip>`_ (MD5 Checksum: 03b2f796df6af808ecff3a18b6000477)
+-  `CodeIgniter v1.2 <http://ellislab.com/asset/ci_download_files/CodeIgniter_1.2.zip>`_ (MD5 Checksum: f9289814fabe102bc35beb791d0c0f62)
+-  `CodeIgniter v1.1 <http://ellislab.com/asset/ci_download_files/CodeIgniter_1.1b.zip>`_ (MD5 Checksum: bf4cabb6a3ea3122a974270b8044befb)
+-  `CodeIgniter v1.0 <http://ellislab.com/asset/ci_download_files/CodeIgniter_1.0b.zip>`_ (MD5 Checksum: 427ca4255e2bdaacee976de1aa143ea0)
 
 
 ******
diff --git a/user_guide_src/source/installation/upgrade_300.rst b/user_guide_src/source/installation/upgrade_300.rst
index b36a70c..c11db34 100644
--- a/user_guide_src/source/installation/upgrade_300.rst
+++ b/user_guide_src/source/installation/upgrade_300.rst
@@ -17,22 +17,63 @@
 .. note:: If you have any custom developed files in these folders please
 	make copies of them first.
 
+**************************************
+Step 2: Update your classes file names
+**************************************
+
+Starting with CodeIgniter 3.0, all class filenames (libraries, drivers, controllers
+and models) must be named in a Ucfirst-like manner or in other words - they must
+start with a capital letter.
+
+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
+
+Controllers:
+
+	application/controllers/welcome.php	->	application/controllers/Welcome.php
+
+Models:
+
+	application/models/misc_model.php	->	application/models/Misc_model.php
+
+Please note that this DOES NOT affect directories, configuration files, views,
+helpers, hooks and anything else - it is only applied to classes.
+
+You must now follow just one simple rule - class names in Ucfirst and everything else
+in lowercase.
+
 ********************************
-Step 2: Replace config/mimes.php
+Step 3: Replace config/mimes.php
 ********************************
 
 This config file has been updated to contain more user mime-types, please copy
 it to _application/config/mimes.php*.
 
 **************************************************************
-Step 3: Remove $autoload['core'] from your config/autoload.php
+Step 4: Remove $autoload['core'] from your config/autoload.php
 **************************************************************
 
 Use of the ``$autoload['core']`` config array has been deprecated as of CodeIgniter 1.4.1 and is now removed.
 Move any entries that you might have listed there to ``$autoload['libraries']`` instead.
 
 ***************************************************
-Step 4: Move your Log class overrides or extensions
+Step 5: Move your Log class overrides or extensions
 ***************************************************
 
 The Log Class is considered as a "core" class and is now located in the
@@ -40,10 +81,10 @@
 or extensions to work, you need to move them to **application/core/**::
 
 	application/libraries/Log.php -> application/core/Log.php
-	application/libraries/MY_Log.php -> application/core/MY_log.php
+	application/libraries/MY_Log.php -> application/core/MY_Log.php
 
 *********************************************************
-Step 5: Convert your Session usage from library to driver
+Step 6: Convert your Session usage from library to driver
 *********************************************************
 
 When you load (or autoload) the Session library, you must now load it as a driver instead of a library. This means
@@ -67,7 +108,7 @@
 the drivers, so your extension may have to be broken down into separate library and driver class extensions.
 
 ***************************************
-Step 6: Update your config/database.php
+Step 7: Update your config/database.php
 ***************************************
 
 Due to 3.0.0's renaming of Active Record to Query Builder, inside your `config/database.php`, you will
@@ -78,14 +119,21 @@
 	// $active_record = TRUE;
 	$query_builder = TRUE;
 
-*******************************
-Step 7: Move your errors folder
-*******************************
+************************************
+Step 8: Replace your error templates
+************************************
 
-In version 3.0.0, the errors folder has been moved from _application/errors* to _application/views/errors*.
+In CodeIgniter 3.0, the error templates are now considered as views and have been moved to the
+_application/views/errors* directory.
+
+Furthermore, we've added support for CLI error templates in plain-text format that unlike HTML,
+is suitable for the command line. This of course requires another level of separation.
+
+It is safe to move your old templates from _application/errors* to _application/views/errors/html*,
+but you'll have to copy the new _application/views/errors/cli* directory from the CodeIgniter archive.
 
 *******************************************************
-Step 8: Update your config/routes.php containing (:any)
+Step 9: Update your config/routes.php containing (:any)
 *******************************************************
 
 Historically, CodeIgniter has always provided the **:any** wildcard in routing,
@@ -104,47 +152,93 @@
 	(.+)	// matches ANYTHING
 	(:any)	// matches any character, except for '/'
 
-*****************************************
-Step 9: Update your libraries' file names
-*****************************************
+*************************************************************************
+Step 10: Many functions now return NULL instead of FALSE on missing items
+*************************************************************************
 
-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:
+Many methods and functions now return NULL instead of FALSE when the required items don't exist:
 
-	application/libraries/mylibrary.php
+ - :doc:`Config Class <../libraries/config>`
 
-... then you'll have to rename it to:
+   - config->item()
+   - config->slash_item()
 
-	application/libraries/Mylibrary.php
+ - :doc:`Input Class <../libraries/input>`
 
-The same goes for driver libraries and extensions and/or overrides of CodeIgniter's
-own libraries and core classes.
+   - input->get()
+   - input->post()
+   - input->get_post()
+   - input->cookie()
+   - input->server()
+   - input->input_stream()
+   - input->get_request_header()
 
-	application/libraries/MY_email.php
-	application/core/MY_log.php
+ - :doc:`Session Class <../libraries/sessions>`
 
-The above files should respectively be renamed to the following:
+   - session->userdata()
+   - session->flashdata()
 
-	application/libraries/MY_Email.php
-	application/core/MY_Log.php
+ - :doc:`URI Class <../libraries/uri>`
 
-*****************************************************************************
-Step 10: Check the calls to Array Helper's element() and elements() functions
-*****************************************************************************
+   - uri->segment()
+   - uri->rsegment()
 
-The default return value of these functions, when the required elements
-don't exist, has been changed from FALSE to NULL.
+ - :doc:`Array Helper <../helpers/array_helper>`
+
+   - element()
+   - elements()
+
+*******************************
+Step 11: Usage of XSS filtering
+*******************************
+
+Many functions in CodeIgniter allow you to use its XSS filtering feature
+on demand by passing a boolean parameter. The default value of that
+parameter used to be boolean FALSE, but it is now changed to NULL and it
+will be dynamically determined by your ``$config['global_xss_filtering']``
+value.
+
+If you used to manually pass a boolean value for the ``$xss_filter``
+parameter or if you've always had ``$config['global_xss_filtering']`` set
+to FALSE, then this change doesn't concern you.
+
+Otherwise however, please review your usage of the following functions:
+
+ - :doc:`Input Library <../libraries/input>`
+
+   - input->get()
+   - input->post()
+   - input->get_post()
+   - input->cookie()
+   - input->server()
+   - input->input_stream()
+
+ - :doc:`Cookie Helper <../helpers/cookie_helper>` :func:`get_cookie()`
+
+.. important:: Another related change is that the ``$_GET``, ``$_POST``,
+	``$_COOKIE`` and ``$_SERVER`` superglobals are no longer
+	automatically overwritten when global XSS filtering is turned on.
+
+********************************************************
+Step 12: Update usage of Input Class's get_post() method
+********************************************************
+
+Previously, the :doc:`Input Class <../libraries/input>` method ``get_post()``
+was searching first in POST data, then in GET data. This method has been
+modified so that it searches in GET then in POST, as its name suggests.
+
+A method has been added, ``post_get()``, which searches in POST then in GET, as
+``get_post()`` was doing before.
 
 ***********************************************************************
-Step 11: Check the calls to Directory Helper's directory_map() function
+Step 13: Update usage of Directory Helper's directory_map() function
 ***********************************************************************
 
 In the resulting array, directories now end with a trailing directory
 separator (i.e. a slash, usually).
 
 *************************************************************
-Step 12: Update usage of Database Forge's drop_table() method
+Step 14: 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
@@ -166,7 +260,7 @@
 	all drivers with the exception of ODBC.
 
 ***********************************************************
-Step 13: Change usage of Email library with multiple emails
+Step 15: Change usage of Email library with multiple emails
 ***********************************************************
 
 The :doc:`Email Library <../libraries/email>` will automatically clear the
@@ -181,7 +275,7 @@
  	}
 
 ***************************************************
-Step 14: Update your Form_validation language lines
+Step 16: Update your Form_validation language lines
 ***************************************************
 
 Two improvements have been made to the :doc:`Form Validation Library
@@ -212,7 +306,7 @@
 	later.
 
 ****************************************************************
-Step 15: Remove usage of (previously) deprecated functionalities
+Step 17: Remove usage of (previously) deprecated functionalities
 ****************************************************************
 
 In addition to the ``$autoload['core']`` configuration setting, there's a
@@ -239,6 +333,26 @@
 :doc:`Smiley Helper <../helpers/smiley_helper>` function ``js_insert_smiley()`` has been deprecated
 since CodeIgniter 1.7.2 and is now removed. You'll need to switch to ``smiley_js()`` instead.
 
+Database drivers 'mysql', 'sqlite', 'mssql', 'pdo/dblib'
+========================================================
+
+The **mysql** driver utilizes the old 'mysql' PHP extension, known for its aging code base and
+many low-level problems. The extension is deprecated as of PHP 5.5 and CodeIgniter deprecates
+it in version 3.0, switching the default configured MySQL driver to **mysqli**.
+
+Please use either the 'mysqli' or 'pdo/mysql' drivers for MySQL. The old 'mysql' driver will be
+removed at some point in the future.
+
+The **sqlite**, **mssql** and **pdo/dblib** (also known as pdo/mssql or pdo/sybase) drivers
+all depend on PHP extensions that for different reasons no longer exist since PHP 5.3.
+
+Therefore we are now deprecating these drivers as we will have to remove them in one of the next
+CodeIgniter versions. You should use the more advanced, **sqlite3**, **sqlsrv** or **pdo/sqlsrv**
+drivers respectively.
+
+.. note:: These drivers are still available, but you're strongly encouraged to switch to other ones
+	sooner rather than later.
+
 Security helper do_hash()
 =========================
 
@@ -401,4 +515,46 @@
 	$this->router->method;
 
 .. note:: Those methods are still available, but you're strongly encouraged to remove their usage
-	sooner rather than later.
\ No newline at end of file
+	sooner rather than later.
+
+Input library method is_cli_request()
+=====================================
+
+Calls to the ``CI_Input::is_cli_request()`` method are necessary at many places
+in the CodeIgniter internals and this is often before the :doc:`Input Library
+<../libraries/input>` is loaded. Because of that, it is being replaced by a common
+function named :php:func:`is_cli()` and this method is now just an alias.
+
+The new function is both available at all times for you to use and shorter to type.
+
+::
+
+	// Old
+	$this->input->is_cli_request();
+
+	// New
+	is_cli();
+
+``CI_Input::is_cli_request()`` is now now deprecated and scheduled for removal in
+CodeIgniter 3.1+.
+
+.. note:: This method is still available, but you're strongly encouraged to remove its usage
+	sooner rather than later.
+
+***********************************************************
+Step 18: Check your usage of Text helper highlight_phrase()
+***********************************************************
+
+The default HTML tag used by :doc:`Text Helper <../helpers/text_helper>` function
+:func:`highlight_phrase()` has been changed from ``<strong>`` to the new HTML5
+tag ``<mark>``.
+
+Unless you've used your own highlighting tags, this might cause trouble
+for your visitors who use older web browsers such as Internet Explorer 8.
+We therefore suggest that you add the following code to your CSS files
+in order to avoid backwards compatibility with old browsers::
+
+	mark {
+		background: #ff0;
+		color: #000;
+	};
diff --git a/user_guide_src/source/libraries/caching.rst b/user_guide_src/source/libraries/caching.rst
index 5a97423..30a9fed 100644
--- a/user_guide_src/source/libraries/caching.rst
+++ b/user_guide_src/source/libraries/caching.rst
@@ -240,17 +240,28 @@
 Redis Caching
 =============
 
+Redis is an in-memory key-value store which can operate in LRU cache mode. 
+To use it, you need Redis server and phpredis PHP extension 
+`https://github.com/nicolasff/phpredis <https://github.com/nicolasff/phpredis>`_.
+
+Config options to connect to redis server must be stored in the application/config/redis.php file.
+Available options are::
+	
+	$config['socket_type'] = 'tcp'; //`tcp` or `unix`
+	$config['socket'] = '/var/run/redis.sock'; // in case of `unix` socket type
+	$config['host'] = '127.0.0.1';
+	$config['password'] = NULL;
+	$config['port'] = 6379;
+	$config['timeout'] = 0;
+
 All of the methods listed above can be accessed without passing a
 specific adapter to the driver loader as follows::
 
 	$this->load->driver('cache');
 	$this->cache->redis->save('foo', 'bar', 10);
 
-.. important:: Redis may require one or more of the following options:
-	**host**, **post**, **timeout**, **password**.
-
-The Redis PHP extension repository is located at
-`https://github.com/nicolasff/phpredis <https://github.com/nicolasff/phpredis>`_.
+For more information on Redis, please see
+`http://redis.io <http://redis.io>`_.
 
 Dummy Cache
 ===========
diff --git a/user_guide_src/source/libraries/calendar.rst b/user_guide_src/source/libraries/calendar.rst
index d9a336d..3879672 100644
--- a/user_guide_src/source/libraries/calendar.rst
+++ b/user_guide_src/source/libraries/calendar.rst
@@ -97,21 +97,23 @@
 month heading, and the "short" day names. More information regarding
 preferences below.
 
-======================  ===========  ===============================================  ===================================================================
-Preference              Default		Options						Description
-======================  ===========  ===============================================  ===================================================================
-**template**           	None		None                                         	A string containing your calendar template.
-											See the template section below.
-**local_time**        	time()		None						A Unix timestamp corresponding to the current time.
-**start_day**         	sunday		Any week day (sunday, monday, tuesday, etc.) 	Sets the day of the week the calendar should start on.
-**month_type**        	long          	long, short                                   	Determines what version of the month name to use in the header.
-											long = January, short = Jan.
-**day_type**		abr		long, short, abr 				Determines what version of the weekday names to use in
-											the column headers. long = Sunday, short = Sun, abr = Su.
-**show_next_prev**	FALSE		TRUE/FALSE (boolean)				Determines whether to display links allowing you to toggle
-											to next/previous months. See information on this feature below.
-**next_prev_url**     	None     	  A URL						Sets the basepath used in the next/previous calendar links.
-======================  ===========  ===============================================  ===================================================================
+======================  =================  ============================================  ===================================================================
+Preference              Default            Options                                       Description
+======================  =================  ============================================  ===================================================================
+**template**           	None               None                                          A string containing your calendar template.
+											   See the template section below.
+**local_time**        	time()             None                                          A Unix timestamp corresponding to the current time.
+**start_day**           sunday             Any week day (sunday, monday, tuesday, etc.)  Sets the day of the week the calendar should start on.
+**month_type**          long               long, short                                   Determines what version of the month name to use in the header.
+											   long = January, short = Jan.
+**day_type**            abr                long, short, abr                              Determines what version of the weekday names to use in
+											   the column headers. long = Sunday, short = Sun, abr = Su.
+**show_next_prev**      FALSE              TRUE/FALSE (boolean)                          Determines whether to display links allowing you to toggle
+											   to next/previous months. See information on this feature below.
+**next_prev_url**       controller/method  A URL                                         Sets the basepath used in the next/previous calendar links.
+**show_other_days**     FALSE              TRUE/FALSE (boolean)                          Determines whether to display days of other months that share the
+											   first or last week of the calendar month.
+======================  =================  ============================================  ===================================================================
 
 
 Showing Next/Previous Month Links
@@ -134,7 +136,8 @@
 
 -  You must set the "show_next_prev" to TRUE.
 -  You must supply the URL to the controller containing your calendar in
-   the "next_prev_url" preference.
+   the "next_prev_url" preference. If you don't, it will be set to the current
+   *controller/method*.
 -  You must supply the "year" and "month" to the calendar generating
    function via the URI segments where they appear (Note: The calendar
    class automatically adds the year/month to the base URL you
@@ -165,6 +168,8 @@
 
 	   {cal_row_start}<tr>{/cal_row_start}
 	   {cal_cell_start}<td>{/cal_cell_start}
+	   {cal_cell_start_today}<td>{/cal_cell_start_today}
+	   {cal_cell_start_other}<td class="other-month">{/cal_cell_start_other}
 
 	   {cal_cell_content}<a href="{content}">{day}</a>{/cal_cell_content}
 	   {cal_cell_content_today}<div class="highlight"><a href="{content}">{day}</a></div>{/cal_cell_content_today}
@@ -174,7 +179,11 @@
 
 	   {cal_cell_blank}&nbsp;{/cal_cell_blank}
 
+	   {cal_cell_other}{day}{cal_cel_other}
+
 	   {cal_cell_end}</td>{/cal_cell_end}
+	   {cal_cell_end_today}</td>{/cal_cell_end_today}
+	   {cal_cell_end_other}</td>{/cal_cell_end_other}
 	   {cal_row_end}</tr>{/cal_row_end}
 
 	   {table_close}</table>{/table_close}
diff --git a/user_guide_src/source/libraries/config.rst b/user_guide_src/source/libraries/config.rst
index 54aa70b..8663324 100644
--- a/user_guide_src/source/libraries/config.rst
+++ b/user_guide_src/source/libraries/config.rst
@@ -99,7 +99,7 @@
 
 	$lang = $this->config->item('language');
 
-The function returns FALSE (boolean) if the item you are trying to fetch
+The function returns NULL if the item you are trying to fetch
 does not exist.
 
 If you are using the second parameter of the $this->config->load
diff --git a/user_guide_src/source/libraries/email.rst b/user_guide_src/source/libraries/email.rst
index 1d9d2c1..ec63984 100644
--- a/user_guide_src/source/libraries/email.rst
+++ b/user_guide_src/source/libraries/email.rst
@@ -254,7 +254,6 @@
 		message CodeIgniter will extract the message from your HTML email
 		and strip the tags.
 
-
 	.. method:: set_header($header, $value)
 
 		:param string $header: header name
@@ -330,8 +329,8 @@
 		:returns: CI_Email object for method chaining
 
 		Enables you to send an attachment. Put the file path/name in the first
-		parameter. Note: Use a file path, not a URL. For multiple attachments
-		use the method multiple times. For example::
+		parameter. For multiple attachments use the method multiple times.
+		For example::
 
 			$this->email->attach('/path/to/photo1.jpg');
 			$this->email->attach('/path/to/photo2.jpg');
@@ -342,6 +341,10 @@
 
 			$this->email->attach('image.jpg', 'inline');
 
+		You can also use a URL::
+
+			$this->email->attach('http://example.com/filename.pdf');
+
 		If you'd like to use a custom file name, you can use the third paramater::
 
 			$this->email->attach('filename.pdf', 'attachment', 'report.pdf');
@@ -352,6 +355,26 @@
 
 			$this->email->attach($buffer, 'attachment', 'report.pdf', 'application/pdf');
 
+	.. method:: attachment_cid($filename)
+
+		:param string $filename: Existing attachment filename
+		:returns: string
+ 
+		Sets and returns an attachment's Content-ID, which enables your to embed an inline
+		(picture) attachment into HTML. First parameter must be the already attached file name.
+		::
+ 
+			$filename = '/img/photo1.jpg';
+			$this->email->attach($filename);
+			foreach ($list as $address)
+			{
+				$this->email->to($address);
+				$cid = $this->email->attach_cid($filename);
+				$this->email->message('<img src='cid:". $cid ."' alt="photo1" />');
+				$this->email->send();
+			}
+
+		.. note:: Content-ID for each e-mail must be re-created for it to be unique.
 
 	.. method:: print_debugger([$include = array('headers', 'subject', 'body')])
 
diff --git a/user_guide_src/source/libraries/file_uploading.rst b/user_guide_src/source/libraries/file_uploading.rst
index 695998d..d679d8a 100644
--- a/user_guide_src/source/libraries/file_uploading.rst
+++ b/user_guide_src/source/libraries/file_uploading.rst
@@ -90,7 +90,7 @@
 The Controller
 ==============
 
-Using a text editor, create a controller called upload.php. In it, place
+Using a text editor, create a controller called Upload.php. In it, place
 this code and save it to your **application/controllers/** directory::
 
 	<?php
@@ -231,6 +231,11 @@
 **detect_mime**              TRUE              TRUE/FALSE (boolean)    If set to TRUE, a server side detection of the file type will be
                                                                        performed to avoid code injection attacks. DO NOT disable this option
                                                                        unless you have no other option as that would cause a security risk.
+**mod_mime_fix**             TRUE              TRUE/FALSE (boolean)    If set to TRUE, multiple filename extensions will be suffixed with an
+                                                                       underscore in order to avoid triggering `Apache mod_mime
+                                                                       <http://httpd.apache.org/docs/2.0/mod/mod_mime.html#multipleext>`_.
+                                                                       DO NOT turn off this option if your upload directory is public, as this
+                                                                       is a security risk.
 ============================ ================= ======================= ======================================================================
 
 Setting preferences in a config file
@@ -340,4 +345,4 @@
 			image_height			Image height
 			image_type				Image type. Typically the file extension without the period.
 			image_size_str		A string containing the width and height. Useful to put into an image tag.
-			================	================================================
\ No newline at end of file
+			================	================================================
diff --git a/user_guide_src/source/libraries/form_validation.rst b/user_guide_src/source/libraries/form_validation.rst
index 35f745f..42422f9 100644
--- a/user_guide_src/source/libraries/form_validation.rst
+++ b/user_guide_src/source/libraries/form_validation.rst
@@ -200,6 +200,7 @@
    message. For example, if your field is named "user" you might give it
    a human name of "Username".
 #. The validation rules for this form field.
+#. (optional) Set custom error messages on any rules given for current field. If not provided will use the default one.
 
 .. note:: If you would like the field name to be stored in a language
 	file, please see :ref:`translating-field-names`.
@@ -225,7 +226,9 @@
 			$this->load->library('form_validation');
 
 			$this->form_validation->set_rules('username', 'Username', 'required');
-			$this->form_validation->set_rules('password', 'Password', 'required');
+			$this->form_validation->set_rules('password', 'Password', 'required',
+				array('required' => 'You must provide a %s.')
+			);
 			$this->form_validation->set_rules('passconf', 'Password Confirmation', 'required');
 			$this->form_validation->set_rules('email', 'Email', 'required');
 
@@ -263,7 +266,10 @@
 		array(
 			'field' => 'password',
 			'label' => 'Password',
-			'rules' => 'required'
+			'rules' => 'required',
+			'errors' => array(
+				'required' => 'You must provide a %s.',
+			),
 		),
 		array(
 			'field' => 'passconf',
@@ -285,7 +291,14 @@
 CodeIgniter lets you pipe multiple rules together. Let's try it. Change
 your rules in the third parameter of rule setting method, like this::
 
-	$this->form_validation->set_rules('username', 'Username', 'required|min_length[5]|max_length[12]|is_unique[users.username]');
+	$this->form_validation->set_rules(
+		'username', 'Username',
+		'required|min_length[5]|max_length[12]|is_unique[users.username]',
+		array(
+			'required'	=> 'You have not provided %s.',
+			'is_unique'	=> 'This %s already exists.'
+		)
+	);
 	$this->form_validation->set_rules('password', 'Password', 'required');
 	$this->form_validation->set_rules('passconf', 'Password Confirmation', 'required|matches[password]');
 	$this->form_validation->set_rules('email', 'Email', 'required|valid_email|is_unique[users.email]');
@@ -431,7 +444,7 @@
 			}
 		}
 
-		protected function username_check($str)
+		public function username_check($str)
 		{
 			if ($str == 'test')
 			{
@@ -469,11 +482,18 @@
 All of the native error messages are located in the following language
 file: **system/language/english/form_validation_lang.php**
 
-To set your own custom message you can either edit that file, or use the
-following method::
+To set your own global custom message for a rule, you can either 
+edit that file, or use the following method::
 
 	$this->form_validation->set_message('rule', 'Error Message');
 
+If you need to set a custom error message for a particular field on 
+some particular rule, use the set_rules() method::
+
+	$this->form_validation->set_rules('field_name', 'Field Label', 'rule1|rule2|rule3',
+		array('rule2'	=> 'Error Message on rule2 for this field_name')
+	);
+
 Where rule corresponds to the name of a particular rule, and Error
 Message is the text you would like displayed.
 
@@ -866,7 +886,8 @@
 **is_unique**             Yes        Returns FALSE if the form element is not unique to the table and field name in the            is_unique[table.field]
                                      parameter. Note: This rule requires :doc:`Query Builder <../database/query_builder>` to be
                                      enabled in order to work.
-**max_length**            Yes        Returns FALSE if the form element is longer then the parameter value.                         max_length[12]
+**min_length**            Yes        Returns FALSE if the form element is shorter than the parameter value.                        min_length[3]
+**max_length**            Yes        Returns FALSE if the form element is longer than the parameter value.                         max_length[12]
 **exact_length**          Yes        Returns FALSE if the form element is not exactly the parameter value.                         exact_length[8]
 **greater_than**          Yes        Returns FALSE if the form element is less than or equal to the parameter value or not         greater_than[8]
                                      numeric.
diff --git a/user_guide_src/source/libraries/input.rst b/user_guide_src/source/libraries/input.rst
index f5ab048..8a83207 100644
--- a/user_guide_src/source/libraries/input.rst
+++ b/user_guide_src/source/libraries/input.rst
@@ -32,7 +32,8 @@
    (and a few other) characters.
 -  Provides XSS (Cross-site Scripting Hacks) filtering. This can be
    enabled globally, or upon request.
--  Standardizes newline characters to \\n(In Windows \\r\\n)
+-  Standardizes newline characters to ``PHP_EOL`` (\\n in UNIX-based OSes,
+   \\r\\n under Windows). This is configurable.
 
 XSS Filtering
 =============
@@ -155,18 +156,32 @@
 			$this->input->get(NULL, TRUE); // returns all GET items with XSS filter
 			$this->input->get(NULL, FALSE); // returns all GET items without XSS filtering
 
+	.. method:: post_get([$index = ''[, $xss_clean = NULL]])
+
+		:param string $index: POST/GET parameter name
+		:param bool $xss_clean: Whether to apply XSS filtering
+		:returns: mixed
+
+		This method works the same way as ``post()`` and ``get()``, only combined.
+		It will search through both POST and GET streams for data, looking in POST
+		first, and then in GET::
+
+			$this->input->post_get('some_data', TRUE);
+
 	.. method:: get_post([$index = ''[, $xss_clean = NULL]])
 
 		:param string $index: GET/POST parameter name
 		:param bool $xss_clean: Whether to apply XSS filtering
 		:returns: mixed
 
-		This method works the same way as ``post()`` and ``get()``, only combined.
-		It will search through both POST and GET streams for data, looking first
-		in POST, and then in GET::
+		This method works the same way as ``post_get()`` only it looks for GET
+		data first.
 
 			$this->input->get_post('some_data', TRUE);
 
+		.. note:: This method used to act EXACTLY like ``post_get()``, but it's
+			behavior has changed in CodeIgniter 3.0.
+
 	.. method:: cookie([$index = ''[, $xss_clean = NULL]])
 
 		:param string $index: COOKIE parameter name
@@ -362,6 +377,9 @@
 
 			$this->input->is_cli_request()
 
+		.. note:: This method is DEPRECATED and is now just an alias for the
+			:func:`is_cli()` function.
+
 	.. method:: method([$upper = FALSE])
 
 		:param bool $upper: Whether to return the request method name in upper or lower case
diff --git a/user_guide_src/source/libraries/loader.rst b/user_guide_src/source/libraries/loader.rst
index ec5a87b..15d9d80 100644
--- a/user_guide_src/source/libraries/loader.rst
+++ b/user_guide_src/source/libraries/loader.rst
@@ -278,6 +278,12 @@
 
 		This method retrieves all variables available to your views.
 
+	.. method:: clear_vars()
+
+		:returns: object
+
+		Clears cached view variables.
+
 	.. method:: model($model[, $name = ''[, $db_conn = FALSE]])
 
 		:param mixed $model: Model name or an array containing multiple models
@@ -292,7 +298,7 @@
 
 		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::
+		*application/models/blog/Queries.php* you'll load it using::
 
 			$this->load->model('blog/queries');
 
@@ -370,6 +376,33 @@
 		This method is an alias of the :doc:`config file loading
 		method <config>`: ``$this->config->load()``
 
+	.. method:: is_loaded($class)
+
+		:param string $class: Class name
+		:returns: mixed
+
+		Allows you to check if a class has already been loaded or not.
+
+		.. note:: The word "class" here refers to libraries and drivers.
+
+		If the requested class has been loaded, the method returns its assigned
+		name in the CI Super-object and FALSE if it's not::
+
+			$this->load->library('form_validation');
+			$this->load->is_loaded('Form_validation');	// returns 'form_validation'
+
+			$this->load->is_loaded('Nonexistent_library');	// returns FALSE
+
+		.. important:: If you have more than one instance of a class (assigned to
+			different properties), then the first one will be returned.
+
+		::
+
+			$this->load->library('form_validation', $config, 'fv');
+			$this->load->library('form_validation');
+
+			$this->load->is_loaded('Form_validation');	// returns 'fv'
+
 	.. method:: add_package_path($path[, $view_cascade = TRUE])
 
 		:param string $path: Path to add
diff --git a/user_guide_src/source/libraries/migration.rst b/user_guide_src/source/libraries/migration.rst
index 128796c..4143609 100644
--- a/user_guide_src/source/libraries/migration.rst
+++ b/user_guide_src/source/libraries/migration.rst
@@ -94,7 +94,7 @@
 Usage Example
 *************
 
-In this example some simple code is placed in **application/controllers/migrate.php** 
+In this example some simple code is placed in **application/controllers/Migrate.php** 
 to update the schema.::
 
 	<?php
@@ -175,4 +175,4 @@
 		specific versions. It works just like ``current()`` but ignores ``$config['migration_version']``.
 		::
 
-			$this->migration->version(5);
\ No newline at end of file
+			$this->migration->version(5);
diff --git a/user_guide_src/source/libraries/security.rst b/user_guide_src/source/libraries/security.rst
index 8d7ccb1..451fadf 100644
--- a/user_guide_src/source/libraries/security.rst
+++ b/user_guide_src/source/libraries/security.rst
@@ -67,12 +67,13 @@
 
 If you use the :doc:`form helper <../helpers/form_helper>`, then
 :func:`form_open()` will automatically insert a hidden csrf field in
-your forms. If not, then you can use ``csrf_get_token_name()`` and ``csrf_get_hash()``
+your forms. If not, then you can use ``get_csrf_token_name()``
+and ``get_csrf_hash()``
 ::
 
 	$csrf = array(
-		'name' => $this->security->csrf_get_token_name(),
-		'hash' => $this->security->csrf_get_hash()
+		'name' => $this->security->get_csrf_token_name(),
+		'hash' => $this->security->get_csrf_hash()
 	);
 
 	...
@@ -149,4 +150,4 @@
 		This method acts a lot like PHP's own native ``html_entity_decode()`` function in ENT_COMPAT mode, only
 		it tries to detect HTML entities that don't end in a semicolon because some browsers allow that.
 
-		If the ``$charset`` parameter is left empty, then your configured ``$config['charset']`` value will be used.
\ No newline at end of file
+		If the ``$charset`` parameter is left empty, then your configured ``$config['charset']`` value will be used.
diff --git a/user_guide_src/source/libraries/sessions.rst b/user_guide_src/source/libraries/sessions.rst
index 010b464..3e6dcf2 100644
--- a/user_guide_src/source/libraries/sessions.rst
+++ b/user_guide_src/source/libraries/sessions.rst
@@ -262,7 +262,7 @@
 ===================
 
 You'll find the following Session related preferences in your
-application/config/config.php file:
+*application/config/config.php* file:
 
 =========================== =============== =========================== ==========================================================================
 Preference                  Default         Options                     Description
@@ -281,7 +281,8 @@
                                                                         table before enabling this option (Cookie driver only).
 **sess_table_name**         ci_sessions     Any valid SQL table name    The name of the session database table (Cookie driver only).
 **sess_time_to_update**     300             Time in seconds             This options controls how often the session class will regenerate itself
-                                                                        and create a new session id.
+                                                                        and create a new session ID. Setting it to 0 will disable session
+                                                                        ID regeneartion.
 **sess_match_ip**           FALSE           TRUE/FALSE (boolean)        Whether to match the user's IP address when reading the session data.
                                                                         Note that some ISPs dynamically changes the IP, so if you want a
                                                                         non-expiring session you will likely set this to FALSE.
@@ -673,4 +674,4 @@
 		Example::
 
 			$this->session->tempdata('message');
-			//returns 'Test message.' considering the set_tempdata example.
\ No newline at end of file
+			//returns 'Test message.' considering the set_tempdata example.
diff --git a/user_guide_src/source/libraries/xmlrpc.rst b/user_guide_src/source/libraries/xmlrpc.rst
index 53fe965..d9b2dfb 100644
--- a/user_guide_src/source/libraries/xmlrpc.rst
+++ b/user_guide_src/source/libraries/xmlrpc.rst
@@ -307,7 +307,7 @@
 The Client
 ----------
 
-Using a text editor, create a controller called xmlrpc_client.php. In
+Using a text editor, create a controller called Xmlrpc_client.php. In
 it, place this code and save it to your application/controllers/
 folder::
 
@@ -348,7 +348,7 @@
 The Server
 ----------
 
-Using a text editor, create a controller called xmlrpc_server.php. In
+Using a text editor, create a controller called Xmlrpc_server.php. In
 it, place this code and save it to your application/controllers/
 folder::
 
@@ -569,4 +569,4 @@
 				'struct'
 			);
 
-		return $this->xmlrpc->send_response($response);
\ No newline at end of file
+		return $this->xmlrpc->send_response($response);
diff --git a/user_guide_src/source/tutorial/news_section.rst b/user_guide_src/source/tutorial/news_section.rst
index d7754e9..ad9ed41 100644
--- a/user_guide_src/source/tutorial/news_section.rst
+++ b/user_guide_src/source/tutorial/news_section.rst
@@ -16,7 +16,7 @@
 database or other data stores. They represent your data.
 
 Open up the application/models directory and create a new file called
-news_model.php and add the following code. Make sure you've configured
+News_model.php and add the following code. Make sure you've configured
 your database properly as described
 `here <../database/configuration.html>`_.
 
@@ -85,7 +85,7 @@
 that are going to display the news items to the user. This could be done
 in our pages controller created earlier, but for the sake of clarity, a
 new "news" controller is defined. Create the new controller at
-application/controllers/news.php.
+application/controllers/News.php.
 
 ::
 
@@ -127,7 +127,7 @@
 
 	public function index()
 	{
-		data['news'] = $this->news_model->get_news();
+		$data['news'] = $this->news_model->get_news();
 		$data['title'] = 'News archive';
 
 		$this->load->view('templates/header', $data);
diff --git a/user_guide_src/source/tutorial/static_pages.rst b/user_guide_src/source/tutorial/static_pages.rst
index 97c7460..330a50e 100644
--- a/user_guide_src/source/tutorial/static_pages.rst
+++ b/user_guide_src/source/tutorial/static_pages.rst
@@ -20,7 +20,7 @@
 As URL schemes become more complex, this may change. But for now, this
 is all we will need to know.
 
-Create a file at application/controllers/pages.php with the following
+Create a file at application/controllers/Pages.php with the following
 code.
 
 ::