Merge pull request #1017 from burakerdem/patch-1

Filesystem cache metadata function return correct TTL now.
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..31b74b1
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,26 @@
+language: php
+
+php:
+  - 5.3
+  - 5.4
+
+env:
+  - DB=mysql
+  - DB=pgsql
+  - DB=sqlite
+  - DB=pdo/mysql
+  - DB=pdo/pgsql
+  - DB=pdo/sqlite
+
+before_script:
+  - curl -s http://getcomposer.org/installer | php
+  - php composer.phar install
+  - sh -c "if [ '$DB' = 'pgsql' ] || [ '$DB' = 'pdo/pgsql' ]; then psql -c 'DROP DATABASE IF EXISTS ci_test;' -U postgres; fi"
+  - sh -c "if [ '$DB' = 'pgsql' ] || [ '$DB' = 'pdo/pgsql' ]; then psql -c 'create database ci_test;' -U postgres; fi"
+  - sh -c "if [ '$DB' = 'mysql' ] || [ '$DB' = 'pdo/mysql' ]; then mysql -e 'create database IF NOT EXISTS ci_test;'; fi"
+
+script: phpunit --coverage-text --configuration tests/travis/$DB.phpunit.xml
+
+branches:
+  only:
+    - develop
\ No newline at end of file
diff --git a/application/config/autoload.php b/application/config/autoload.php
index db49ca1..b3e63cb 100644
--- a/application/config/autoload.php
+++ b/application/config/autoload.php
@@ -1,13 +1,13 @@
-<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * 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:
diff --git a/application/config/config.php b/application/config/config.php
index 17b854b..2628885 100644
--- a/application/config/config.php
+++ b/application/config/config.php
@@ -1,13 +1,13 @@
-<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * 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:
@@ -297,12 +297,14 @@
 | 'cookie_domain' = Set to .your-domain.com for site-wide cookies
 | 'cookie_path'   =  Typically will be a forward slash
 | 'cookie_secure' =  Cookies will only be set if a secure HTTPS connection exists.
+| 'cookie_httponly' = Cookie will only be accessible via HTTP(S) (no javascript) 
 |
 */
 $config['cookie_prefix']	= "";
 $config['cookie_domain']	= "";
 $config['cookie_path']		= "/";
 $config['cookie_secure']	= FALSE;
+$config['cookie_httponly'] 	= FALSE;
 
 /*
 |--------------------------------------------------------------------------
diff --git a/application/config/constants.php b/application/config/constants.php
index c7203e4..d22d296 100644
--- a/application/config/constants.php
+++ b/application/config/constants.php
@@ -1,13 +1,13 @@
-<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * 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:
@@ -66,8 +66,8 @@
 | Display Debug backtrace
 |--------------------------------------------------------------------------
 |
-| If set to TRUE, a backtrace will be displayed along with php errors. If 
-| error_reporting is disabled, the backtrace will not display, regardless 
+| If set to TRUE, a backtrace will be displayed along with php errors. If
+| error_reporting is disabled, the backtrace will not display, regardless
 | of this setting
 |
 */
diff --git a/application/config/database.php b/application/config/database.php
index 7eac59b..1949873 100644
--- a/application/config/database.php
+++ b/application/config/database.php
@@ -1,13 +1,13 @@
-<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * 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:
@@ -37,14 +37,16 @@
 | EXPLANATION OF VARIABLES
 | -------------------------------------------------------------------
 |
+|	['dsn']      The full DSN string describe a connection to the database.
 |	['hostname'] The hostname of your database server.
 |	['username'] The username used to connect to the database
 |	['password'] The password used to connect to the database
 |	['database'] The name of the database you want to connect to
 |	['dbdriver'] The database type. e.g.: mysql.  Currently supported:
-				 mysql, mysqli, pdo, postgre, odbc, mssql, sqlite, oci8
+|				 cubrid, interbase, mssql, mysql, mysqli, oci8, 
+|				 odbc, pdo, postgre, sqlite, sqlite3, sqlsrv
 |	['dbprefix'] You can add an optional prefix, which will be added
-|				 to the table name when using the  Active Record class
+|				 to the table name when using the  Query Builder class
 |	['pconnect'] TRUE/FALSE - Whether to use a persistent connection
 |	['db_debug'] TRUE/FALSE - Whether database errors should be displayed.
 |	['cache_on'] TRUE/FALSE - Enables/disables query caching
@@ -67,29 +69,32 @@
 | The $active_group variable lets you choose which connection group to
 | make active.  By default there is only one group (the 'default' group).
 |
-| The $active_record variables lets you determine whether or not to load
-| the active record class
+| The $query_builder variables lets you determine whether or not to load
+| the query builder class
 */
 
 $active_group = 'default';
-$active_record = TRUE;
+$query_builder = TRUE;
 
-$db['default']['hostname'] = 'localhost';
-$db['default']['username'] = '';
-$db['default']['password'] = '';
-$db['default']['database'] = '';
-$db['default']['dbdriver'] = 'mysql';
-$db['default']['dbprefix'] = '';
-$db['default']['pconnect'] = FALSE;
-$db['default']['db_debug'] = TRUE;
-$db['default']['cache_on'] = FALSE;
-$db['default']['cachedir'] = '';
-$db['default']['char_set'] = 'utf8';
-$db['default']['dbcollat'] = 'utf8_general_ci';
-$db['default']['swap_pre'] = '';
-$db['default']['autoinit'] = TRUE;
-$db['default']['stricton'] = FALSE;
-$db['default']['failover'] = array();
+$db['default'] = array(
+	'dsn'	=> '',
+	'hostname' => 'localhost',
+	'username' => '',
+	'password' => '',
+	'database' => '',
+	'dbdriver' => 'mysqli',
+	'dbprefix' => '',
+	'pconnect' => FALSE,
+	'db_debug' => TRUE,
+	'cache_on' => FALSE,
+	'cachedir' => '',
+	'char_set' => 'utf8',
+	'dbcollat' => 'utf8_general_ci',
+	'swap_pre' => '',
+	'autoinit' => TRUE,
+	'stricton' => FALSE,
+	'failover' => array()
+);
 
 /* End of file database.php */
 /* Location: ./application/config/database.php */
\ No newline at end of file
diff --git a/application/config/doctypes.php b/application/config/doctypes.php
index 984da59..c7f5b55 100644
--- a/application/config/doctypes.php
+++ b/application/config/doctypes.php
@@ -1,13 +1,13 @@
-<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * 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:
@@ -26,15 +26,25 @@
  */
 
 $_doctypes = array(
-					'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>',
-					'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">'
+					'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>',
+					'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">',
+					'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">',
+					'xhtml-math-svg-sh'	=> '<!DOCTYPE svg:svg 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">',
+					'xhtml-rdfa-1'		=> '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML+RDFa 1.0//EN" "http://www.w3.org/MarkUp/DTD/xhtml-rdfa-1.dtd">',
+					'xhtml-rdfa-2'		=> '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML+RDFa 1.1//EN" "http://www.w3.org/MarkUp/DTD/xhtml-rdfa-2.dtd">'
 					);
 
 /* End of file doctypes.php */
diff --git a/application/config/foreign_chars.php b/application/config/foreign_chars.php
index 1ae0cef..41de123 100644
--- a/application/config/foreign_chars.php
+++ b/application/config/foreign_chars.php
@@ -1,13 +1,13 @@
-<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * 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:
@@ -40,50 +40,55 @@
 	'/Ä/' => 'Ae',
 	'/Ü/' => 'Ue',
 	'/Ö/' => 'Oe',
-	'/À|Á|Â|Ã|Ä|Å|Ǻ|Ā|Ă|Ą|Ǎ/' => 'A',
-	'/à|á|â|ã|å|ǻ|ā|ă|ą|ǎ|ª/' => 'a',
+	'/À|Á|Â|Ã|Ä|Å|Ǻ|Ā|Ă|Ą|Ǎ|Α|Ά/' => 'A',
+	'/à|á|â|ã|å|ǻ|ā|ă|ą|ǎ|ª|α|ά/' => 'a',
 	'/Ç|Ć|Ĉ|Ċ|Č/' => 'C',
 	'/ç|ć|ĉ|ċ|č/' => 'c',
-	'/Ð|Ď|Đ/' => 'Dj',
-	'/ð|ď|đ/' => 'dj',
-	'/È|É|Ê|Ë|Ē|Ĕ|Ė|Ę|Ě/' => 'E',
-	'/è|é|ê|ë|ē|ĕ|ė|ę|ě/' => 'e',
-	'/Ĝ|Ğ|Ġ|Ģ/' => 'G',
-	'/ĝ|ğ|ġ|ģ/' => 'g',
+	'/Ð|Ď|Đ|Δ/' => 'Dj',
+	'/ð|ď|đ|δ/' => 'dj',
+	'/È|É|Ê|Ë|Ē|Ĕ|Ė|Ę|Ě|Ε|Έ/' => 'E',
+	'/è|é|ê|ë|ē|ĕ|ė|ę|ě|έ|ε/' => 'e',
+	'/Ĝ|Ğ|Ġ|Ģ|Γ/' => 'G',
+	'/ĝ|ğ|ġ|ģ|γ/' => 'g',
 	'/Ĥ|Ħ/' => 'H',
 	'/ĥ|ħ/' => 'h',
-	'/Ì|Í|Î|Ï|Ĩ|Ī|Ĭ|Ǐ|Į|İ/' => 'I',
-	'/ì|í|î|ï|ĩ|ī|ĭ|ǐ|į|ı/' => 'i',
+	'/Ì|Í|Î|Ï|Ĩ|Ī|Ĭ|Ǐ|Į|İ|Η|Ή|Ί|Ι|Ϊ/' => 'I',
+	'/ì|í|î|ï|ĩ|ī|ĭ|ǐ|į|ı|η|ή|ί|ι|ϊ/' => 'i',
 	'/Ĵ/' => 'J',
 	'/ĵ/' => 'j',
-	'/Ķ/' => 'K',
-	'/ķ/' => 'k',
-	'/Ĺ|Ļ|Ľ|Ŀ|Ł/' => 'L',
-	'/ĺ|ļ|ľ|ŀ|ł/' => 'l',
-	'/Ñ|Ń|Ņ|Ň/' => 'N',
-	'/ñ|ń|ņ|ň|ʼn/' => 'n',
-	'/Ò|Ó|Ô|Õ|Ō|Ŏ|Ǒ|Ő|Ơ|Ø|Ǿ/' => 'O',
-	'/ò|ó|ô|õ|ō|ŏ|ǒ|ő|ơ|ø|ǿ|º/' => 'o',
-	'/Ŕ|Ŗ|Ř/' => 'R',
-	'/ŕ|ŗ|ř/' => 'r',
-	'/Ś|Ŝ|Ş|Š/' => 'S',
-	'/ś|ŝ|ş|š|ſ/' => 's',
-	'/Ţ|Ť|Ŧ/' => 'T',
-	'/ţ|ť|ŧ/' => 't',
+	'/Ķ|Κ/' => 'K',
+	'/ķ|κ/' => 'k',
+	'/Ĺ|Ļ|Ľ|Ŀ|Ł|Λ/' => 'L',
+	'/ĺ|ļ|ľ|ŀ|ł|λ/' => 'l',
+	'/Ñ|Ń|Ņ|Ň|Ν/' => 'N',
+	'/ñ|ń|ņ|ň|ʼn|ν/' => 'n',
+	'/Ò|Ó|Ô|Õ|Ō|Ŏ|Ǒ|Ő|Ơ|Ø|Ǿ|Ο|Ό|Ω|Ώ/' => 'O',
+	'/ò|ó|ô|õ|ō|ŏ|ǒ|ő|ơ|ø|ǿ|º|ο|ό|ω|ώ/' => 'o',
+	'/Ŕ|Ŗ|Ř|Ρ/' => 'R',
+	'/ŕ|ŗ|ř|ρ/' => 'r',
+	'/Ś|Ŝ|Ş|Ș|Š|Σ/' => 'S',
+	'/ś|ŝ|ş|ș|š|ſ|σ|ς/' => 's',
+	'/Ț|Ţ|Ť|Ŧ|τ/' => 'T',
+	'/ț|ţ|ť|ŧ/' => 't',
 	'/Ù|Ú|Û|Ũ|Ū|Ŭ|Ů|Ű|Ų|Ư|Ǔ|Ǖ|Ǘ|Ǚ|Ǜ/' => 'U',
-	'/ù|ú|û|ũ|ū|ŭ|ů|ű|ų|ư|ǔ|ǖ|ǘ|ǚ|ǜ/' => 'u',
-	'/Ý|Ÿ|Ŷ/' => 'Y',
+	'/ù|ú|û|ũ|ū|ŭ|ů|ű|ų|ư|ǔ|ǖ|ǘ|ǚ|ǜ|υ|ύ|ϋ/' => 'u',
+	'/Ý|Ÿ|Ŷ|Υ|Ύ|Ϋ/' => 'Y',
 	'/ý|ÿ|ŷ/' => 'y',
 	'/Ŵ/' => 'W',
 	'/ŵ/' => 'w',
-	'/Ź|Ż|Ž/' => 'Z',
-	'/ź|ż|ž/' => 'z',
+	'/Ź|Ż|Ž|Ζ/' => 'Z',
+	'/ź|ż|ž|ζ/' => 'z',
 	'/Æ|Ǽ/' => 'AE',
 	'/ß/'=> 'ss',
 	'/IJ/' => 'IJ',
 	'/ij/' => 'ij',
 	'/Œ/' => 'OE',
-	'/ƒ/' => 'f'
+	'/ƒ/' => 'f',
+	'/ξ/' => 'ks',
+	'/π/' => 'p',
+	'/β/' => 'v',
+	'/μ/' => 'm',
+	'/ψ/' => 'ps',
 );
 
 /* End of file foreign_chars.php */
diff --git a/application/config/hooks.php b/application/config/hooks.php
index 80269df..3500503 100644
--- a/application/config/hooks.php
+++ b/application/config/hooks.php
@@ -1,13 +1,13 @@
-<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * 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:
@@ -37,6 +37,5 @@
 */
 
 
-
 /* End of file hooks.php */
 /* Location: ./application/config/hooks.php */
\ No newline at end of file
diff --git a/application/config/memcached.php b/application/config/memcached.php
index 2b1a772..7166b70 100644
--- a/application/config/memcached.php
+++ b/application/config/memcached.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
diff --git a/application/config/migration.php b/application/config/migration.php
index 668c357..88e3982 100644
--- a/application/config/migration.php
+++ b/application/config/migration.php
@@ -1,8 +1,8 @@
-<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -89,5 +89,5 @@
 */
 $config['migration_path'] = APPPATH . 'migrations/';
 
-
-/* End of file migration.php */
\ No newline at end of file
+/* 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 8c34fd2..15493af 100644
--- a/application/config/mimes.php
+++ b/application/config/mimes.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -34,135 +34,137 @@
 |
 */
 
-$mimes = array('hqx'	=>	array('application/mac-binhex40', 'application/mac-binhex', 'application/x-binhex40', 'application/x-mac-binhex40'),
-				'cpt'	=>	'application/mac-compactpro',
-				'csv'	=>	array('text/x-comma-separated-values', 'text/comma-separated-values', 'application/octet-stream', 'application/vnd.ms-excel', 'application/x-csv', 'text/x-csv', 'text/csv', 'application/csv', 'application/excel', 'application/vnd.msexcel'),
-				'bin'	=>	array('application/macbinary', 'application/mac-binary', 'application/octet-stream', 'application/x-binary', 'application/x-macbinary'),
-				'dms'	=>	'application/octet-stream',
-				'lha'	=>	'application/octet-stream',
-				'lzh'	=>	'application/octet-stream',
-				'exe'	=>	array('application/octet-stream', 'application/x-msdownload'),
-				'class'	=>	'application/octet-stream',
-				'psd'	=>	'application/x-photoshop',
-				'so'	=>	'application/octet-stream',
-				'sea'	=>	'application/octet-stream',
-				'dll'	=>	'application/octet-stream',
-				'oda'	=>	'application/oda',
-				'pdf'	=>	array('application/pdf', 'application/x-download'),
-				'ai'	=>	'application/postscript',
-				'eps'	=>	'application/postscript',
-				'ps'	=>	'application/postscript',
-				'smi'	=>	'application/smil',
-				'smil'	=>	'application/smil',
-				'mif'	=>	'application/vnd.mif',
-				'xls'	=>	array('application/excel', 'application/vnd.ms-excel', 'application/msexcel'),
-				'ppt'	=>	array('application/powerpoint', 'application/vnd.ms-powerpoint'),
-				'pptx'	=> 	'application/vnd.openxmlformats-officedocument.presentationml.presentation',
-				'wbxml'	=>	'application/wbxml',
-				'wmlc'	=>	'application/wmlc',
-				'dcr'	=>	'application/x-director',
-				'dir'	=>	'application/x-director',
-				'dxr'	=>	'application/x-director',
-				'dvi'	=>	'application/x-dvi',
-				'gtar'	=>	'application/x-gtar',
-				'gz'	=>	'application/x-gzip',
-				'gzip'  =>	'application/x-gzip',
-				'php'	=>	'application/x-httpd-php',
-				'php4'	=>	'application/x-httpd-php',
-				'php3'	=>	'application/x-httpd-php',
-				'phtml'	=>	'application/x-httpd-php',
-				'phps'	=>	'application/x-httpd-php-source',
-				'js'	=>	'application/x-javascript',
-				'swf'	=>	'application/x-shockwave-flash',
-				'sit'	=>	'application/x-stuffit',
-				'tar'	=>	'application/x-tar',
-				'tgz'	=>	array('application/x-tar', 'application/x-gzip-compressed'),
-				'xhtml'	=>	'application/xhtml+xml',
-				'xht'	=>	'application/xhtml+xml',
-				'zip'	=>	array('application/x-zip', 'application/zip', 'application/x-zip-compressed'),
-				'mid'	=>	'audio/midi',
-				'midi'	=>	'audio/midi',
-				'mpga'	=>	'audio/mpeg',
-				'mp2'	=>	'audio/mpeg',
-				'mp3'	=>	array('audio/mpeg', 'audio/mpg', 'audio/mpeg3', 'audio/mp3'),
-				'aif'	=>	array('audio/x-aiff', 'audio/aiff'),
-				'aiff'	=>	array('audio/x-aiff', 'audio/aiff'),
-				'aifc'	=>	'audio/x-aiff',
-				'ram'	=>	'audio/x-pn-realaudio',
-				'rm'	=>	'audio/x-pn-realaudio',
-				'rpm'	=>	'audio/x-pn-realaudio-plugin',
-				'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'),
-				'gif'	=>	'image/gif',
-				'jpeg'	=>	array('image/jpeg', 'image/pjpeg'),
-				'jpg'	=>	array('image/jpeg', 'image/pjpeg'),
-				'jpe'	=>	array('image/jpeg', 'image/pjpeg'),
-				'png'	=>	array('image/png',  'image/x-png'),
-				'tiff'	=>	'image/tiff',
-				'tif'	=>	'image/tiff',
-				'css'	=>	'text/css',
-				'html'	=>	'text/html',
-				'htm'	=>	'text/html',
-				'shtml'	=>	'text/html',
-				'txt'	=>	'text/plain',
-				'text'	=>	'text/plain',
-				'log'	=>	array('text/plain', 'text/x-log'),
-				'rtx'	=>	'text/richtext',
-				'rtf'	=>	'text/rtf',
-				'xml'	=>	array('application/xml', 'text/xml'),
-				'xsl'	=>	array('application/xml', 'text/xsl', 'text/xml'),
-				'mpeg'	=>	'video/mpeg',
-				'mpg'	=>	'video/mpeg',
-				'mpe'	=>	'video/mpeg',
-				'qt'	=>	'video/quicktime',
-				'mov'	=>	'video/quicktime',
-				'avi'	=>	array('video/x-msvideo', 'video/msvideo', 'video/avi', 'application/x-troff-msvideo'),
-				'movie'	=>	'video/x-sgi-movie',
-				'doc'	=>	'application/msword',
-				'docx'	=>	'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
-				'xlsx'	=>	'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
-				'word'	=>	array('application/msword', 'application/octet-stream'),
-				'xl'	=>	'application/excel',
-				'eml'	=>	'message/rfc822',
-				'json'  =>	array('application/json', 'text/json'),
-				'pem'   =>	array('application/x-x509-user-cert', 'application/x-pem-file', 'application/octet-stream'),
-				'p10'   =>	array('application/x-pkcs10', 'application/pkcs10'),
-				'p12'   =>	'application/x-pkcs12',
-				'p7a'   =>	'application/x-pkcs7-signature',
-				'p7c'   =>	array('application/pkcs7-mime', 'application/x-pkcs7-mime'),
-				'p7m'   =>	array('application/pkcs7-mime', 'application/x-pkcs7-mime'),
-				'p7r'   =>	'application/x-pkcs7-certreqresp',
-				'p7s'   =>	'application/pkcs7-signature',
-				'crt'   =>	array('application/x-x509-ca-cert', 'application/x-x509-user-cert', 'application/pkix-cert'),
-				'crl'   =>	array('application/pkix-crl', 'application/pkcs-crl'),
-				'der'   =>	'application/x-x509-ca-cert',
-				'kdb'   =>	'application/octet-stream',
-				'pgp'   =>	'application/pgp',
-				'gpg'   =>	'application/gpg-keys',
-				'sst'   =>	'application/octet-stream',
-				'csr'   =>	'application/octet-stream',
-				'rsa'   =>	'application/x-pkcs7',
-				'cer'   =>	array('application/pkix-cert', 'application/x-x509-ca-cert'),
-				'3g2'   =>	'video/3gpp2',
-				'3gp'   =>	'video/3gp',
-				'mp4'   =>	'video/mp4',
-				'm4a'   =>	'audio/x-m4a',
-				'f4v'   =>	'video/mp4',
-				'aac'   =>	'audio/x-acc',
-				'm4u'   =>	'application/vnd.mpegurl',
-				'm3u'   =>	'text/plain',
-				'xspf'  =>	'application/xspf+xml',
-				'vlc'   =>	'application/videolan',
-				'wmv'   =>	'video/x-ms-wmv',
-				'au'    =>	'audio/x-au',
-				'ac3'   =>	'audio/ac3',
-				'flac'  =>	'audio/x-flac',
-				'ogg'   =>	'audio/ogg',
-				'kmz'	=>	array('application/vnd.google-earth.kmz', 'application/zip', 'application/x-zip'),
-				'kml'	=>	array('application/vnd.google-earth.kml+xml', 'application/xml', 'text/xml')
-			);
+return array(
+	'hqx'	=>	array('application/mac-binhex40', 'application/mac-binhex', 'application/x-binhex40', 'application/x-mac-binhex40'),
+	'cpt'	=>	'application/mac-compactpro',
+	'csv'	=>	array('text/x-comma-separated-values', 'text/comma-separated-values', 'application/octet-stream', 'application/vnd.ms-excel', 'application/x-csv', 'text/x-csv', 'text/csv', 'application/csv', 'application/excel', 'application/vnd.msexcel'),
+	'bin'	=>	array('application/macbinary', 'application/mac-binary', 'application/octet-stream', 'application/x-binary', 'application/x-macbinary'),
+	'dms'	=>	'application/octet-stream',
+	'lha'	=>	'application/octet-stream',
+	'lzh'	=>	'application/octet-stream',
+	'exe'	=>	array('application/octet-stream', 'application/x-msdownload'),
+	'class'	=>	'application/octet-stream',
+	'psd'	=>	'application/x-photoshop',
+	'so'	=>	'application/octet-stream',
+	'sea'	=>	'application/octet-stream',
+	'dll'	=>	'application/octet-stream',
+	'oda'	=>	'application/oda',
+	'pdf'	=>	array('application/pdf', 'application/x-download'),
+	'ai'	=>	'application/postscript',
+	'eps'	=>	'application/postscript',
+	'ps'	=>	'application/postscript',
+	'smi'	=>	'application/smil',
+	'smil'	=>	'application/smil',
+	'mif'	=>	'application/vnd.mif',
+	'xls'	=>	array('application/excel', 'application/vnd.ms-excel', 'application/msexcel'),
+	'ppt'	=>	array('application/powerpoint', 'application/vnd.ms-powerpoint'),
+	'pptx'	=> 	'application/vnd.openxmlformats-officedocument.presentationml.presentation',
+	'wbxml'	=>	'application/wbxml',
+	'wmlc'	=>	'application/wmlc',
+	'dcr'	=>	'application/x-director',
+	'dir'	=>	'application/x-director',
+	'dxr'	=>	'application/x-director',
+	'dvi'	=>	'application/x-dvi',
+	'gtar'	=>	'application/x-gtar',
+	'gz'	=>	'application/x-gzip',
+	'gzip'  =>	'application/x-gzip',
+	'php'	=>	'application/x-httpd-php',
+	'php4'	=>	'application/x-httpd-php',
+	'php3'	=>	'application/x-httpd-php',
+	'phtml'	=>	'application/x-httpd-php',
+	'phps'	=>	'application/x-httpd-php-source',
+	'js'	=>	'application/x-javascript',
+	'swf'	=>	'application/x-shockwave-flash',
+	'sit'	=>	'application/x-stuffit',
+	'tar'	=>	'application/x-tar',
+	'tgz'	=>	array('application/x-tar', 'application/x-gzip-compressed'),
+	'xhtml'	=>	'application/xhtml+xml',
+	'xht'	=>	'application/xhtml+xml',
+	'zip'	=>	array('application/x-zip', 'application/zip', 'application/x-zip-compressed'),
+	'mid'	=>	'audio/midi',
+	'midi'	=>	'audio/midi',
+	'mpga'	=>	'audio/mpeg',
+	'mp2'	=>	'audio/mpeg',
+	'mp3'	=>	array('audio/mpeg', 'audio/mpg', 'audio/mpeg3', 'audio/mp3'),
+	'aif'	=>	array('audio/x-aiff', 'audio/aiff'),
+	'aiff'	=>	array('audio/x-aiff', 'audio/aiff'),
+	'aifc'	=>	'audio/x-aiff',
+	'ram'	=>	'audio/x-pn-realaudio',
+	'rm'	=>	'audio/x-pn-realaudio',
+	'rpm'	=>	'audio/x-pn-realaudio-plugin',
+	'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'),
+	'gif'	=>	'image/gif',
+	'jpeg'	=>	array('image/jpeg', 'image/pjpeg'),
+	'jpg'	=>	array('image/jpeg', 'image/pjpeg'),
+	'jpe'	=>	array('image/jpeg', 'image/pjpeg'),
+	'png'	=>	array('image/png',  'image/x-png'),
+	'tiff'	=>	'image/tiff',
+	'tif'	=>	'image/tiff',
+	'css'	=>	'text/css',
+	'html'	=>	'text/html',
+	'htm'	=>	'text/html',
+	'shtml'	=>	'text/html',
+	'txt'	=>	'text/plain',
+	'text'	=>	'text/plain',
+	'log'	=>	array('text/plain', 'text/x-log'),
+	'rtx'	=>	'text/richtext',
+	'rtf'	=>	'text/rtf',
+	'xml'	=>	array('application/xml', 'text/xml'),
+	'xsl'	=>	array('application/xml', 'text/xsl', 'text/xml'),
+	'mpeg'	=>	'video/mpeg',
+	'mpg'	=>	'video/mpeg',
+	'mpe'	=>	'video/mpeg',
+	'qt'	=>	'video/quicktime',
+	'mov'	=>	'video/quicktime',
+	'avi'	=>	array('video/x-msvideo', 'video/msvideo', 'video/avi', 'application/x-troff-msvideo'),
+	'movie'	=>	'video/x-sgi-movie',
+	'doc'	=>	array('application/msword', 'application/vnd.ms-office'),
+	'docx'	=>	array('application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/zip'),
+	'xlsx'	=>	array('application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'application/zip'),
+	'word'	=>	array('application/msword', 'application/octet-stream'),
+	'xl'	=>	'application/excel',
+	'eml'	=>	'message/rfc822',
+	'json'  =>	array('application/json', 'text/json'),
+	'pem'   =>	array('application/x-x509-user-cert', 'application/x-pem-file', 'application/octet-stream'),
+	'p10'   =>	array('application/x-pkcs10', 'application/pkcs10'),
+	'p12'   =>	'application/x-pkcs12',
+	'p7a'   =>	'application/x-pkcs7-signature',
+	'p7c'   =>	array('application/pkcs7-mime', 'application/x-pkcs7-mime'),
+	'p7m'   =>	array('application/pkcs7-mime', 'application/x-pkcs7-mime'),
+	'p7r'   =>	'application/x-pkcs7-certreqresp',
+	'p7s'   =>	'application/pkcs7-signature',
+	'crt'   =>	array('application/x-x509-ca-cert', 'application/x-x509-user-cert', 'application/pkix-cert'),
+	'crl'   =>	array('application/pkix-crl', 'application/pkcs-crl'),
+	'der'   =>	'application/x-x509-ca-cert',
+	'kdb'   =>	'application/octet-stream',
+	'pgp'   =>	'application/pgp',
+	'gpg'   =>	'application/gpg-keys',
+	'sst'   =>	'application/octet-stream',
+	'csr'   =>	'application/octet-stream',
+	'rsa'   =>	'application/x-pkcs7',
+	'cer'   =>	array('application/pkix-cert', 'application/x-x509-ca-cert'),
+	'3g2'   =>	'video/3gpp2',
+	'3gp'   =>	'video/3gp',
+	'mp4'   =>	'video/mp4',
+	'm4a'   =>	'audio/x-m4a',
+	'f4v'   =>	'video/mp4',
+	'aac'   =>	'audio/x-acc',
+	'm4u'   =>	'application/vnd.mpegurl',
+	'm3u'   =>	'text/plain',
+	'xspf'  =>	'application/xspf+xml',
+	'vlc'   =>	'application/videolan',
+	'wmv'   =>	'video/x-ms-wmv',
+	'au'    =>	'audio/x-au',
+	'ac3'   =>	'audio/ac3',
+	'flac'  =>	'audio/x-flac',
+	'ogg'   =>	'audio/ogg',
+	'kmz'	=>	array('application/vnd.google-earth.kmz', 'application/zip', 'application/x-zip'),
+	'kml'	=>	array('application/vnd.google-earth.kml+xml', 'application/xml', 'text/xml'),
+	'ics'	=>	'text/calendar'
+);
 
 /* End of file mimes.php */
-/* Location: ./application/config/mimes.php */
+/* Location: ./application/config/mimes.php */
\ No newline at end of file
diff --git a/application/config/profiler.php b/application/config/profiler.php
index f956142..c161a4d 100644
--- a/application/config/profiler.php
+++ b/application/config/profiler.php
@@ -1,13 +1,13 @@
-<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * 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:
@@ -38,6 +38,5 @@
 */
 
 
-
 /* End of file profiler.php */
 /* Location: ./application/config/profiler.php */
\ No newline at end of file
diff --git a/application/config/routes.php b/application/config/routes.php
index 53fc7e7..0011986 100644
--- a/application/config/routes.php
+++ b/application/config/routes.php
@@ -1,13 +1,13 @@
-<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * 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:
@@ -64,9 +64,8 @@
 |
 */
 
-$route['default_controller'] = "welcome";
+$route['default_controller'] = 'welcome';
 $route['404_override'] = '';
 
-
 /* End of file routes.php */
 /* Location: ./application/config/routes.php */
\ No newline at end of file
diff --git a/application/config/smileys.php b/application/config/smileys.php
index 4132aed..baefe53 100644
--- a/application/config/smileys.php
+++ b/application/config/smileys.php
@@ -1,13 +1,13 @@
-<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * 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:
diff --git a/application/config/user_agents.php b/application/config/user_agents.php
index e7a6894..416ef56 100644
--- a/application/config/user_agents.php
+++ b/application/config/user_agents.php
@@ -1,8 +1,8 @@
-<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -29,14 +29,13 @@
 | -------------------------------------------------------------------
 | USER AGENT TYPES
 | -------------------------------------------------------------------
-| This file contains four arrays of user agent data.  It is used by the
+| This file contains four arrays of user agent data. It is used by the
 | User Agent Class to help identify browser, platform, robot, and
-| mobile device data.  The array keys are used to identify the device
+| mobile device data. The array keys are used to identify the device
 | and the array values are used to set the actual name of the item.
-|
 */
 
-$platforms = array (
+$platforms = array(
 	'windows nt 6.1'	=> 'Windows 7',
 	'windows nt 6.0'	=> 'Windows Vista',
 	'windows nt 5.2'	=> 'Windows 2003',
@@ -51,6 +50,11 @@
 	'windows 95'		=> 'Windows 95',
 	'win95'				=> 'Windows 95',
 	'windows'			=> 'Unknown Windows OS',
+	'android'			=> 'Android',
+	'blackberry'		=> 'BlackBerry',
+	'iphone'			=> 'iOS',
+	'ipad'				=> 'iOS',
+	'ipod'				=> 'iOS',
 	'os x'				=> 'Mac OS X',
 	'ppc mac'			=> 'Power PC Mac',
 	'freebsd'			=> 'FreeBSD',
@@ -117,84 +121,84 @@
 //	'motorola'			=> 'Motorola'
 
 	// Phones and Manufacturers
-	'motorola'		=> "Motorola",
-	'nokia'			=> "Nokia",
-	'palm'			=> "Palm",
-	'iphone'		=> "Apple iPhone",
-	'ipad'			=> "iPad",
-	'ipod'			=> "Apple iPod Touch",
-	'sony'			=> "Sony Ericsson",
-	'ericsson'		=> "Sony Ericsson",
-	'blackberry'	=> "BlackBerry",
-	'cocoon'		=> "O2 Cocoon",
-	'blazer'		=> "Treo",
-	'lg'			=> "LG",
-	'amoi'			=> "Amoi",
-	'xda'			=> "XDA",
-	'mda'			=> "MDA",
-	'vario'			=> "Vario",
-	'htc'			=> "HTC",
-	'samsung'		=> "Samsung",
-	'sharp'			=> "Sharp",
-	'sie-'			=> "Siemens",
-	'alcatel'		=> "Alcatel",
-	'benq'			=> "BenQ",
-	'ipaq'			=> "HP iPaq",
-	'mot-'			=> "Motorola",
-	'playstation portable'	=> "PlayStation Portable",
-	'hiptop'		=> "Danger Hiptop",
-	'nec-'			=> "NEC",
-	'panasonic'		=> "Panasonic",
-	'philips'		=> "Philips",
-	'sagem'			=> "Sagem",
-	'sanyo'			=> "Sanyo",
-	'spv'			=> "SPV",
-	'zte'			=> "ZTE",
-	'sendo'			=> "Sendo",
-	'dsi'			=> "Nintendo DSi",
-	'ds'			=> "Nintendo DS",
-	'wii'			=> "Nintendo Wii",
-	'3ds'			=> "Nintendo 3DS",
-	'open web'		=> "Open Web",
-	'openweb'		=> "OpenWeb",
+	'motorola'		=> 'Motorola',
+	'nokia'			=> 'Nokia',
+	'palm'			=> 'Palm',
+	'iphone'		=> 'Apple iPhone',
+	'ipad'			=> 'iPad',
+	'ipod'			=> 'Apple iPod Touch',
+	'sony'			=> 'Sony Ericsson',
+	'ericsson'		=> 'Sony Ericsson',
+	'blackberry'	=> 'BlackBerry',
+	'cocoon'		=> 'O2 Cocoon',
+	'blazer'		=> 'Treo',
+	'lg'			=> 'LG',
+	'amoi'			=> 'Amoi',
+	'xda'			=> 'XDA',
+	'mda'			=> 'MDA',
+	'vario'			=> 'Vario',
+	'htc'			=> 'HTC',
+	'samsung'		=> 'Samsung',
+	'sharp'			=> 'Sharp',
+	'sie-'			=> 'Siemens',
+	'alcatel'		=> 'Alcatel',
+	'benq'			=> 'BenQ',
+	'ipaq'			=> 'HP iPaq',
+	'mot-'			=> 'Motorola',
+	'playstation portable'	=> 'PlayStation Portable',
+	'hiptop'		=> 'Danger Hiptop',
+	'nec-'			=> 'NEC',
+	'panasonic'		=> 'Panasonic',
+	'philips'		=> 'Philips',
+	'sagem'			=> 'Sagem',
+	'sanyo'			=> 'Sanyo',
+	'spv'			=> 'SPV',
+	'zte'			=> 'ZTE',
+	'sendo'			=> 'Sendo',
+	'dsi'			=> 'Nintendo DSi',
+	'ds'			=> 'Nintendo DS',
+	'wii'			=> 'Nintendo Wii',
+	'3ds'			=> 'Nintendo 3DS',
+	'open web'		=> 'Open Web',
+	'openweb'		=> 'OpenWeb',
 
 	// Operating Systems
-	'android'		=> "Android",
-	'symbian'		=> "Symbian",
-	'SymbianOS'		=> "SymbianOS",
-	'elaine'		=> "Palm",
-	'palm'			=> "Palm",
-	'series60'		=> "Symbian S60",
-	'windows ce'	=> "Windows CE",
+	'android'		=> 'Android',
+	'symbian'		=> 'Symbian',
+	'SymbianOS'		=> 'SymbianOS',
+	'elaine'		=> 'Palm',
+	'series60'		=> 'Symbian S60',
+	'windows ce'	=> 'Windows CE',
 
 	// Browsers
-	'obigo'			=> "Obigo",
-	'netfront'		=> "Netfront Browser",
-	'openwave'		=> "Openwave Browser",
-	'mobilexplorer'	=> "Mobile Explorer",
-	'operamini'		=> "Opera Mini",
-	'opera mini'	=> "Opera Mini",
-	'opera mobi'	=> "Opera Mobile",
+	'obigo'			=> 'Obigo',
+	'netfront'		=> 'Netfront Browser',
+	'openwave'		=> 'Openwave Browser',
+	'mobilexplorer'	=> 'Mobile Explorer',
+	'operamini'		=> 'Opera Mini',
+	'opera mini'	=> 'Opera Mini',
+	'opera mobi'	=> 'Opera Mobile',
+	'fennec'	=> 'Firefox Mobile',
 
 	// Other
-	'digital paths'	=> "Digital Paths",
-	'avantgo'		=> "AvantGo",
-	'xiino'			=> "Xiino",
-	'novarra'		=> "Novarra Transcoder",
-	'vodafone'		=> "Vodafone",
-	'docomo'		=> "NTT DoCoMo",
-	'o2'			=> "O2",
+	'digital paths'	=> 'Digital Paths',
+	'avantgo'		=> 'AvantGo',
+	'xiino'			=> 'Xiino',
+	'novarra'		=> 'Novarra Transcoder',
+	'vodafone'		=> 'Vodafone',
+	'docomo'		=> 'NTT DoCoMo',
+	'o2'			=> 'O2',
 
 	// Fallback
-	'mobile'		=> "Generic Mobile",
-	'wireless'		=> "Generic Mobile",
-	'j2me'			=> "Generic Mobile",
-	'midp'			=> "Generic Mobile",
-	'cldc'			=> "Generic Mobile",
-	'up.link'		=> "Generic Mobile",
-	'up.browser'	=> "Generic Mobile",
-	'smartphone'	=> "Generic Mobile",
-	'cellphone'		=> "Generic Mobile"
+	'mobile'		=> 'Generic Mobile',
+	'wireless'		=> 'Generic Mobile',
+	'j2me'			=> 'Generic Mobile',
+	'midp'			=> 'Generic Mobile',
+	'cldc'			=> 'Generic Mobile',
+	'up.link'		=> 'Generic Mobile',
+	'up.browser'	=> 'Generic Mobile',
+	'smartphone'	=> 'Generic Mobile',
+	'cellphone'		=> 'Generic Mobile'
 );
 
 // There are hundreds of bots but these are the most common.
@@ -211,4 +215,4 @@
 );
 
 /* End of file user_agents.php */
-/* Location: ./application/config/user_agents.php */
+/* Location: ./application/config/user_agents.php */
\ No newline at end of file
diff --git a/application/controllers/welcome.php b/application/controllers/welcome.php
index 5eb0e96..1ed82d2 100644
--- a/application/controllers/welcome.php
+++ b/application/controllers/welcome.php
@@ -1,13 +1,13 @@
-<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * 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:
@@ -32,10 +32,10 @@
 	 *
 	 * Maps to the following URL
 	 * 		http://example.com/index.php/welcome
-	 *	- or -  
+	 *	- or -
 	 * 		http://example.com/index.php/welcome/index
 	 *	- or -
-	 * Since this controller is set as the default controller in 
+	 * Since this controller is set as the default controller in
 	 * config/routes.php, it's displayed at http://example.com/
 	 *
 	 * So any other public methods not prefixed with an underscore will
diff --git a/application/errors/error_404.php b/application/views/errors/error_404.php
similarity index 90%
rename from application/errors/error_404.php
rename to application/views/errors/error_404.php
index 4dd8fc4..c19bedf 100644
--- a/application/errors/error_404.php
+++ b/application/views/errors/error_404.php
@@ -1,13 +1,13 @@
-<?php
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * 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:
@@ -24,9 +24,7 @@
  * @since		Version 1.0
  * @filesource
  */
-?>
-
-<!DOCTYPE html>
+?><!DOCTYPE html>
 <html lang="en">
 <head>
 <meta charset="utf-8">
@@ -74,7 +72,7 @@
 #container {
 	margin: 10px;
 	border: 1px solid #D0D0D0;
-	-webkit-box-shadow: 0 0 8px #D0D0D0;
+	box-shadow: 0 0 8px #D0D0D0;
 }
 
 p {
diff --git a/application/errors/error_db.php b/application/views/errors/error_db.php
similarity index 90%
rename from application/errors/error_db.php
rename to application/views/errors/error_db.php
index 130ffc1..3b244e0 100644
--- a/application/errors/error_db.php
+++ b/application/views/errors/error_db.php
@@ -1,13 +1,13 @@
-<?php
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * 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:
@@ -24,9 +24,7 @@
  * @since		Version 1.0
  * @filesource
  */
-?>
-
-<!DOCTYPE html>
+?><!DOCTYPE html>
 <html lang="en">
 <head>
 <meta charset="utf-8">
@@ -74,7 +72,7 @@
 #container {
 	margin: 10px;
 	border: 1px solid #D0D0D0;
-	-webkit-box-shadow: 0 0 8px #D0D0D0;
+	box-shadow: 0 0 8px #D0D0D0;
 }
 
 p {
diff --git a/application/errors/error_general.php b/application/views/errors/error_general.php
similarity index 90%
rename from application/errors/error_general.php
rename to application/views/errors/error_general.php
index 2a844a8..c88afe1 100644
--- a/application/errors/error_general.php
+++ b/application/views/errors/error_general.php
@@ -1,13 +1,13 @@
-<?php
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * 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:
@@ -24,9 +24,7 @@
  * @since		Version 1.0
  * @filesource
  */
-?>
-
-<!DOCTYPE html>
+?><!DOCTYPE html>
 <html lang="en">
 <head>
 <meta charset="utf-8">
@@ -74,7 +72,7 @@
 #container {
 	margin: 10px;
 	border: 1px solid #D0D0D0;
-	-webkit-box-shadow: 0 0 8px #D0D0D0;
+	box-shadow: 0 0 8px #D0D0D0;
 }
 
 p {
diff --git a/application/errors/error_php.php b/application/views/errors/error_php.php
similarity index 80%
rename from application/errors/error_php.php
rename to application/views/errors/error_php.php
index 8e293cd..b76dc8a 100644
--- a/application/errors/error_php.php
+++ b/application/views/errors/error_php.php
@@ -1,13 +1,13 @@
-<?php
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * 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:
@@ -35,19 +35,22 @@
 <p>Filename: <?php echo $filepath; ?></p>
 <p>Line Number: <?php echo $line; ?></p>
 
-<?php if(defined('SHOW_DEBUG_BACKTRACE') && SHOW_DEBUG_BACKTRACE === TRUE): ?>
-	
+<?php if (defined('SHOW_DEBUG_BACKTRACE') && SHOW_DEBUG_BACKTRACE === TRUE): ?>
+
 	<p>Backtrace: </p>
 	<?php foreach(debug_backtrace() as $error): ?>
-	
-		<?php if(isset($error['file']) &&  ! stristr($error['file'], SYSDIR)): ?>
+
+		<?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>
+
 		<?php endif ?>
-	
+
 	<?php endforeach ?></p>
 
 <?php endif ?>
diff --git a/application/errors/index.html b/application/views/errors/index.html
similarity index 100%
rename from application/errors/index.html
rename to application/views/errors/index.html
diff --git a/application/views/welcome_message.php b/application/views/welcome_message.php
index acc36b6..65f62a9 100644
--- a/application/views/welcome_message.php
+++ b/application/views/welcome_message.php
@@ -1,13 +1,13 @@
-<?php
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * 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:
@@ -24,9 +24,7 @@
  * @since		Version 1.0
  * @filesource
  */
-?>
-
-<!DOCTYPE html>
+?><!DOCTYPE html>
 <html lang="en">
 <head>
 	<meta charset="utf-8">
@@ -75,7 +73,7 @@
 	#body{
 		margin: 0 15px 0 15px;
 	}
-	
+
 	p.footer{
 		text-align: right;
 		font-size: 11px;
@@ -84,7 +82,7 @@
 		padding: 0 10px 0 10px;
 		margin: 20px 0 0 0;
 	}
-	
+
 	#container{
 		margin: 10px;
 		border: 1px solid #D0D0D0;
@@ -109,7 +107,7 @@
 		<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>
 
-	<p class="footer">Page rendered in <strong>{elapsed_time}</strong> seconds. <?php echo  (ENVIRONMENT == 'development') ?  'CodeIgniter Version <strong>' . CI_VERSION . '</strong>' : '' ?></p>
+	<p class="footer">Page rendered in <strong>{elapsed_time}</strong> seconds. <?php echo  (ENVIRONMENT === 'development') ?  'CodeIgniter Version <strong>' . CI_VERSION . '</strong>' : '' ?></p>
 </div>
 
 </body>
diff --git a/composer.json b/composer.json
new file mode 100644
index 0000000..fa6dc02
--- /dev/null
+++ b/composer.json
@@ -0,0 +1,5 @@
+{
+    "require": {
+        "mikey179/vfsStream": "*"
+    }
+}
\ No newline at end of file
diff --git a/index.php b/index.php
index a378266..680dccf 100644
--- a/index.php
+++ b/index.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -42,7 +42,7 @@
  *
  * NOTE: If you change these, also change the error_reporting() code below
  */
-	define('ENVIRONMENT', 'development');
+	define('ENVIRONMENT', isset($_SERVER['CI_ENV']) ? $_SERVER['CI_ENV'] : 'development');
 /*
  *---------------------------------------------------------------
  * ERROR REPORTING
@@ -178,9 +178,11 @@
 	{
 		$system_path = realpath($system_path).'/';
 	}
-
-	// ensure there's a trailing slash
-	$system_path = rtrim($system_path, '/').'/';
+	else
+	{
+		// Ensure there's a trailing slash
+		$system_path = rtrim($system_path, '/').'/';
+	}
 
 	// Is the system path correct?
 	if ( ! is_dir($system_path))
@@ -196,10 +198,6 @@
 	// The name of THIS file
 	define('SELF', pathinfo(__FILE__, PATHINFO_BASENAME));
 
-	// The PHP file extension
-	// this global constant is deprecated.
-	define('EXT', '.php');
-
 	// Path to the system folder
 	define('BASEPATH', str_replace('\\', '/', $system_path));
 
@@ -212,6 +210,11 @@
 	// The path to the "application" folder
 	if (is_dir($application_folder))
 	{
+		if (realpath($system_path) !== FALSE)
+		{
+			$application_folder = realpath($application_folder);
+		}
+
 		define('APPPATH', $application_folder.'/');
 	}
 	else
@@ -226,21 +229,34 @@
 	}
 
 	// The path to the "views" folder
-	if (is_dir($view_folder))
+	if ( ! is_dir($view_folder))
 	{
-		define ('VIEWPATH', $view_folder .'/');
-	}
-	else
-	{
-		if ( ! is_dir(APPPATH.'views/'))
+		if ( ! empty($view_folder) && is_dir(APPPATH.$view_folder.'/'))
+		{
+			$view_folder = APPPATH.$view_folder;
+		}
+		elseif ( ! is_dir(APPPATH.'views/'))
 		{
 			header('HTTP/1.1 503 Service Unavailable.', TRUE, '503');
 			exit('Your view folder path does not appear to be set correctly. Please open the following file and correct this: '.SELF);
 		}
-
-		define ('VIEWPATH', APPPATH.'views/' );
+		else
+		{
+			$view_folder = APPPATH.'views';
+		}
 	}
 
+	if (realpath($view_folder) !== FALSE)
+	{
+		$view_folder = realpath($view_folder).'/';
+	}
+	else
+	{
+		$view_folder = rtrim($view_folder, '/').'/';
+	}
+
+	define ('VIEWPATH', $view_folder);
+
 /*
  * --------------------------------------------------------------------
  * LOAD THE BOOTSTRAP FILE
@@ -251,4 +267,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/license.rst b/license.rst
deleted file mode 100644
index 17179a9..0000000
--- a/license.rst
+++ /dev/null
@@ -1,245 +0,0 @@
-###################################
-Open Software License ("OSL") v 3.0
-###################################
-
-This Open Software License (the "License") applies to any original work of
-authorship (the "Original Work") whose owner (the "Licensor") has placed the
-following licensing notice adjacent to the copyright notice for the Original
-Work:
-
-*Licensed under the Open Software License version 3.0*
-
-
-*****************************
-1) Grant of Copyright License
-*****************************
-
-Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable
-license, for the duration of the copyright, to do the following:
-
-	*a)* to reproduce the Original Work in copies, either alone or as part of
-	a collective work;
-
-	*b)* to translate, adapt, alter, transform, modify, or arrange the
-	Original Work, thereby creating derivative works ("Derivative Works")
-	based upon the Original Work;
-
-	*c)* to distribute or communicate copies of the Original Work and
-	Derivative Works to the public, *with the proviso that copies of Original
-	Work or Derivative Works that You distribute or communicate shall be
-	licensed under this Open Software License*;
-
-	*d)* to perform the Original Work publicly; and
-
-	*e)* to display the Original Work publicly.
-
-
-**************************
-2) Grant of Patent License
-**************************
-
-Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable
-license, under patent claims owned or controlled by the Licensor that are
-embodied in the Original Work as furnished by the Licensor, for the duration
-of the patents, to make, use, sell, offer for sale, have made, and import the
-Original Work and Derivative Works.
-
-
-*******************************
-3) Grant of Source Code License
-*******************************
-
-The term "Source Code" means the preferred form of the Original Work for
-making modifications to it and all available documentation describing how to
-modify the Original Work. Licensor agrees to provide a machine-readable copy
-of the Source Code of the Original Work along with each copy of the Original
-Work that Licensor distributes. Licensor reserves the right to satisfy this
-obligation by placing a machine-readable copy of the Source Code in an
-information repository reasonably calculated to permit inexpensive and
-convenient access by You for as long as Licensor continues to distribute the
-Original Work.
-
-
-********************************
-4) Exclusions From License Grant
-********************************
-
-Neither the names of Licensor, nor the names of any contributors to the
-Original Work, nor any of their trademarks or service marks, may be used to
-endorse or promote products derived from this Original Work without express
-prior permission of the Licensor. Except as expressly stated herein, nothing
-in this License grants any license to Licensor's trademarks, copyrights,
-patents, trade secrets or any other intellectual property. No patent license
-is granted to make, use, sell, offer for sale, have made, or import
-embodiments of any patent claims other than the licensed claims defined in
-Section 2) No license is granted to the trademarks of Licensor even if such
-marks are included in the Original Work. Nothing in this License shall be
-interpreted to prohibit Licensor from licensing under terms different from
-this License any Original Work that Licensor otherwise would have a right to
-license.
-
-
-**********************
-5) External Deployment
-**********************
-
-The term "External Deployment" means the use, distribution, or communication
-of the Original Work or Derivative Works in any way such that the Original
-Work or Derivative Works may be used by anyone other than You, whether those
-works are distributed or communicated to those persons or made available as an
-application intended for use over a network. As an express condition for the
-grants of license hereunder, You must treat any External Deployment by You of
-the Original Work or a Derivative Work as a distribution under section 1(c).
-
-
-*********************
-6) Attribution Rights
-*********************
-
-You must retain, in the Source Code of any Derivative Works that You create,
-all copyright, patent, or trademark notices from the Source Code of the
-Original Work, as well as any notices of licensing and any descriptive text
-identified therein as an "Attribution Notice." You must cause the Source Code
-for any Derivative Works that You create to carry a prominent Attribution
-Notice reasonably calculated to inform recipients that You have modified the
-Original Work.
-
-
-****************************************************
-7) Warranty of Provenance and Disclaimer of Warranty
-****************************************************
-
-Licensor warrants that the copyright in and to the Original Work and the
-patent rights granted herein by Licensor are owned by the Licensor or are
-sublicensed to You under the terms of this License with the permission of the
-contributor(s) of those copyrights and patent rights. Except as expressly
-stated in the immediately preceding sentence, the Original Work is provided
-under this License on an "AS IS" BASIS and WITHOUT WARRANTY, either express or
-implied, including, without limitation, the warranties of non-infringement,
-merchantability or fitness for a particular purpose. THE ENTIRE RISK AS TO THE
-QUALITY OF THE ORIGINAL WORK IS WITH YOU. This DISCLAIMER OF WARRANTY
-constitutes an essential part of this License. No license to the Original Work
-is granted by this License except under this disclaimer.
-
-
-**************************
-8) Limitation of Liability
-**************************
-
-Under no circumstances and under no legal theory, whether in tort (including
-negligence), contract, or otherwise, shall the Licensor be liable to anyone
-for any indirect, special, incidental, or consequential damages of any
-character arising as a result of this License or the use of the Original Work
-including, without limitation, damages for loss of goodwill, work stoppage,
-computer failure or malfunction, or any and all other commercial damages or
-losses. This limitation of liability shall not apply to the extent applicable
-law prohibits such limitation.
-
-
-*****************************
-9) Acceptance and Termination
-*****************************
-
-If, at any time, You expressly assented to this License, that assent indicates
-your clear and irrevocable acceptance of this License and all of its terms and
-conditions. If You distribute or communicate copies of the Original Work or a
-Derivative Work, You must make a reasonable effort under the circumstances to
-obtain the express assent of recipients to the terms of this License. This
-License conditions your rights to undertake the activities listed in Section
-1, including your right to create Derivative Works based upon the Original
-Work, and doing so without honoring these terms and conditions is prohibited
-by copyright law and international treaty. Nothing in this License is intended
-to affect copyright exceptions and limitations (including "fair use" or "fair
-dealing"). This License shall terminate immediately and You may no longer
-exercise any of the rights granted to You by this License upon your failure to
-honor the conditions in Section 1(c).
-
-
-*********************************
-10) Termination for Patent Action
-*********************************
-
-This License shall terminate automatically and You may no longer exercise any
-of the rights granted to You by this License as of the date You commence an
-action, including a cross-claim or counterclaim, against Licensor or any
-licensee alleging that the Original Work infringes a patent. This termination
-provision shall not apply for an action alleging patent infringement by
-combinations of the Original Work with other software or hardware.
-
-
-*****************************************
-11) Jurisdiction, Venue and Governing Law
-*****************************************
-
-Any action or suit relating to this License may be brought only in the courts
-of a jurisdiction wherein the Licensor resides or in which Licensor conducts
-its primary business, and under the laws of that jurisdiction excluding its
-conflict-of-law provisions. The application of the United Nations Convention
-on Contracts for the International Sale of Goods is expressly excluded. Any
-use of the Original Work outside the scope of this License or after its
-termination shall be subject to the requirements and penalties of copyright or
-patent law in the appropriate jurisdiction. This section shall survive the
-termination of this License.
-
-
-*******************
-12) Attorneys' Fees
-*******************
-
-In any action to enforce the terms of this License or seeking damages relating
-thereto, the prevailing party shall be entitled to recover its costs and
-expenses, including, without limitation, reasonable attorneys' fees and costs
-incurred in connection with such action, including any appeal of such action.
-This section shall survive the termination of this License.
-
-
-*****************
-13) Miscellaneous
-*****************
-
-If any provision of this License is held to be unenforceable, such provision
-shall be reformed only to the extent necessary to make it enforceable.
-
-
-***************************************
-14) Definition of "You" in This License
-***************************************
-
-"You" throughout this License, whether in upper or lower case, means an
-individual or a legal entity exercising rights under, and complying with all
-of the terms of, this License. For legal entities, "You" includes any entity
-that controls, is controlled by, or is under common control with you. For
-purposes of this definition, "control" means (i) the power, direct or
-indirect, to cause the direction or management of such entity, whether by
-contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the
-outstanding shares, or (iii) beneficial ownership of such entity.
-
-
-****************
-15) Right to Use
-****************
-
-You may use the Original Work in all ways not otherwise restricted or
-conditioned by this License or by law, and Licensor promises not to interfere
-with or be responsible for such uses by You.
-
-
-********************************
-16) Modification of This License
-********************************
-
-This License is Copyright © 2005 Lawrence Rosen. Permission is granted to
-copy, distribute, or communicate this License without modification. Nothing in
-this License permits You to modify this License as applied to the Original
-Work or to Derivative Works. However, You may modify the text of this License
-and copy, distribute or communicate your modified version (the "Modified
-License") and apply it to other original works of authorship subject to the
-following conditions: (i) You may not indicate in any way that your Modified
-License is the "Open Software License" or "OSL" and you may not use those
-names in the name of your Modified License; (ii) You must replace the notice
-specified in the first paragraph above with the notice "Licensed under <insert
-your license name here>" or with a notice of your own that is not confusingly
-similar to the notice in this License; and (iii) You may not claim that your
-original works are open source software unless your Modified License has been
-approved by Open Source Initiative (OSI) and You comply with its license
-review and certification process.
\ No newline at end of file
diff --git a/phpdoc.dist.xml b/phpdoc.dist.xml
new file mode 100644
index 0000000..6dc58c2
--- /dev/null
+++ b/phpdoc.dist.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<phpdoc>
+	<title>CodeIgniter v3.0.0 API</title>
+    <parser>
+        <target>./api/</target>
+    </parser>
+    <transformer>
+        <target>./api/</target>
+    </transformer>
+    <files>
+        <directory>./system</directory>
+    </files>
+
+    <logging>
+        <level>warn</level>
+        <paths>
+            <default>./api/log/{DATE}.log</default>
+            <errors>./api/{DATE}.errors.log</errors>
+        </paths>
+    </logging>
+</phpdoc>
\ No newline at end of file
diff --git a/readme.rst b/readme.rst
index 26e04ce..7b718fe 100644
--- a/readme.rst
+++ b/readme.rst
@@ -23,13 +23,13 @@
 **************************
 
 You can find a list of all changes for each release in the `user
-guide change log <https://github.com/EllisLab/CodeIgniter/blob/develop/user_guide/changelog.html>`_.
+guide change log <https://github.com/EllisLab/CodeIgniter/blob/develop/user_guide_src/source/changelog.rst>`_.
 
 *******************
 Server Requirements
 *******************
 
--  PHP version 5.1.6 or newer.
+-  PHP version 5.2.4 or newer.
 
 ************
 Installation
@@ -90,9 +90,9 @@
 Compatibility
 =============
 
-CodeIgniter is compatible with PHP 5.1.6 so all code supplied must stick to
-this requirement. If PHP 5.2 or 5.3 functions or features are used then there
-must be a fallback for PHP 5.1.6.
+CodeIgniter is compatible with PHP 5.2.4 so all code supplied must stick to
+this requirement. If PHP 5.3 or 5.4 functions or features are used then there
+must be a fallback for PHP 5.2.4.
 
 Branching
 =========
@@ -183,8 +183,6 @@
 
 -  `User Guide <http://codeigniter.com/user_guide/>`_
 -  `Community Forums <http://codeigniter.com/forums/>`_
--  `User
-   Voice <http://codeigniter.uservoice.com/forums/40508-codeigniter-reactor>`_
 -  `Community Wiki <http://codeigniter.com/wiki/>`_
 -  `Community IRC <http://codeigniter.com/irc/>`_
 
@@ -193,4 +191,4 @@
 ***************
 
 The EllisLab team and The Reactor Engineers would like to thank all the
-contributors to the CodeIgniter project and you, the CodeIgniter user.
\ No newline at end of file
+contributors to the CodeIgniter project and you, the CodeIgniter user.
diff --git a/system/core/Benchmark.php b/system/core/Benchmark.php
old mode 100755
new mode 100644
index f4dfd3d..2fabdf4
--- a/system/core/Benchmark.php
+++ b/system/core/Benchmark.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -25,13 +25,11 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * CodeIgniter Benchmark Class
  *
  * This class enables you to mark points and calculate the time difference
- * between them.  Memory consumption can also be displayed.
+ * between them. Memory consumption can also be displayed.
  *
  * @package		CodeIgniter
  * @subpackage	Libraries
@@ -46,7 +44,7 @@
 	 *
 	 * @var array
 	 */
-	public $marker = array();
+	public $marker =	array();
 
 	// --------------------------------------------------------------------
 
@@ -61,7 +59,7 @@
 	 */
 	public function mark($name)
 	{
-		$this->marker[$name] = microtime();
+		$this->marker[$name] = microtime(TRUE);
 	}
 
 	// --------------------------------------------------------------------
@@ -81,7 +79,7 @@
 	 */
 	public function elapsed_time($point1 = '', $point2 = '', $decimals = 4)
 	{
-		if ($point1 == '')
+		if ($point1 === '')
 		{
 			return '{elapsed_time}';
 		}
@@ -93,13 +91,10 @@
 
 		if ( ! isset($this->marker[$point2]))
 		{
-			$this->marker[$point2] = microtime();
+			$this->marker[$point2] = microtime(TRUE);
 		}
 
-		list($sm, $ss) = explode(' ', $this->marker[$point1]);
-		list($em, $es) = explode(' ', $this->marker[$point2]);
-
-		return number_format(($em + $es) - ($sm + $ss), $decimals);
+		return number_format($this->marker[$point2] - $this->marker[$point1], $decimals);
 	}
 
 	// --------------------------------------------------------------------
@@ -122,4 +117,4 @@
 }
 
 /* End of file Benchmark.php */
-/* Location: ./system/core/Benchmark.php */
+/* Location: ./system/core/Benchmark.php */
\ No newline at end of file
diff --git a/system/core/CodeIgniter.php b/system/core/CodeIgniter.php
old mode 100755
new mode 100644
index 7af3c48..8159b19
--- a/system/core/CodeIgniter.php
+++ b/system/core/CodeIgniter.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -25,15 +25,13 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * System Initialization File
  *
  * Loads the base classes and executes the request.
  *
  * @package		CodeIgniter
- * @subpackage	codeigniter
+ * @subpackage	CodeIgniter
  * @category	Front-controller
  * @author		EllisLab Dev Team
  * @link		http://codeigniter.com/user_guide/
@@ -42,7 +40,7 @@
 /**
  * CodeIgniter Version
  *
- * @var string
+ * @var	string
  *
  */
 	define('CI_VERSION', '3.0-dev');
@@ -75,9 +73,9 @@
  */
 	set_error_handler('_exception_handler');
 
-	if ( ! is_php('5.3'))
+	if ( ! is_php('5.4'))
 	{
-		@set_magic_quotes_runtime(0); // Kill magic quotes
+		@ini_set('magic_quotes_runtime', 0); // Kill magic quotes
 	}
 
 /*
@@ -96,24 +94,13 @@
  * Note: Since the config file data is cached it doesn't
  * hurt to load it here.
  */
-	if (isset($assign_to_config['subclass_prefix']) && $assign_to_config['subclass_prefix'] != '')
+	if ( ! empty($assign_to_config['subclass_prefix']))
 	{
 		get_config(array('subclass_prefix' => $assign_to_config['subclass_prefix']));
 	}
 
 /*
  * ------------------------------------------------------
- *  Set a liberal script execution time limit
- * ------------------------------------------------------
- */
-	if (function_exists('set_time_limit') && @ini_get('safe_mode') == 0
-		&& php_sapi_name() !== 'cli') // Do not override the Time Limit value if running from Command Line
-	{
-		@set_time_limit(300);
-	}
-
-/*
- * ------------------------------------------------------
  *  Start the timer... tick tock tick tock...
  * ------------------------------------------------------
  */
@@ -133,7 +120,7 @@
  *  Is there a "pre_system" hook?
  * ------------------------------------------------------
  */
-	$EXT->_call_hook('pre_system');
+	$EXT->call_hook('pre_system');
 
 /*
  * ------------------------------------------------------
@@ -155,7 +142,7 @@
  *
  * Note: Order here is rather important as the UTF-8
  * class needs to be used very early on, but it cannot
- * properly determine if UTf-8 can be supported until
+ * properly determine if UTF-8 can be supported until
  * after the Config class is instantiated.
  *
  */
@@ -194,8 +181,8 @@
  *	Is there a valid cache file? If so, we're done...
  * ------------------------------------------------------
  */
-	if ($EXT->_call_hook('cache_override') === FALSE
-		&& $OUT->_display_cache($CFG, $URI) == TRUE)
+	if ($EXT->call_hook('cache_override') === FALSE
+		&& $OUT->_display_cache($CFG, $URI) === TRUE)
 	{
 		exit;
 	}
@@ -230,6 +217,13 @@
 	// Load the base controller class
 	require BASEPATH.'core/Controller.php';
 
+	/**
+	 * Reference to the CI_Controller method.
+	 *
+	 * Returns current CI instance object
+	 *
+	 * @return object
+	 */
 	function &get_instance()
 	{
 		return CI_Controller::get_instance();
@@ -275,12 +269,12 @@
 		{
 			$x = explode('/', $RTR->routes['404_override'], 2);
 			$class = $x[0];
-			$method = (isset($x[1]) ? $x[1] : 'index');
+			$method = isset($x[1]) ? $x[1] : 'index';
 			if ( ! class_exists($class))
 			{
 				if ( ! file_exists(APPPATH.'controllers/'.$class.'.php'))
 				{
-					show_404("{$class}/{$method}");
+					show_404($class.'/'.$method);
 				}
 
 				include_once(APPPATH.'controllers/'.$class.'.php');
@@ -288,7 +282,7 @@
 		}
 		else
 		{
-			show_404("{$class}/{$method}");
+			show_404($class.'/'.$method);
 		}
 	}
 
@@ -297,7 +291,7 @@
  *  Is there a "pre_controller" hook?
  * ------------------------------------------------------
  */
-	$EXT->_call_hook('pre_controller');
+	$EXT->call_hook('pre_controller');
 
 /*
  * ------------------------------------------------------
@@ -314,7 +308,7 @@
  *  Is there a "post_controller_constructor" hook?
  * ------------------------------------------------------
  */
-	$EXT->_call_hook('post_controller_constructor');
+	$EXT->call_hook('post_controller_constructor');
 
 /*
  * ------------------------------------------------------
@@ -337,12 +331,12 @@
 			{
 				$x = explode('/', $RTR->routes['404_override'], 2);
 				$class = $x[0];
-				$method = (isset($x[1]) ? $x[1] : 'index');
+				$method = isset($x[1]) ? $x[1] : 'index';
 				if ( ! class_exists($class))
 				{
 					if ( ! file_exists(APPPATH.'controllers/'.$class.'.php'))
 					{
-						show_404("{$class}/{$method}");
+						show_404($class.'/'.$method);
 					}
 
 					include_once(APPPATH.'controllers/'.$class.'.php');
@@ -352,7 +346,7 @@
 			}
 			else
 			{
-				show_404("{$class}/{$method}");
+				show_404($class.'/'.$method);
 			}
 		}
 
@@ -369,14 +363,14 @@
  *  Is there a "post_controller" hook?
  * ------------------------------------------------------
  */
-	$EXT->_call_hook('post_controller');
+	$EXT->call_hook('post_controller');
 
 /*
  * ------------------------------------------------------
  *  Send the final rendered output to the browser
  * ------------------------------------------------------
  */
-	if ($EXT->_call_hook('display_override') === FALSE)
+	if ($EXT->call_hook('display_override') === FALSE)
 	{
 		$OUT->_display();
 	}
@@ -386,17 +380,7 @@
  *  Is there a "post_system" hook?
  * ------------------------------------------------------
  */
-	$EXT->_call_hook('post_system');
-
-/*
- * ------------------------------------------------------
- *  Close the DB connection if one exists
- * ------------------------------------------------------
- */
-	if (class_exists('CI_DB') && isset($CI->db))
-	{
-		$CI->db->close();
-	}
+	$EXT->call_hook('post_system');
 
 /* End of file CodeIgniter.php */
-/* Location: ./system/core/CodeIgniter.php */
+/* Location: ./system/core/CodeIgniter.php */
\ No newline at end of file
diff --git a/system/core/Common.php b/system/core/Common.php
index 225227d..1708653 100644
--- a/system/core/Common.php
+++ b/system/core/Common.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -25,15 +25,13 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * Common Functions
  *
  * Loads the base classes and executes the request.
  *
  * @package		CodeIgniter
- * @subpackage	codeigniter
+ * @subpackage	CodeIgniter
  * @category	Common Functions
  * @author		EllisLab Dev Team
  * @link		http://codeigniter.com/user_guide/
@@ -41,26 +39,25 @@
 
 // ------------------------------------------------------------------------
 
-/**
-* Determines if the current version of PHP is greater then the supplied value
-*
-* Since there are a few places where we conditionally test for PHP > 5
-* we'll set a static variable.
-*
-* @access	public
-* @param	string
-* @return	bool	TRUE if the current version is $version or higher
-*/
 if ( ! function_exists('is_php'))
 {
-	function is_php($version = '5.0.0')
+	/**
+	 * Determines if the current version of PHP is greater then the supplied value
+	 *
+	 * Since there are a few places where we conditionally test for PHP > 5.3
+	 * we'll set a static variable.
+	 *
+	 * @param	string
+	 * @return	bool	TRUE if the current version is $version or higher
+	 */
+	function is_php($version = '5.3.0')
 	{
 		static $_is_php;
-		$version = (string)$version;
+		$version = (string) $version;
 
 		if ( ! isset($_is_php[$version]))
 		{
-			$_is_php[$version] = (version_compare(PHP_VERSION, $version) < 0) ? FALSE : TRUE;
+			$_is_php[$version] = (version_compare(PHP_VERSION, $version) >= 0);
 		}
 
 		return $_is_php[$version];
@@ -69,22 +66,22 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Tests for file writability
- *
- * is_writable() returns TRUE on Windows servers when you really can't write to
- * the file, based on the read-only attribute. is_writable() is also unreliable
- * on Unix servers if safe_mode is on.
- *
- * @access	public
- * @return	void
- */
 if ( ! function_exists('is_really_writable'))
 {
+	/**
+	 * Tests for file writability
+	 *
+	 * is_writable() returns TRUE on Windows servers when you really can't write to
+	 * the file, based on the read-only attribute. is_writable() is also unreliable
+	 * on Unix servers if safe_mode is on.
+	 *
+	 * @param	string
+	 * @return	void
+	 */
 	function is_really_writable($file)
 	{
 		// If we're on a Unix server with safe_mode off we call is_writable
-		if (DIRECTORY_SEPARATOR === '/' AND @ini_get('safe_mode') == FALSE)
+		if (DIRECTORY_SEPARATOR === '/' && (bool) @ini_get('safe_mode') === FALSE)
 		{
 			return is_writable($file);
 		}
@@ -117,21 +114,20 @@
 
 // ------------------------------------------------------------------------
 
-/**
-* Class registry
-*
-* This function acts as a singleton.  If the requested class does not
-* exist it is instantiated and set to a static variable.  If it has
-* previously been instantiated the variable is returned.
-*
-* @access	public
-* @param	string	the class name being requested
-* @param	string	the directory where the class should be found
-* @param	string	the class name prefix
-* @return	object
-*/
 if ( ! function_exists('load_class'))
 {
+	/**
+	 * Class registry
+	 *
+	 * This function acts as a singleton. If the requested class does not
+	 * exist it is instantiated and set to a static variable. If it has
+	 * previously been instantiated the variable is returned.
+	 *
+	 * @param	string	the class name being requested
+	 * @param	string	the directory where the class should be found
+	 * @param	string	the class name prefix
+	 * @return	object
+	 */
 	function &load_class($class, $directory = 'libraries', $prefix = 'CI_')
 	{
 		static $_classes = array();
@@ -191,20 +187,20 @@
 
 // --------------------------------------------------------------------
 
-/**
-* Keeps track of which libraries have been loaded.  This function is
-* called by the load_class() function above
-*
-* @access	public
-* @return	array
-*/
 if ( ! function_exists('is_loaded'))
 {
+	/**
+	 * Keeps track of which libraries have been loaded. This function is
+	 * called by the load_class() function above
+	 *
+	 * @param	string
+	 * @return	array
+	 */
 	function &is_loaded($class = '')
 	{
 		static $_is_loaded = array();
 
-		if ($class != '')
+		if ($class !== '')
 		{
 			$_is_loaded[strtolower($class)] = $class;
 		}
@@ -215,17 +211,17 @@
 
 // ------------------------------------------------------------------------
 
-/**
-* Loads the main config.php file
-*
-* This function lets us grab the config file even if the Config class
-* hasn't been instantiated yet
-*
-* @access	private
-* @return	array
-*/
 if ( ! function_exists('get_config'))
 {
+	/**
+	 * Loads the main config.php file
+	 *
+	 * This function lets us grab the config file even if the Config class
+	 * hasn't been instantiated yet
+	 *
+	 * @param	array
+	 * @return	array
+	 */
 	function &get_config($replace = array())
 	{
 		static $_config;
@@ -235,21 +231,25 @@
 			return $_config[0];
 		}
 
-		// Is the config file in the environment folder?
-		if ( ! defined('ENVIRONMENT') OR ! file_exists($file_path = APPPATH.'config/'.ENVIRONMENT.'/config.php'))
+		$file_path = APPPATH.'config/config.php';
+		$found = FALSE;
+		if (file_exists($file_path))
 		{
-			$file_path = APPPATH.'config/config.php';
+			$found = TRUE;
+			require($file_path);
 		}
 
-		// Fetch the config file
-		if ( ! file_exists($file_path))
+		// Is the config file in the environment folder?
+		if (defined('ENVIRONMENT') && file_exists($file_path = APPPATH.'config/'.ENVIRONMENT.'/config.php'))
+		{
+			require($file_path);
+		}
+		elseif ( ! $found)
 		{
 			set_status_header(503);
 			exit('The configuration file does not exist.');
 		}
 
-		require($file_path);
-
 		// Does the $config array exist in the file?
 		if ( ! isset($config) OR ! is_array($config))
 		{
@@ -275,14 +275,14 @@
 
 // ------------------------------------------------------------------------
 
-/**
-* Returns the specified config item
-*
-* @access	public
-* @return	mixed
-*/
 if ( ! function_exists('config_item'))
 {
+	/**
+	 * Returns the specified config item
+	 *
+	 * @param	string
+	 * @return	mixed
+	 */
 	function config_item($item)
 	{
 		static $_config_item = array();
@@ -304,20 +304,48 @@
 
 // ------------------------------------------------------------------------
 
-/**
-* Error Handler
-*
-* This function lets us invoke the exception class and
-* display errors using the standard error template located
-* in application/errors/errors.php
-* This function will send the error page directly to the
-* browser and exit.
-*
-* @access	public
-* @return	void
-*/
+if ( ! function_exists('get_mimes'))
+{
+	/**
+	 * Returns the MIME types array from config/mimes.php
+	 *
+	 * @return	array
+	 */
+	function &get_mimes()
+	{
+		static $_mimes = array();
+
+		if (defined('ENVIRONMENT') && is_file(APPPATH.'config/'.ENVIRONMENT.'/mimes.php'))
+		{
+			$_mimes = include(APPPATH.'config/'.ENVIRONMENT.'/mimes.php');
+		}
+		elseif (is_file(APPPATH.'config/mimes.php'))
+		{
+			$_mimes = include(APPPATH.'config/mimes.php');
+		}
+
+		return $_mimes;
+	}
+}
+
+// ------------------------------------------------------------------------
+
 if ( ! function_exists('show_error'))
 {
+	/**
+	 * Error Handler
+	 *
+	 * This function lets us invoke the exception class and
+	 * display errors using the standard error template located
+	 * in application/errors/errors.php
+	 * This function will send the error page directly to the
+	 * browser and exit.
+	 *
+	 * @param	string
+	 * @param	int
+	 * @param	string
+	 * @return	void
+	 */
 	function show_error($message, $status_code = 500, $heading = 'An Error Was Encountered')
 	{
 		$_error =& load_class('Exceptions', 'core');
@@ -328,18 +356,19 @@
 
 // ------------------------------------------------------------------------
 
-/**
-* 404 Page Handler
-*
-* This function is similar to the show_error() function above
-* However, instead of the standard error template it displays
-* 404 errors.
-*
-* @access	public
-* @return	void
-*/
 if ( ! function_exists('show_404'))
 {
+	/**
+	 * 404 Page Handler
+	 *
+	 * This function is similar to the show_error() function above
+	 * However, instead of the standard error template it displays
+	 * 404 errors.
+	 *
+	 * @param	string
+	 * @param	bool
+	 * @return	void
+	 */
 	function show_404($page = '', $log_error = TRUE)
 	{
 		$_error =& load_class('Exceptions', 'core');
@@ -350,22 +379,24 @@
 
 // ------------------------------------------------------------------------
 
-/**
-* Error Logging Interface
-*
-* We use this as a simple mechanism to access the logging
-* class and send messages to be logged.
-*
-* @access	public
-* @return	void
-*/
 if ( ! function_exists('log_message'))
 {
+	/**
+	 * Error Logging Interface
+	 *
+	 * We use this as a simple mechanism to access the logging
+	 * class and send messages to be logged.
+	 *
+	 * @param	string
+	 * @param	string
+	 * @param	bool
+	 * @return	void
+	 */
 	function log_message($level = 'error', $message, $php_error = FALSE)
 	{
 		static $_log;
 
-		if (config_item('log_threshold') == 0)
+		if (config_item('log_threshold') === 0)
 		{
 			return;
 		}
@@ -377,134 +408,125 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Set HTTP Status Header
- *
- * @access	public
- * @param	int		the status code
- * @param	string
- * @return	void
- */
 if ( ! function_exists('set_status_header'))
 {
+	/**
+	 * Set HTTP Status Header
+	 *
+	 * @param	int	the status code
+	 * @param	string
+	 * @return	void
+	 */
 	function set_status_header($code = 200, $text = '')
 	{
 		$stati = array(
-					200	=> 'OK',
-					201	=> 'Created',
-					202	=> 'Accepted',
-					203	=> 'Non-Authoritative Information',
-					204	=> 'No Content',
-					205	=> 'Reset Content',
-					206	=> 'Partial Content',
+			200	=> 'OK',
+			201	=> 'Created',
+			202	=> 'Accepted',
+			203	=> 'Non-Authoritative Information',
+			204	=> 'No Content',
+			205	=> 'Reset Content',
+			206	=> 'Partial Content',
 
-					300	=> 'Multiple Choices',
-					301	=> 'Moved Permanently',
-					302	=> 'Found',
-					304	=> 'Not Modified',
-					305	=> 'Use Proxy',
-					307	=> 'Temporary Redirect',
+			300	=> 'Multiple Choices',
+			301	=> 'Moved Permanently',
+			302	=> 'Found',
+			304	=> 'Not Modified',
+			305	=> 'Use Proxy',
+			307	=> 'Temporary Redirect',
 
-					400	=> 'Bad Request',
-					401	=> 'Unauthorized',
-					403	=> 'Forbidden',
-					404	=> 'Not Found',
-					405	=> 'Method Not Allowed',
-					406	=> 'Not Acceptable',
-					407	=> 'Proxy Authentication Required',
-					408	=> 'Request Timeout',
-					409	=> 'Conflict',
-					410	=> 'Gone',
-					411	=> 'Length Required',
-					412	=> 'Precondition Failed',
-					413	=> 'Request Entity Too Large',
-					414	=> 'Request-URI Too Long',
-					415	=> 'Unsupported Media Type',
-					416	=> 'Requested Range Not Satisfiable',
-					417	=> 'Expectation Failed',
-					422	=> 'Unprocessable Entity',
+			400	=> 'Bad Request',
+			401	=> 'Unauthorized',
+			403	=> 'Forbidden',
+			404	=> 'Not Found',
+			405	=> 'Method Not Allowed',
+			406	=> 'Not Acceptable',
+			407	=> 'Proxy Authentication Required',
+			408	=> 'Request Timeout',
+			409	=> 'Conflict',
+			410	=> 'Gone',
+			411	=> 'Length Required',
+			412	=> 'Precondition Failed',
+			413	=> 'Request Entity Too Large',
+			414	=> 'Request-URI Too Long',
+			415	=> 'Unsupported Media Type',
+			416	=> 'Requested Range Not Satisfiable',
+			417	=> 'Expectation Failed',
+			422	=> 'Unprocessable Entity',
 
-					500	=> 'Internal Server Error',
-					501	=> 'Not Implemented',
-					502	=> 'Bad Gateway',
-					503	=> 'Service Unavailable',
-					504	=> 'Gateway Timeout',
-					505	=> 'HTTP Version Not Supported'
-			);
+			500	=> 'Internal Server Error',
+			501	=> 'Not Implemented',
+			502	=> 'Bad Gateway',
+			503	=> 'Service Unavailable',
+			504	=> 'Gateway Timeout',
+			505	=> 'HTTP Version Not Supported'
+		);
 
 		if ($code == '' OR ! is_numeric($code))
 		{
 			show_error('Status codes must be numeric', 500);
 		}
-
-		if (isset($stati[$code]) AND $text == '')
+		elseif (isset($stati[$code]) && $text === '')
 		{
 			$text = $stati[$code];
 		}
 
-		if ($text == '')
+		if ($text === '')
 		{
 			show_error('No status text available. Please check your status code number or supply your own message text.', 500);
 		}
 
-		$server_protocol = (isset($_SERVER['SERVER_PROTOCOL'])) ? $_SERVER['SERVER_PROTOCOL'] : FALSE;
+		$server_protocol = isset($_SERVER['SERVER_PROTOCOL']) ? $_SERVER['SERVER_PROTOCOL'] : FALSE;
 
 		if (strpos(php_sapi_name(), 'cgi') === 0)
 		{
-			header("Status: {$code} {$text}", TRUE);
+			header('Status: '.$code.' '.$text, TRUE);
 		}
-		elseif ($server_protocol == 'HTTP/1.1' OR $server_protocol == 'HTTP/1.0')
+		elseif ($server_protocol === 'HTTP/1.0')
 		{
-			header($server_protocol." {$code} {$text}", TRUE, $code);
+			header('HTTP/1.0 '.$code.' '.$text, TRUE, $code);
 		}
 		else
 		{
-			header("HTTP/1.1 {$code} {$text}", TRUE, $code);
+			header('HTTP/1.1 '.$code.' '.$text, TRUE, $code);
 		}
 	}
 }
 
 // --------------------------------------------------------------------
 
-/**
-* 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
-* 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.
-*
-* @access	private
-* @return	void
-*/
 if ( ! function_exists('_exception_handler'))
 {
+	/**
+	 * 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
+	 * 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
+	 * @return	void
+	 */
 	function _exception_handler($severity, $message, $filepath, $line)
 	{
-		 // We don't bother with "strict" notices since they tend to fill up
-		 // the log file with excess information that isn't normally very helpful.
-		 // For example, if you are running PHP 5 and you use version 4 style
-		 // class functions (without prefixes like "public", "private", etc.)
-		 // you'll get notices telling you that these have been deprecated.
-		if ($severity == E_STRICT)
-		{
-			return;
-		}
-
 		$_error =& load_class('Exceptions', 'core');
 
 		// Should we display the error? We'll get the current error_reporting
 		// level and add its bits with the severity bits to find out.
-		if (($severity & error_reporting()) == $severity)
+		if (($severity & error_reporting()) === $severity)
 		{
 			$_error->show_php_error($severity, $message, $filepath, $line);
 		}
 
-		// Should we log the error?  No?  We're done...
-		if (config_item('log_threshold') == 0)
+		// Should we log the error? No? We're done...
+		if (config_item('log_threshold') === 0)
 		{
 			return;
 		}
@@ -515,18 +537,18 @@
 
 // --------------------------------------------------------------------
 
-/**
- * Remove Invisible Characters
- *
- * This prevents sandwiching null characters
- * between ascii characters, like Java\0script.
- *
- * @access	public
- * @param	string
- * @return	string
- */
 if ( ! function_exists('remove_invisible_characters'))
 {
+	/**
+	 * Remove Invisible Characters
+	 *
+	 * This prevents sandwiching null characters
+	 * between ascii characters, like Java\0script.
+	 *
+	 * @param	string
+	 * @param	bool
+	 * @return	string
+	 */
 	function remove_invisible_characters($str, $url_encoded = TRUE)
 	{
 		$non_displayables = array();
@@ -553,27 +575,21 @@
 
 // ------------------------------------------------------------------------
 
-/**
-* Returns HTML escaped variable
-*
-* @access	public
-* @param	mixed
-* @return	mixed
-*/
 if ( ! function_exists('html_escape'))
 {
+	/**
+	 * Returns HTML escaped variable
+	 *
+	 * @param	mixed
+	 * @return	mixed
+	 */
 	function html_escape($var)
 	{
-		if (is_array($var))
-		{
-			return array_map('html_escape', $var);
-		}
-		else
-		{
-			return htmlspecialchars($var, ENT_QUOTES, config_item('charset'));
-		}
+		return is_array($var)
+			? array_map('html_escape', $var)
+			: htmlspecialchars($var, ENT_QUOTES, config_item('charset'));
 	}
 }
 
 /* End of file Common.php */
-/* Location: ./system/core/Common.php */
+/* Location: ./system/core/Common.php */
\ No newline at end of file
diff --git a/system/core/Config.php b/system/core/Config.php
old mode 100755
new mode 100644
index 6841743..3de1bcb
--- a/system/core/Config.php
+++ b/system/core/Config.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * CodeIgniter Config Class
  *
@@ -45,30 +43,27 @@
 	 *
 	 * @var array
 	 */
-	public $config = array();
+	public $config =	array();
+
 	/**
 	 * List of all loaded config files
 	 *
 	 * @var array
 	 */
-	public $is_loaded = array();
+	public $is_loaded =	array();
+
 	/**
 	 * List of paths to search when trying to load a config file.
 	 * This must be public as it's used by the Loader class.
 	 *
 	 * @var array
 	 */
-	public $_config_paths = array(APPPATH);
+	public $_config_paths =	array(APPPATH);
 
 	/**
 	 * Constructor
 	 *
 	 * Sets the $config data from the primary config.php file as a class variable
-	 *
-	 * @param   string	the config file name
-	 * @param   boolean  if configuration values should be loaded into their own section
-	 * @param   boolean  true if errors should just return false, false if an error message should be displayed
-	 * @return  boolean  if the file was successfully loaded or not
 	 */
 	public function __construct()
 	{
@@ -76,13 +71,13 @@
 		log_message('debug', 'Config Class Initialized');
 
 		// Set the base_url automatically if none was provided
-		if ($this->config['base_url'] == '')
+		if (empty($this->config['base_url']))
 		{
 			if (isset($_SERVER['HTTP_HOST']))
 			{
-				$base_url = ! empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) !== 'off' ? 'https' : 'http';
-				$base_url .= '://'. $_SERVER['HTTP_HOST']
-					. str_replace(basename($_SERVER['SCRIPT_NAME']), '', $_SERVER['SCRIPT_NAME']);
+				$base_url = ( ! empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) !== 'off') ? 'https' : 'http';
+				$base_url .= '://'.$_SERVER['HTTP_HOST']
+					.str_replace(basename($_SERVER['SCRIPT_NAME']), '', $_SERVER['SCRIPT_NAME']);
 			}
 			else
 			{
@@ -99,13 +94,13 @@
 	 * Load Config File
 	 *
 	 * @param	string	the config file name
-	 * @param	boolean	if configuration values should be loaded into their own section
-	 * @param	boolean	true if errors should just return false, false if an error message should be displayed
-	 * @return	boolean	if the file was loaded correctly
+	 * @param	bool	if configuration values should be loaded into their own section
+	 * @param	bool	true if errors should just return false, false if an error message should be displayed
+	 * @return	bool	if the file was loaded correctly
 	 */
 	public function load($file = '', $use_sections = FALSE, $fail_gracefully = FALSE)
 	{
-		$file = ($file == '') ? 'config' : str_replace('.php', '', $file);
+		$file = ($file === '') ? 'config' : str_replace('.php', '', $file);
 		$found = $loaded = FALSE;
 
 		foreach ($this->_config_paths as $path)
@@ -188,10 +183,8 @@
 	/**
 	 * Fetch a config file item
 	 *
-	 *
 	 * @param	string	the config item name
 	 * @param	string	the index name
-	 * @param	bool
 	 * @return	string
 	 */
 	public function item($item, $index = '')
@@ -210,7 +203,6 @@
 	 * Fetch a config file item - adds slash after item (if item is not empty)
 	 *
 	 * @param	string	the config item name
-	 * @param	bool
 	 * @return	string
 	 */
 	public function slash_item($item)
@@ -219,7 +211,7 @@
 		{
 			return FALSE;
 		}
-		elseif (trim($this->config[$item]) == '')
+		elseif (trim($this->config[$item]) === '')
 		{
 			return '';
 		}
@@ -238,14 +230,14 @@
 	 */
 	public function site_url($uri = '')
 	{
-		if ($uri == '')
+		if ($uri === '')
 		{
 			return $this->slash_item('base_url').$this->item('index_page');
 		}
 
-		if ($this->item('enable_query_strings') == FALSE)
+		if ($this->item('enable_query_strings') === FALSE)
 		{
-			$suffix = ($this->item('url_suffix') == FALSE) ? '' : $this->item('url_suffix');
+			$suffix = ($this->item('url_suffix') === FALSE) ? '' : $this->item('url_suffix');
 			return $this->slash_item('base_url').$this->slash_item('index_page').$this->_uri_string($uri).$suffix;
 		}
 		else
@@ -260,8 +252,8 @@
 	 * Base URL
 	 * Returns base_url [. uri_string]
 	 *
-	 * @param string $uri
-	 * @return string
+	 * @param	string	$uri
+	 * @return	string
 	 */
 	public function base_url($uri = '')
 	{
@@ -273,12 +265,12 @@
 	/**
 	 * Build URI string for use in Config::site_url() and Config::base_url()
 	 *
-	 * @param  mixed $uri
-	 * @return string
+	 * @param	mixed	$uri
+	 * @return	string
 	 */
 	protected function _uri_string($uri)
 	{
-		if ($this->item('enable_query_strings') == FALSE)
+		if ($this->item('enable_query_strings') === FALSE)
 		{
 			if (is_array($uri))
 			{
@@ -351,7 +343,8 @@
 			}
 		}
 	}
+
 }
 
 /* End of file Config.php */
-/* Location: ./system/core/Config.php */
+/* Location: ./system/core/Config.php */
\ No newline at end of file
diff --git a/system/core/Controller.php b/system/core/Controller.php
index 0dc1317..4914148 100644
--- a/system/core/Controller.php
+++ b/system/core/Controller.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * CodeIgniter Application Controller Class
  *
@@ -41,8 +39,18 @@
  */
 class CI_Controller {
 
+	/**
+	 * Reference to the global CI instance
+	 *
+	 * @var	object
+	 */
 	private static $instance;
 
+	/**
+	 * Set up controller properties and methods
+	 *
+	 * @return	void
+	 */
 	public function __construct()
 	{
 		self::$instance =& $this;
@@ -60,11 +68,17 @@
 		log_message('debug', 'Controller Class Initialized');
 	}
 
+	/**
+	 * Return the CI object
+	 *
+	 * @return	object
+	 */
 	public static function &get_instance()
 	{
 		return self::$instance;
 	}
+
 }
 
 /* End of file Controller.php */
-/* Location: ./system/core/Controller.php */
+/* Location: ./system/core/Controller.php */
\ No newline at end of file
diff --git a/system/core/Exceptions.php b/system/core/Exceptions.php
old mode 100755
new mode 100644
index bf99012..8c32085
--- a/system/core/Exceptions.php
+++ b/system/core/Exceptions.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * Exceptions Class
  *
@@ -38,39 +36,38 @@
  */
 class CI_Exceptions {
 
-	public $action;
-	public $severity;
-	public $message;
-	public $filename;
-	public $line;
-
 	/**
 	 * Nesting level of the output buffering mechanism
 	 *
-	 * @var int
+	 * @var	int
 	 */
 	public $ob_level;
 
 	/**
 	 * List if available error levels
 	 *
-	 * @var array
+	 * @var	array
 	 */
 	public $levels = array(
-				E_ERROR			=>	'Error',
-				E_WARNING		=>	'Warning',
-				E_PARSE			=>	'Parsing Error',
-				E_NOTICE		=>	'Notice',
-				E_CORE_ERROR		=>	'Core Error',
-				E_CORE_WARNING		=>	'Core Warning',
-				E_COMPILE_ERROR		=>	'Compile Error',
-				E_COMPILE_WARNING	=>	'Compile Warning',
-				E_USER_ERROR		=>	'User Error',
-				E_USER_WARNING		=>	'User Warning',
-				E_USER_NOTICE		=>	'User Notice',
-				E_STRICT		=>	'Runtime Notice'
-			);
+		E_ERROR			=>	'Error',
+		E_WARNING		=>	'Warning',
+		E_PARSE			=>	'Parsing Error',
+		E_NOTICE		=>	'Notice',
+		E_CORE_ERROR		=>	'Core Error',
+		E_CORE_WARNING		=>	'Core Warning',
+		E_COMPILE_ERROR		=>	'Compile Error',
+		E_COMPILE_WARNING	=>	'Compile Warning',
+		E_USER_ERROR		=>	'User Error',
+		E_USER_WARNING		=>	'User Warning',
+		E_USER_NOTICE		=>	'User Notice',
+		E_STRICT		=>	'Runtime Notice'
+	);
 
+	/**
+	 * Initialize execption class
+	 *
+	 * @return	void
+	 */
 	public function __construct()
 	{
 		$this->ob_level = ob_get_level();
@@ -92,7 +89,7 @@
 	 */
 	public function log_exception($severity, $message, $filepath, $line)
 	{
-		$severity = ( ! isset($this->levels[$severity])) ? $severity : $this->levels[$severity];
+		$severity = isset($this->levels[$severity]) ? $this->levels[$severity] : $severity;
 		log_message('error', 'Severity: '.$severity.'  --> '.$message. ' '.$filepath.' '.$line, TRUE);
 	}
 
@@ -132,21 +129,21 @@
 	 * @param	string	the heading
 	 * @param	string	the message
 	 * @param	string	the template name
-	 * @param 	int		the status code
+	 * @param 	int	the status code
 	 * @return	string
 	 */
 	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)) ? array($message) : $message).'</p>';
+		$message = '<p>'.implode('</p><p>', is_array($message) ? $message : array($message)).'</p>';
 
 		if (ob_get_level() > $this->ob_level + 1)
 		{
 			ob_end_flush();
 		}
 		ob_start();
-		include(APPPATH.'errors/'.$template.'.php');
+		include(APPPATH.'views/errors/'.$template.'.php');
 		$buffer = ob_get_contents();
 		ob_end_clean();
 		return $buffer;
@@ -163,9 +160,9 @@
 	 * @param	string	the error line number
 	 * @return	string
 	 */
-	function show_php_error($severity, $message, $filepath, $line)
+	public function show_php_error($severity, $message, $filepath, $line)
 	{
-		$severity = ( ! isset($this->levels[$severity])) ? $severity : $this->levels[$severity];
+		$severity = isset($this->levels[$severity]) ? $this->levels[$severity] : $severity;
 		$filepath = str_replace('\\', '/', $filepath);
 
 		// For safety reasons we do not show the full file path
@@ -180,7 +177,7 @@
 			ob_end_flush();
 		}
 		ob_start();
-		include(APPPATH.'errors/'.'error_php.php');
+		include(APPPATH.'views/errors/error_php.php');
 		$buffer = ob_get_contents();
 		ob_end_clean();
 		echo $buffer;
@@ -189,4 +186,4 @@
 }
 
 /* End of file Exceptions.php */
-/* Location: ./system/core/Exceptions.php */
+/* Location: ./system/core/Exceptions.php */
\ No newline at end of file
diff --git a/system/core/Hooks.php b/system/core/Hooks.php
old mode 100755
new mode 100644
index e1ac58e..29fd882
--- a/system/core/Hooks.php
+++ b/system/core/Hooks.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * CodeIgniter Hooks Class
  *
@@ -45,46 +43,42 @@
 	 *
 	 * @var bool
 	 */
-	public $enabled		= FALSE;
+	public $enabled =	FALSE;
+
 	/**
 	 * List of all hooks set in config/hooks.php
 	 *
 	 * @var array
 	 */
-	public $hooks			= array();
+	public $hooks =	array();
+
 	/**
 	 * Determines wether hook is in progress, used to prevent infinte loops
 	 *
 	 * @var bool
 	 */
-	public $in_progress	= FALSE;
-
-	public function __construct()
-	{
-		$this->_initialize();
-		log_message('debug', 'Hooks Class Initialized');
-	}
-
-	// --------------------------------------------------------------------
+	public $in_progress	=	FALSE;
 
 	/**
 	 * Initialize the Hooks Preferences
 	 *
 	 * @return	void
 	 */
-	private function _initialize()
+	public function __construct()
 	{
 		$CFG =& load_class('Config', 'core');
 
+		log_message('debug', 'Hooks Class Initialized');
+
 		// If hooks are not enabled in the config file
 		// there is nothing else to do
-		if ($CFG->item('enable_hooks') == FALSE)
+		if ($CFG->item('enable_hooks') === FALSE)
 		{
 			return;
 		}
 
 		// Grab the "hooks" definition file.
-		if (defined('ENVIRONMENT') AND is_file(APPPATH.'config/'.ENVIRONMENT.'/hooks.php'))
+		if (defined('ENVIRONMENT') && is_file(APPPATH.'config/'.ENVIRONMENT.'/hooks.php'))
 		{
 			include(APPPATH.'config/'.ENVIRONMENT.'/hooks.php');
 		}
@@ -113,14 +107,14 @@
 	 * @param	string	the hook name
 	 * @return	mixed
 	 */
-	public function _call_hook($which = '')
+	public function call_hook($which = '')
 	{
 		if ( ! $this->enabled OR ! isset($this->hooks[$which]))
 		{
 			return FALSE;
 		}
 
-		if (isset($this->hooks[$which][0]) AND is_array($this->hooks[$which][0]))
+		if (isset($this->hooks[$which][0]) && is_array($this->hooks[$which][0]))
 		{
 			foreach ($this->hooks[$which] as $val)
 			{
@@ -158,7 +152,7 @@
 
 		// If the script being called happens to have the same
 		// hook call within it a loop can happen
-		if ($this->in_progress == TRUE)
+		if ($this->in_progress === TRUE)
 		{
 			return;
 		}
@@ -167,7 +161,7 @@
 		// Set file path
 		// -----------------------------------
 
-		if ( ! isset($data['filepath']) OR ! isset($data['filename']))
+		if ( ! isset($data['filepath'], $data['filename']))
 		{
 			return FALSE;
 		}
@@ -187,12 +181,12 @@
 		$function	= FALSE;
 		$params		= '';
 
-		if (isset($data['class']) AND $data['class'] != '')
+		if ( ! empty($data['class']))
 		{
 			$class = $data['class'];
 		}
 
-		if (isset($data['function']))
+		if ( ! empty($data['function']))
 		{
 			$function = $data['function'];
 		}
@@ -202,7 +196,7 @@
 			$params = $data['params'];
 		}
 
-		if ($class === FALSE AND $function === FALSE)
+		if ($class === FALSE && $function === FALSE)
 		{
 			return FALSE;
 		}
@@ -244,4 +238,4 @@
 }
 
 /* End of file Hooks.php */
-/* Location: ./system/core/Hooks.php */
+/* Location: ./system/core/Hooks.php */
\ No newline at end of file
diff --git a/system/core/Input.php b/system/core/Input.php
old mode 100755
new mode 100644
index 3339d97..162e40c
--- a/system/core/Input.php
+++ b/system/core/Input.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * Input Class
  *
@@ -45,51 +43,59 @@
 	 *
 	 * @var string
 	 */
-	public $ip_address				= FALSE;
+	public $ip_address =	FALSE;
+
 	/**
 	 * user agent (web browser) being used by the current user
 	 *
 	 * @var string
 	 */
-	public $user_agent				= FALSE;
+	public $user_agent =	FALSE;
+
 	/**
 	 * If FALSE, then $_GET will be set to an empty array
 	 *
 	 * @var bool
 	 */
-	protected $_allow_get_array		= TRUE;
+	protected $_allow_get_array =	TRUE;
+
 	/**
 	 * If TRUE, then newlines are standardized
 	 *
 	 * @var bool
 	 */
-	protected $_standardize_newlines	= TRUE;
+	protected $_standardize_newlines =	TRUE;
+
 	/**
 	 * Determines whether the XSS filter is always active when GET, POST or COOKIE data is encountered
 	 * Set automatically based on config setting
 	 *
 	 * @var bool
 	 */
-	protected $_enable_xss			= FALSE;
+	protected $_enable_xss =	FALSE;
+
 	/**
 	 * Enables a CSRF cookie token to be set.
 	 * Set automatically based on config setting
 	 *
 	 * @var bool
 	 */
-	protected $_enable_csrf			= FALSE;
+	protected $_enable_csrf =	FALSE;
+
 	/**
 	 * List of all HTTP request headers
 	 *
 	 * @var array
 	 */
-	protected $headers			= array();
+	protected $headers =	array();
 
 	/**
 	 * Constructor
 	 *
 	 * Sets whether to globally enable the XSS processing
 	 * and whether to allow the $_GET array
+	 *
+	 * @return	void
 	 */
 	public function __construct()
 	{
@@ -129,7 +135,7 @@
 	{
 		if ( ! isset($array[$index]))
 		{
-			return FALSE;
+			return NULL;
 		}
 
 		if ($xss_clean === TRUE)
@@ -143,16 +149,16 @@
 	// --------------------------------------------------------------------
 
 	/**
-	* Fetch an item from the GET array
-	*
-	* @param	string
-	* @param	bool
-	* @return	string
-	*/
+	 * Fetch an item from the GET array
+	 *
+	 * @param	string
+	 * @param	bool
+	 * @return	string
+	 */
 	public function get($index = NULL, $xss_clean = FALSE)
 	{
 		// Check if a field has been provided
-		if ($index === NULL AND ! empty($_GET))
+		if ($index === NULL && ! empty($_GET))
 		{
 			$get = array();
 
@@ -170,16 +176,16 @@
 	// --------------------------------------------------------------------
 
 	/**
-	* Fetch an item from the POST array
-	*
-	* @param	string
-	* @param	bool
-	* @return	string
-	*/
+	 * Fetch an item from the POST array
+	 *
+	 * @param	string
+	 * @param	bool
+	 * @return	string
+	 */
 	public function post($index = NULL, $xss_clean = FALSE)
 	{
 		// Check if a field has been provided
-		if ($index === NULL AND ! empty($_POST))
+		if ($index === NULL && ! empty($_POST))
 		{
 			$post = array();
 
@@ -198,28 +204,28 @@
 	// --------------------------------------------------------------------
 
 	/**
-	* Fetch an item from either the GET array or the POST
-	*
-	* @param	string	The index key
-	* @param	bool	XSS cleaning
-	* @return	string
-	*/
+	 * Fetch an item from either the GET array or the POST
+	 *
+	 * @param	string	The index key
+	 * @param	bool	XSS cleaning
+	 * @return	string
+	 */
 	public function get_post($index = '', $xss_clean = FALSE)
 	{
-		return ( ! isset($_POST[$index]))
-			? $this->get($index, $xss_clean)
-			: $this->post($index, $xss_clean);
+		return isset($_POST[$index])
+			? $this->post($index, $xss_clean)
+			: $this->get($index, $xss_clean);
 	}
 
 	// --------------------------------------------------------------------
 
 	/**
-	* Fetch an item from the COOKIE array
-	*
-	* @param	string
-	* @param	bool
-	* @return	string
-	*/
+	 * Fetch an item from the COOKIE array
+	 *
+	 * @param	string
+	 * @param	bool
+	 * @return	string
+	 */
 	public function cookie($index = '', $xss_clean = FALSE)
 	{
 		return $this->_fetch_from_array($_COOKIE, $index, $xss_clean);
@@ -228,26 +234,27 @@
 	// ------------------------------------------------------------------------
 
 	/**
-	* Set cookie
-	*
-	* Accepts six parameter, or you can submit an associative
-	* array in the first parameter containing all the values.
-	*
-	* @param	mixed
-	* @param	string	the value of the cookie
-	* @param	string	the number of seconds until expiration
-	* @param	string	the cookie domain.  Usually:  .yourdomain.com
-	* @param	string	the cookie path
-	* @param	string	the cookie prefix
-	* @param	bool	true makes the cookie secure
-	* @return	void
-	*/
-	public function set_cookie($name = '', $value = '', $expire = '', $domain = '', $path = '/', $prefix = '', $secure = FALSE)
+	 * Set cookie
+	 *
+	 * Accepts seven parameters, or you can submit an associative
+	 * array in the first parameter containing all the values.
+	 *
+	 * @param	mixed
+	 * @param	string	the value of the cookie
+	 * @param	string	the number of seconds until expiration
+	 * @param	string	the cookie domain.  Usually:  .yourdomain.com
+	 * @param	string	the cookie path
+	 * @param	string	the cookie prefix
+	 * @param	bool	true makes the cookie secure
+	 * @param	bool	true makes the cookie accessible via http(s) only (no javascript)
+	 * @return	void
+	 */
+	public function set_cookie($name = '', $value = '', $expire = '', $domain = '', $path = '/', $prefix = '', $secure = FALSE, $httponly = FALSE)
 	{
 		if (is_array($name))
 		{
 			// always leave 'name' in last place, as the loop will break otherwise, due to $$item
-			foreach (array('value', 'expire', 'domain', 'path', 'prefix', 'secure', 'name') as $item)
+			foreach (array('value', 'expire', 'domain', 'path', 'prefix', 'secure', 'httponly', 'name') as $item)
 			{
 				if (isset($name[$item]))
 				{
@@ -256,23 +263,31 @@
 			}
 		}
 
-		if ($prefix == '' AND config_item('cookie_prefix') != '')
+		if ($prefix === '' && config_item('cookie_prefix') !== '')
 		{
 			$prefix = config_item('cookie_prefix');
 		}
-		if ($domain == '' AND config_item('cookie_domain') != '')
+
+		if ($domain == '' && config_item('cookie_domain') != '')
 		{
 			$domain = config_item('cookie_domain');
 		}
-		if ($path == '/' AND config_item('cookie_path') != '/')
+
+		if ($path === '/' && config_item('cookie_path') !== '/')
 		{
 			$path = config_item('cookie_path');
 		}
-		if ($secure == FALSE AND config_item('cookie_secure') != FALSE)
+
+		if ($secure === FALSE && config_item('cookie_secure') !== FALSE)
 		{
 			$secure = config_item('cookie_secure');
 		}
 
+		if ($httponly === FALSE && config_item('cookie_httponly') !== FALSE)
+		{
+			$httponly = config_item('cookie_httponly');
+		}
+
 		if ( ! is_numeric($expire))
 		{
 			$expire = time() - 86500;
@@ -282,18 +297,18 @@
 			$expire = ($expire > 0) ? time() + $expire : 0;
 		}
 
-		setcookie($prefix.$name, $value, $expire, $path, $domain, $secure);
+		setcookie($prefix.$name, $value, $expire, $path, $domain, $secure, $httponly);
 	}
 
 	// --------------------------------------------------------------------
 
 	/**
-	* Fetch an item from the SERVER array
-	*
-	* @param	string
-	* @param	bool
-	* @return	string
-	*/
+	 * Fetch an item from the SERVER array
+	 *
+	 * @param	string
+	 * @param	bool
+	 * @return	string
+	 */
 	public function server($index = '', $xss_clean = FALSE)
 	{
 		return $this->_fetch_from_array($_SERVER, $index, $xss_clean);
@@ -302,10 +317,10 @@
 	// --------------------------------------------------------------------
 
 	/**
-	* Fetch the IP Address
-	*
-	* @return	string
-	*/
+	 * Fetch the IP Address
+	 *
+	 * @return	string
+	 */
 	public function ip_address()
 	{
 		if ($this->ip_address !== FALSE)
@@ -320,11 +335,11 @@
 
 			$this->ip_address = in_array($_SERVER['REMOTE_ADDR'], $proxies) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : $_SERVER['REMOTE_ADDR'];
 		}
-		elseif ( ! $this->server('HTTP_CLIENT_IP') AND $this->server('REMOTE_ADDR'))
+		elseif ( ! $this->server('HTTP_CLIENT_IP') && $this->server('REMOTE_ADDR'))
 		{
 			$this->ip_address = $_SERVER['REMOTE_ADDR'];
 		}
-		elseif ($this->server('REMOTE_ADDR') AND $this->server('HTTP_CLIENT_IP'))
+		elseif ($this->server('REMOTE_ADDR') && $this->server('HTTP_CLIENT_IP'))
 		{
 			$this->ip_address = $_SERVER['HTTP_CLIENT_IP'];
 		}
@@ -359,54 +374,37 @@
 	// --------------------------------------------------------------------
 
 	/**
-	* Validate IP Address
-	*
-	* Updated version suggested by Geert De Deckere
-	*
-	* @param	string
-	* @return	bool
-	*/
-	public function valid_ip($ip)
+	 * Validate IP Address
+	 *
+	 * @param	string
+	 * @param	string	'ipv4' or 'ipv6'
+	 * @return	bool
+	 */
+	public function valid_ip($ip, $which = '')
 	{
-		// if php version >= 5.2, use filter_var to check validate ip.
-		if (function_exists('filter_var'))
+		switch (strtolower($which))
 		{
-			return (bool) filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4);
+			case 'ipv4':
+				$which = FILTER_FLAG_IPV4;
+				break;
+			case 'ipv6':
+				$which = FILTER_FLAG_IPV6;
+				break;
+			default:
+				$which = NULL;
+				break;
 		}
 
-		$ip_segments = explode('.', $ip);
-
-		// Always 4 segments needed
-		if (count($ip_segments) !== 4)
-		{
-			return FALSE;
-		}
-		// IP can not start with 0
-		if ($ip_segments[0][0] == '0')
-		{
-			return FALSE;
-		}
-		// Check each segment
-		foreach ($ip_segments as $segment)
-		{
-			// IP segments must be digits and can not be
-			// longer than 3 digits or greater then 255
-			if ($segment == '' OR preg_match('/[^0-9]/', $segment) OR $segment > 255 OR strlen($segment) > 3)
-			{
-				return FALSE;
-			}
-		}
-
-		return TRUE;
+		return (bool) filter_var($ip, FILTER_VALIDATE_IP, $which);
 	}
 
 	// --------------------------------------------------------------------
 
 	/**
-	* User Agent
-	*
-	* @return	string
-	*/
+	 * User Agent
+	 *
+	 * @return	string
+	 */
 	public function user_agent()
 	{
 		if ($this->user_agent !== FALSE)
@@ -414,44 +412,51 @@
 			return $this->user_agent;
 		}
 
-		return $this->user_agent = ( ! isset($_SERVER['HTTP_USER_AGENT'])) ? FALSE : $_SERVER['HTTP_USER_AGENT'];
+		return $this->user_agent = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : FALSE;
 	}
 
 	// --------------------------------------------------------------------
 
 	/**
-	* Sanitize Globals
-	*
-	* This function does the following:
-	*
-	* - Unsets $_GET data (if query strings are not enabled)
-	* - Unsets all globals if register_globals is enabled
-	* - Standardizes newline characters to \n
-	*
-	* @return	void
-	*/
+	 * Sanitize Globals
+	 *
+	 * This function does the following:
+	 *
+	 * - Unsets $_GET data (if query strings are not enabled)
+	 * - Unsets all globals if register_globals is enabled
+	 * - Standardizes newline characters to \n
+	 *
+	 * @return	void
+	 */
 	protected function _sanitize_globals()
 	{
 		// It would be "wrong" to unset any of these GLOBALS.
-		$protected = array('_SERVER', '_GET', '_POST', '_FILES', '_REQUEST',
-					'_SESSION', '_ENV', 'GLOBALS', 'HTTP_RAW_POST_DATA',
-					'system_folder', 'application_folder', 'BM', 'EXT',
-					'CFG', 'URI', 'RTR', 'OUT', 'IN'
-				);
+		$protected = array(
+			'_SERVER',
+			'_GET',
+			'_POST',
+			'_FILES',
+			'_REQUEST',
+			'_SESSION',
+			'_ENV',
+			'GLOBALS',
+			'HTTP_RAW_POST_DATA',
+			'system_folder',
+			'application_folder',
+			'BM',
+			'EXT',
+			'CFG',
+			'URI',
+			'RTR',
+			'OUT',
+			'IN'
+		);
 
 		// Unset globals for securiy.
 		// This is effectively the same as register_globals = off
 		foreach (array($_GET, $_POST, $_COOKIE) as $global)
 		{
-			if ( ! is_array($global))
-			{
-				if ( ! in_array($global, $protected))
-				{
-					global $$global;
-					$$global = NULL;
-				}
-			}
-			else
+			if (is_array($global))
 			{
 				foreach ($global as $key => $val)
 				{
@@ -462,26 +467,28 @@
 					}
 				}
 			}
+			elseif ( ! in_array($global, $protected))
+			{
+				global $$global;
+				$$global = NULL;
+			}
 		}
 
 		// Is $_GET data allowed? If not we'll set the $_GET to an empty array
-		if ($this->_allow_get_array == FALSE)
+		if ($this->_allow_get_array === FALSE)
 		{
 			$_GET = array();
 		}
-		else
+		elseif (is_array($_GET) && count($_GET) > 0)
 		{
-			if (is_array($_GET) AND count($_GET) > 0)
+			foreach ($_GET as $key => $val)
 			{
-				foreach ($_GET as $key => $val)
-				{
-					$_GET[$this->_clean_input_keys($key)] = $this->_clean_input_data($val);
-				}
+				$_GET[$this->_clean_input_keys($key)] = $this->_clean_input_data($val);
 			}
 		}
 
 		// Clean $_POST Data
-		if (is_array($_POST) AND count($_POST) > 0)
+		if (is_array($_POST) && count($_POST) > 0)
 		{
 			foreach ($_POST as $key => $val)
 			{
@@ -490,7 +497,7 @@
 		}
 
 		// Clean $_COOKIE Data
-		if (is_array($_COOKIE) AND count($_COOKIE) > 0)
+		if (is_array($_COOKIE) && count($_COOKIE) > 0)
 		{
 			// Also get rid of specially treated cookies that might be set by a server
 			// or silly application, that are of no use to a CI application anyway
@@ -511,7 +518,7 @@
 		$_SERVER['PHP_SELF'] = strip_tags($_SERVER['PHP_SELF']);
 
 		// CSRF Protection check
-		if ($this->_enable_csrf == TRUE)
+		if ($this->_enable_csrf === TRUE)
 		{
 			$this->security->csrf_verify();
 		}
@@ -522,14 +529,14 @@
 	// --------------------------------------------------------------------
 
 	/**
-	* Clean Input Data
-	*
-	* This is a helper function. It escapes data and
-	* standardizes newline characters to \n
-	*
-	* @param	string
-	* @return	string
-	*/
+	 * Clean Input Data
+	 *
+	 * This is a helper function. It escapes data and
+	 * standardizes newline characters to \n
+	 *
+	 * @param	string
+	 * @return	string
+	 */
 	protected function _clean_input_data($str)
 	{
 		if (is_array($str))
@@ -568,7 +575,7 @@
 		}
 
 		// Standardize newlines if needed
-		if ($this->_standardize_newlines == TRUE AND strpos($str, "\r") !== FALSE)
+		if ($this->_standardize_newlines === TRUE && strpos($str, "\r") !== FALSE)
 		{
 			return str_replace(array("\r\n", "\r", "\r\n\n"), PHP_EOL, $str);
 		}
@@ -579,15 +586,15 @@
 	// --------------------------------------------------------------------
 
 	/**
-	* Clean Keys
-	*
-	* This is a helper function. To prevent malicious users
-	* from trying to exploit keys we make sure that keys are
-	* only named with alpha-numeric text and a few other items.
-	*
-	* @param	string
-	* @return	string
-	*/
+	 * Clean Keys
+	 *
+	 * This is a helper function. To prevent malicious users
+	 * from trying to exploit keys we make sure that keys are
+	 * only named with alpha-numeric text and a few other items.
+	 *
+	 * @param	string
+	 * @return	string
+	 */
 	protected function _clean_input_keys($str)
 	{
 		if ( ! preg_match('/^[a-z0-9:_\/-]+$/i', $str))
@@ -613,7 +620,7 @@
 	 * In Apache, you can simply call apache_request_headers(), however for
 	 * people running other webservers the function is undefined.
 	 *
-	 * @param	bool XSS cleaning
+	 * @param	bool	XSS cleaning
 	 * @return	array
 	 */
 	public function request_headers($xss_clean = FALSE)
@@ -625,7 +632,7 @@
 		}
 		else
 		{
-			$headers['Content-Type'] = (isset($_SERVER['CONTENT_TYPE'])) ? $_SERVER['CONTENT_TYPE'] : @getenv('CONTENT_TYPE');
+			$headers['Content-Type'] = isset($_SERVER['CONTENT_TYPE']) ? $_SERVER['CONTENT_TYPE'] : @getenv('CONTENT_TYPE');
 
 			foreach ($_SERVER as $key => $val)
 			{
@@ -655,9 +662,9 @@
 	 *
 	 * Returns the value of a single member of the headers class member
 	 *
-	 * @param 	string		array key for $this->headers
-	 * @param	boolean		XSS Clean or not
-	 * @return 	mixed		FALSE on failure, string on success
+	 * @param	string	array key for $this->headers
+	 * @param	bool	XSS Clean or not
+	 * @return	mixed	FALSE on failure, string on success
 	 */
 	public function get_request_header($index, $xss_clean = FALSE)
 	{
@@ -668,15 +675,12 @@
 
 		if ( ! isset($this->headers[$index]))
 		{
-			return FALSE;
+			return NULL;
 		}
 
-		if ($xss_clean === TRUE)
-		{
-			return $this->security->xss_clean($this->headers[$index]);
-		}
-
-		return $this->headers[$index];
+		return ($xss_clean === TRUE)
+			? $this->security->xss_clean($this->headers[$index])
+			: $this->headers[$index];
 	}
 
 	// --------------------------------------------------------------------
@@ -686,11 +690,11 @@
 	 *
 	 * Test to see if a request contains the HTTP_X_REQUESTED_WITH header
 	 *
-	 * @return 	boolean
+	 * @return 	bool
 	 */
 	public function is_ajax_request()
 	{
-		return ($this->server('HTTP_X_REQUESTED_WITH') === 'XMLHttpRequest');
+		return ( ! empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest');
 	}
 
 	// --------------------------------------------------------------------
@@ -700,14 +704,31 @@
 	 *
 	 * Test to see if a request was made from the command line
 	 *
-	 * @return 	boolean
+	 * @return 	bool
 	 */
 	public function is_cli_request()
 	{
-		return (php_sapi_name() === 'cli') or defined('STDIN');
+		return (php_sapi_name() === 'cli' OR defined('STDIN'));
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Get Request Method
+	 *
+	 * Return the Request Method
+	 *
+	 * @param	bool	uppercase or lowercase
+	 * @return 	bool
+	 */
+	public function method($upper = FALSE)
+	{
+		return ($upper)
+			? strtoupper($this->server('REQUEST_METHOD'))
+			: strtolower($this->server('REQUEST_METHOD'));
 	}
 
 }
 
 /* End of file Input.php */
-/* Location: ./system/core/Input.php */
+/* Location: ./system/core/Input.php */
\ No newline at end of file
diff --git a/system/core/Lang.php b/system/core/Lang.php
old mode 100755
new mode 100644
index c40a685..3001f1b
--- a/system/core/Lang.php
+++ b/system/core/Lang.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * Language Class
  *
@@ -43,14 +41,20 @@
 	 *
 	 * @var array
 	 */
-	public $language	= array();
+	public $language =	array();
+
 	/**
 	 * List of loaded language files
 	 *
 	 * @var array
 	 */
-	public $is_loaded	= array();
+	public $is_loaded =	array();
 
+	/**
+	 * Initialize language class
+	 *
+	 * @return	void
+	 */
 	public function __construct()
 	{
 		log_message('debug', 'Language Class Initialized');
@@ -61,39 +65,37 @@
 	/**
 	 * Load a language file
 	 *
-	 * @param	mixed	the name of the language file to be loaded. Can be an array
+	 * @param	mixed	the name of the language file to be loaded
 	 * @param	string	the language (english, etc.)
 	 * @param	bool	return loaded array of translations
 	 * @param 	bool	add suffix to $langfile
 	 * @param 	string	alternative path to look for language file
 	 * @return	mixed
 	 */
-	public function load($langfile = '', $idiom = '', $return = FALSE, $add_suffix = TRUE, $alt_path = '')
+	public function load($langfile, $idiom = '', $return = FALSE, $add_suffix = TRUE, $alt_path = '')
 	{
 		$langfile = str_replace('.php', '', $langfile);
 
-		if ($add_suffix == TRUE)
+		if ($add_suffix === TRUE)
 		{
-			$langfile = str_replace('_lang.', '', $langfile).'_lang';
+			$langfile = str_replace('_lang', '', $langfile).'_lang';
 		}
 
 		$langfile .= '.php';
 
-		if (in_array($langfile, $this->is_loaded, TRUE))
+		if ($idiom === '')
+		{
+			$config =& get_config();
+			$idiom = ( ! empty($config['language'])) ? $config['language'] : 'english';
+		}
+
+		if ($return === FALSE && isset($this->is_loaded[$langfile]) && $this->is_loaded[$langfile] === $idiom)
 		{
 			return;
 		}
 
-		$config =& get_config();
-
-		if ($idiom == '')
-		{
-			$deft_lang = ( ! isset($config['language'])) ? 'english' : $config['language'];
-			$idiom = ($deft_lang == '') ? 'english' : $deft_lang;
-		}
-
 		// Determine where the language file is and load it
-		if ($alt_path != '' && file_exists($alt_path.'language/'.$idiom.'/'.$langfile))
+		if ($alt_path !== '' && file_exists($alt_path.'language/'.$idiom.'/'.$langfile))
 		{
 			include($alt_path.'language/'.$idiom.'/'.$langfile);
 		}
@@ -121,17 +123,21 @@
 		if ( ! isset($lang) OR ! is_array($lang))
 		{
 			log_message('error', 'Language file contains no data: language/'.$idiom.'/'.$langfile);
+
+			if ($return === TRUE)
+			{
+				return array();
+			}
 			return;
 		}
 
-		if ($return == TRUE)
+		if ($return === TRUE)
 		{
 			return $lang;
 		}
 
-		$this->is_loaded[] = $langfile;
+		$this->is_loaded[$langfile] = $idiom;
 		$this->language = array_merge($this->language, $lang);
-		unset($lang);
 
 		log_message('debug', 'Language file loaded: language/'.$idiom.'/'.$langfile);
 		return TRUE;
@@ -147,7 +153,7 @@
 	 */
 	public function line($line = '')
 	{
-		$value = ($line == '' OR ! isset($this->language[$line])) ? FALSE : $this->language[$line];
+		$value = ($line === '' OR ! isset($this->language[$line])) ? FALSE : $this->language[$line];
 
 		// Because killer robots like unicorns!
 		if ($value === FALSE)
@@ -161,4 +167,4 @@
 }
 
 /* End of file Lang.php */
-/* Location: ./system/core/Lang.php */
+/* Location: ./system/core/Lang.php */
\ No newline at end of file
diff --git a/system/core/Loader.php b/system/core/Loader.php
index 12daaa9..09e9487 100644
--- a/system/core/Loader.php
+++ b/system/core/Loader.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * Loader Class
  *
@@ -34,8 +32,8 @@
  *
  * @package		CodeIgniter
  * @subpackage	Libraries
- * @author		EllisLab Dev Team
  * @category	Loader
+ * @author		EllisLab Dev Team
  * @link		http://codeigniter.com/user_guide/libraries/loader.html
  */
 class CI_Loader {
@@ -47,80 +45,93 @@
 	 * @var int
 	 */
 	protected $_ci_ob_level;
+
 	/**
 	 * List of paths to load views from
 	 *
 	 * @var array
 	 */
-	protected $_ci_view_paths		= array();
+	protected $_ci_view_paths =	array();
+
 	/**
 	 * List of paths to load libraries from
 	 *
 	 * @var array
 	 */
-	protected $_ci_library_paths	= array();
+	protected $_ci_library_paths =	array();
+
 	/**
 	 * List of paths to load models from
 	 *
 	 * @var array
 	 */
-	protected $_ci_model_paths		= array();
+	protected $_ci_model_paths =	array();
+
 	/**
 	 * List of paths to load helpers from
 	 *
 	 * @var array
 	 */
-	protected $_ci_helper_paths		= array();
+	protected $_ci_helper_paths =	array();
+
 	/**
 	 * List of loaded base classes
 	 *
 	 * @var array
 	 */
-	protected $_base_classes		= array(); // Set by the controller class
+	protected $_base_classes =	array(); // Set by the controller class
+
 	/**
 	 * List of cached variables
 	 *
 	 * @var array
 	 */
-	protected $_ci_cached_vars		= array();
+	protected $_ci_cached_vars =	array();
+
 	/**
 	 * List of loaded classes
 	 *
 	 * @var array
 	 */
-	protected $_ci_classes			= array();
+	protected $_ci_classes =	array();
+
 	/**
 	 * List of loaded files
 	 *
 	 * @var array
 	 */
-	protected $_ci_loaded_files		= array();
+	protected $_ci_loaded_files =	array();
+
 	/**
 	 * List of loaded models
 	 *
 	 * @var array
 	 */
-	protected $_ci_models			= array();
+	protected $_ci_models =	array();
+
 	/**
 	 * List of loaded helpers
 	 *
 	 * @var array
 	 */
-	protected $_ci_helpers			= array();
+	protected $_ci_helpers =	array();
+
 	/**
 	 * List of class name mappings
 	 *
 	 * @var array
 	 */
-	protected $_ci_varmap			= array(
-							'unit_test' => 'unit',
-							'user_agent' => 'agent'
-							);
+	protected $_ci_varmap =	array(
+		'unit_test' => 'unit',
+		'user_agent' => 'agent'
+	);
 
 	/**
 	 * Constructor
 	 *
 	 * Sets the path to the view files and gets the initial output buffering level
+	 *
+	 * @return	void
 	 */
 	public function __construct()
 	{
@@ -140,7 +151,6 @@
 	 *
 	 * This method is called once in CI_Controller.
 	 *
-	 * @param 	array
 	 * @return 	object
 	 */
 	public function initialize()
@@ -170,12 +180,7 @@
 	 */
 	public function is_loaded($class)
 	{
-		if (isset($this->_ci_classes[$class]))
-		{
-			return $this->_ci_classes[$class];
-		}
-
-		return FALSE;
+		return isset($this->_ci_classes[$class]) ? $this->_ci_classes[$class] : FALSE;
 	}
 
 	// --------------------------------------------------------------------
@@ -203,7 +208,7 @@
 			return;
 		}
 
-		if ($library == '' OR isset($this->_base_classes[$library]))
+		if ($library === '' OR isset($this->_base_classes[$library]))
 		{
 			return FALSE;
 		}
@@ -239,7 +244,7 @@
 			return;
 		}
 
-		if ($model == '')
+		if ($model === '')
 		{
 			return;
 		}
@@ -256,7 +261,7 @@
 			$model = substr($model, $last_slash);
 		}
 
-		if ($name == '')
+		if (empty($name))
 		{
 			$name = $model;
 		}
@@ -281,7 +286,7 @@
 				continue;
 			}
 
-			if ($db_conn !== FALSE AND ! class_exists('CI_DB'))
+			if ($db_conn !== FALSE && ! class_exists('CI_DB'))
 			{
 				if ($db_conn === TRUE)
 				{
@@ -315,16 +320,16 @@
 	 *
 	 * @param	string	the DB credentials
 	 * @param	bool	whether to return the DB object
-	 * @param	bool	whether to enable active record (this allows us to override the config setting)
+	 * @param	bool	whether to enable query builder (this allows us to override the config setting)
 	 * @return	object
 	 */
-	public function database($params = '', $return = FALSE, $active_record = NULL)
+	public function database($params = '', $return = FALSE, $query_builder = NULL)
 	{
 		// Grab the super object
 		$CI =& get_instance();
 
 		// Do we even need to load the database class?
-		if (class_exists('CI_DB') AND $return == FALSE AND $active_record == NULL AND isset($CI->db) AND is_object($CI->db))
+		if (class_exists('CI_DB') && $return === FALSE && $query_builder === NULL && isset($CI->db) && is_object($CI->db))
 		{
 			return FALSE;
 		}
@@ -333,7 +338,7 @@
 
 		if ($return === TRUE)
 		{
-			return DB($params, $active_record);
+			return DB($params, $query_builder);
 		}
 
 		// Initialize the db variable. Needed to prevent
@@ -341,7 +346,7 @@
 		$CI->db = '';
 
 		// Load the DB class
-		$CI->db =& DB($params, $active_record);
+		$CI->db =& DB($params, $query_builder);
 	}
 
 	// --------------------------------------------------------------------
@@ -399,13 +404,13 @@
 	/**
 	 * Load View
 	 *
-	 * This function is used to load a "view" file.  It has three parameters:
+	 * This function is used to load a "view" file. It has three parameters:
 	 *
 	 * 1. The name of the "view" file to be included.
 	 * 2. An associative array of data to be extracted for use in the view.
-	 * 3. TRUE/FALSE - whether to return the data or load it.  In
-	 * some cases it's advantageous to be able to return data so that
-	 * a developer can process it in some way.
+	 * 3. TRUE/FALSE - whether to return the data or load it. In
+	 *    some cases it's advantageous to be able to return data so that
+	 *    a developer can process it in some way.
 	 *
 	 * @param	string
 	 * @param	array
@@ -447,14 +452,14 @@
 	 */
 	public function vars($vars = array(), $val = '')
 	{
-		if ($val != '' AND is_string($vars))
+		if ($val !== '' && is_string($vars))
 		{
 			$vars = array($vars => $val);
 		}
 
 		$vars = $this->_ci_object_to_array($vars);
 
-		if (is_array($vars) AND count($vars) > 0)
+		if (is_array($vars) && count($vars) > 0)
 		{
 			foreach ($vars as $key => $val)
 			{
@@ -615,20 +620,29 @@
 	 *
 	 * Loads a driver library
 	 *
-	 * @param	string	the name of the class
+	 * @param	mixed	the name of the class or array of classes
 	 * @param	mixed	the optional parameters
 	 * @param	string	an optional object name
 	 * @return	void
 	 */
 	public function driver($library = '', $params = NULL, $object_name = NULL)
 	{
+		if (is_array($library))
+		{
+			foreach ($library as $driver)
+			{
+				$this->driver($driver);
+			}
+			return FALSE;
+		}
+
 		if ( ! class_exists('CI_Driver_Library'))
 		{
 			// we aren't instantiating an object here, that'll be done by the Library itself
 			require BASEPATH.'libraries/Driver.php';
 		}
 
-		if ($library == '')
+		if ($library === '')
 		{
 			return FALSE;
 		}
@@ -651,7 +665,7 @@
 	 * Prepends a parent path to the library, model, helper, and config path arrays
 	 *
 	 * @param	string
-	 * @param 	boolean
+	 * @param 	bool
 	 * @return	void
 	 */
 	public function add_package_path($path, $view_cascade=TRUE)
@@ -666,7 +680,7 @@
 
 		// Add config file path
 		$config =& $this->_ci_get_component('config');
-		array_unshift($config->_config_paths, $path);
+		array_push($config->_config_paths, $path);
 	}
 
 	// --------------------------------------------------------------------
@@ -692,21 +706,21 @@
 	 * Remove a path from the library, model, and helper path arrays if it exists
 	 * If no path is provided, the most recently added path is removed.
 	 *
-	 * @param	type
+	 * @param	string
 	 * @param 	bool
-	 * @return	type
+	 * @return	void
 	 */
 	public function remove_package_path($path = '', $remove_config_path = TRUE)
 	{
 		$config =& $this->_ci_get_component('config');
 
-		if ($path == '')
+		if ($path === '')
 		{
 			array_shift($this->_ci_library_paths);
 			array_shift($this->_ci_model_paths);
 			array_shift($this->_ci_helper_paths);
 			array_shift($this->_ci_view_paths);
-			array_shift($config->_config_paths);
+			array_pop($config->_config_paths);
 		}
 		else
 		{
@@ -755,13 +769,13 @@
 		// Set the default data variables
 		foreach (array('_ci_view', '_ci_vars', '_ci_path', '_ci_return') as $_ci_val)
 		{
-			$$_ci_val = ( ! isset($_ci_data[$_ci_val])) ? FALSE : $_ci_data[$_ci_val];
+			$$_ci_val = isset($_ci_data[$_ci_val]) ? $_ci_data[$_ci_val] : FALSE;
 		}
 
 		$file_exists = FALSE;
 
 		// Set the path to the requested file
-		if ($_ci_path != '')
+		if (is_string($_ci_path) && $_ci_path !== '')
 		{
 			$_ci_x = explode('/', $_ci_path);
 			$_ci_file = end($_ci_x);
@@ -769,7 +783,7 @@
 		else
 		{
 			$_ci_ext = pathinfo($_ci_view, PATHINFO_EXTENSION);
-			$_ci_file = ($_ci_ext == '') ? $_ci_view.'.php' : $_ci_view;
+			$_ci_file = ($_ci_ext === '') ? $_ci_view.'.php' : $_ci_view;
 
 			foreach ($this->_ci_view_paths as $view_file => $cascade)
 			{
@@ -833,7 +847,7 @@
 		// If the PHP installation does not support short tags we'll
 		// do a little string replacement, changing the short tags
 		// to standard PHP echo statements.
-		if ((bool) @ini_get('short_open_tag') === FALSE AND config_item('rewrite_short_tags') == TRUE)
+		if ( ! is_php('5.4') && (bool) @ini_get('short_open_tag') === FALSE && config_item('rewrite_short_tags') === TRUE)
 		{
 			echo eval('?>'.preg_replace('/;*\s*\?>/', '; ?>', str_replace('<?=', '<?php echo ', file_get_contents($_ci_path))));
 		}
@@ -986,7 +1000,7 @@
 		} // END FOREACH
 
 		// One last attempt. Maybe the library is in a subdirectory, but it wasn't specified?
-		if ($subdir == '')
+		if ($subdir === '')
 		{
 			$path = strtolower($class).'/'.$class;
 			return $this->_ci_load_class($path, $params);
@@ -994,7 +1008,7 @@
 
 		// If we got this far we were unable to find the requested class.
 		// We do not issue errors if the load call failed due to a duplicate request
-		if ($is_duplicate == FALSE)
+		if ($is_duplicate === FALSE)
 		{
 			log_message('error', 'Unable to load the requested class: '.$class);
 			show_error('Unable to load the requested class: '.$class);
@@ -1010,11 +1024,11 @@
 	 * @param	string
 	 * @param	bool
 	 * @param	string	an optional object name
-	 * @return	null
+	 * @return	void
 	 */
 	protected function _ci_init_class($class, $prefix = '', $config = FALSE, $object_name = NULL)
 	{
-		// Is there an associated config file for this class?  Note: these should always be lowercase
+		// Is there an associated config file for this class? Note: these should always be lowercase
 		if ($config === NULL)
 		{
 			// Fetch the config paths containing any package paths
@@ -1029,31 +1043,31 @@
 					// We test for both uppercase and lowercase, for servers that
 					// are case-sensitive with regard to file names. Check for environment
 					// first, global next
-					if (defined('ENVIRONMENT') AND file_exists($path .'config/'.ENVIRONMENT.'/'.strtolower($class).'.php'))
+					if (defined('ENVIRONMENT') && file_exists($path.'config/'.ENVIRONMENT.'/'.strtolower($class).'.php'))
 					{
-						include($path .'config/'.ENVIRONMENT.'/'.strtolower($class).'.php');
+						include($path.'config/'.ENVIRONMENT.'/'.strtolower($class).'.php');
 						break;
 					}
-					elseif (defined('ENVIRONMENT') AND file_exists($path .'config/'.ENVIRONMENT.'/'.ucfirst(strtolower($class)).'.php'))
+					elseif (defined('ENVIRONMENT') && file_exists($path.'config/'.ENVIRONMENT.'/'.ucfirst(strtolower($class)).'.php'))
 					{
-						include($path .'config/'.ENVIRONMENT.'/'.ucfirst(strtolower($class)).'.php');
+						include($path.'config/'.ENVIRONMENT.'/'.ucfirst(strtolower($class)).'.php');
 						break;
 					}
-					elseif (file_exists($path .'config/'.strtolower($class).'.php'))
+					elseif (file_exists($path.'config/'.strtolower($class).'.php'))
 					{
-						include($path .'config/'.strtolower($class).'.php');
+						include($path.'config/'.strtolower($class).'.php');
 						break;
 					}
-					elseif (file_exists($path .'config/'.ucfirst(strtolower($class)).'.php'))
+					elseif (file_exists($path.'config/'.ucfirst(strtolower($class)).'.php'))
 					{
-						include($path .'config/'.ucfirst(strtolower($class)).'.php');
+						include($path.'config/'.ucfirst(strtolower($class)).'.php');
 						break;
 					}
 				}
 			}
 		}
 
-		if ($prefix == '')
+		if ($prefix === '')
 		{
 			if (class_exists('CI_'.$class))
 			{
@@ -1086,7 +1100,7 @@
 
 		if (is_null($object_name))
 		{
-			$classvar = ( ! isset($this->_ci_varmap[$class])) ? $class : $this->_ci_varmap[$class];
+			$classvar = isset($this->_ci_varmap[$class]) ? $this->_ci_varmap[$class] : $class;
 		}
 		else
 		{
@@ -1104,7 +1118,7 @@
 		}
 		else
 		{
-			$CI->$classvar = new $name;
+			$CI->$classvar = new $name();
 		}
 	}
 
@@ -1116,12 +1130,11 @@
 	 * The config/autoload.php file contains an array that permits sub-systems,
 	 * libraries, and helpers to be loaded automatically.
 	 *
-	 * @param	array
 	 * @return	void
 	 */
 	protected function _ci_autoloader()
 	{
-		if (defined('ENVIRONMENT') AND file_exists(APPPATH.'config/'.ENVIRONMENT.'/autoload.php'))
+		if (defined('ENVIRONMENT') && file_exists(APPPATH.'config/'.ENVIRONMENT.'/autoload.php'))
 		{
 			include(APPPATH.'config/'.ENVIRONMENT.'/autoload.php');
 		}
@@ -1157,14 +1170,14 @@
 		// Autoload helpers and languages
 		foreach (array('helper', 'language') as $type)
 		{
-			if (isset($autoload[$type]) AND count($autoload[$type]) > 0)
+			if (isset($autoload[$type]) && count($autoload[$type]) > 0)
 			{
 				$this->$type($autoload[$type]);
 			}
 		}
 
 		// Load libraries
-		if (isset($autoload['libraries']) AND count($autoload['libraries']) > 0)
+		if (isset($autoload['libraries']) && count($autoload['libraries']) > 0)
 		{
 			// Load the database driver.
 			if (in_array('database', $autoload['libraries']))
@@ -1199,7 +1212,7 @@
 	 */
 	protected function _ci_object_to_array($object)
 	{
-		return (is_object($object)) ? get_object_vars($object) : $object;
+		return is_object($object) ? get_object_vars($object) : $object;
 	}
 
 	// --------------------------------------------------------------------
@@ -1243,7 +1256,8 @@
 			return $filename;
 		}
 	}
+
 }
 
 /* End of file Loader.php */
-/* Location: ./system/core/Loader.php */
+/* Location: ./system/core/Loader.php */
\ No newline at end of file
diff --git a/system/core/Model.php b/system/core/Model.php
old mode 100755
new mode 100644
index a595a6a..9bc9f87
--- a/system/core/Model.php
+++ b/system/core/Model.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * CodeIgniter Model Class
  *
@@ -38,6 +36,11 @@
  */
 class CI_Model {
 
+	/**
+	 * Initialize CI_Model Class
+	 *
+	 * @return	void
+	 */
 	public function __construct()
 	{
 		log_message('debug', 'Model Class Initialized');
@@ -56,7 +59,8 @@
 		$CI =& get_instance();
 		return $CI->$key;
 	}
+
 }
 
 /* End of file Model.php */
-/* Location: ./system/core/Model.php */
+/* Location: ./system/core/Model.php */
\ No newline at end of file
diff --git a/system/core/Output.php b/system/core/Output.php
old mode 100755
new mode 100644
index abd8a0e..5588ffe
--- a/system/core/Output.php
+++ b/system/core/Output.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * Output Class
  *
@@ -45,66 +43,69 @@
 	 *
 	 * @var string
 	 */
-	protected $final_output;
+	public $final_output;
+
 	/**
 	 * Cache expiration time
 	 *
 	 * @var int
 	 */
-	protected $cache_expiration	= 0;
+	public $cache_expiration =	0;
+
 	/**
 	 * List of server headers
 	 *
 	 * @var array
 	 */
-	protected $headers			= array();
+	public $headers =	array();
+
 	/**
 	 * List of mime types
 	 *
 	 * @var array
 	 */
-	protected $mime_types		= array();
+	public $mimes =		array();
+
 	/**
 	 * Determines wether profiler is enabled
 	 *
 	 * @var book
 	 */
-	protected $enable_profiler	= FALSE;
+	public $enable_profiler =	FALSE;
+
 	/**
 	 * Determines if output compression is enabled
 	 *
 	 * @var bool
 	 */
-	protected $_zlib_oc			= FALSE;
+	protected $_zlib_oc =	FALSE;
+
 	/**
 	 * List of profiler sections
 	 *
 	 * @var array
 	 */
-	protected $_profiler_sections = array();
+	protected $_profiler_sections =	array();
+
 	/**
 	 * Whether or not to parse variables like {elapsed_time} and {memory_usage}
 	 *
 	 * @var bool
 	 */
-	protected $parse_exec_vars	= TRUE;
+	public $parse_exec_vars =	TRUE;
 
+	/**
+	 * Set up Output class
+	 *
+	 * @return	void
+	 */
 	public function __construct()
 	{
-		$this->_zlib_oc = @ini_get('zlib.output_compression');
+		$this->_zlib_oc = (bool) @ini_get('zlib.output_compression');
 
 		// Get mime types for later
-		if (defined('ENVIRONMENT') AND file_exists(APPPATH.'config/'.ENVIRONMENT.'/mimes.php'))
-		{
-			include APPPATH.'config/'.ENVIRONMENT.'/mimes.php';
-		}
-		else
-		{
-			include APPPATH.'config/mimes.php';
-		}
+		$this->mimes =& get_mimes();
 
-
-		$this->mime_types = $mimes;
 		log_message('debug', 'Output Class Initialized');
 	}
 
@@ -169,7 +170,7 @@
 	 *
 	 * Lets you set a server header which will be outputted with the final display.
 	 *
-	 * Note:  If a file is cached, headers will not be sent.  We need to figure out
+	 * Note: If a file is cached, headers will not be sent. We need to figure out
 	 * how to permit header data to be saved with the cache data...
 	 *
 	 * @param	string
@@ -182,7 +183,7 @@
 		// but it will not modify the content-length header to compensate for
 		// the reduction, causing the browser to hang waiting for more data.
 		// We'll just skip content-length in those cases.
-		if ($this->_zlib_oc && strncasecmp($header, 'content-length', 14) == 0)
+		if ($this->_zlib_oc && strncasecmp($header, 'content-length', 14) === 0)
 		{
 			return;
 		}
@@ -199,16 +200,16 @@
 	 * @param	string	extension of the file we're outputting
 	 * @return	void
 	 */
-	public function set_content_type($mime_type)
+	public function set_content_type($mime_type, $charset = NULL)
 	{
 		if (strpos($mime_type, '/') === FALSE)
 		{
 			$extension = ltrim($mime_type, '.');
 
 			// Is this extension supported?
-			if (isset($this->mime_types[$extension]))
+			if (isset($this->mimes[$extension]))
 			{
-				$mime_type =& $this->mime_types[$extension];
+				$mime_type =& $this->mimes[$extension];
 
 				if (is_array($mime_type))
 				{
@@ -217,7 +218,13 @@
 			}
 		}
 
-		$header = 'Content-Type: '.$mime_type;
+		if (empty($charset))
+		{
+			$charset = config_item('charset');
+		}
+
+		$header = 'Content-Type: '.$mime_type
+			.(empty($charset) ? NULL : '; charset='.strtolower($charset));
 
 		$this->headers[] = array($header, TRUE);
 		return $this;
@@ -226,10 +233,30 @@
 	// --------------------------------------------------------------------
 
 	/**
+	 * Get Current Content Type Header
+	 *
+	 * @return	string	'text/html', if not already set
+	 */
+	public function get_content_type()
+	{
+		for ($i = 0, $c = count($this->headers); $i < $c; $i++)
+		{
+			if (preg_match('/^Content-Type:\s(.+)$/', $this->headers[$i][0], $matches))
+			{
+				return $matches[1];
+			}
+		}
+
+		return 'text/html';
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
 	 * Set HTTP Status Header
 	 * moved to Common procedural functions in 1.7.2
 	 *
-	 * @param	int		the status code
+	 * @param	int	the status code
 	 * @param	string
 	 * @return	void
 	 */
@@ -249,7 +276,7 @@
 	 */
 	public function enable_profiler($val = TRUE)
 	{
-		$this->enable_profiler = (is_bool($val)) ? $val : TRUE;
+		$this->enable_profiler = is_bool($val) ? $val : TRUE;
 		return $this;
 	}
 
@@ -267,7 +294,7 @@
 	{
 		foreach ($sections as $section => $enable)
 		{
-			$this->_profiler_sections[$section] = ($enable !== FALSE) ? TRUE : FALSE;
+			$this->_profiler_sections[$section] = ($enable !== FALSE);
 		}
 
 		return $this;
@@ -278,12 +305,12 @@
 	/**
 	 * Set Cache
 	 *
-	 * @param	integer
+	 * @param	int
 	 * @return	void
 	 */
 	public function cache($time)
 	{
-		$this->cache_expiration = ( ! is_numeric($time)) ? 0 : $time;
+		$this->cache_expiration = is_numeric($time) ? $time : 0;
 		return $this;
 	}
 
@@ -297,7 +324,7 @@
 	 * $this->final_output
 	 *
 	 * This function sends the finalized output data to the browser along
-	 * with any server headers and profile data.  It also stops the
+	 * with any server headers and profile data. It also stops the
 	 * benchmark timer so the page rendering speed and memory usage can be shown.
 	 *
 	 * @param 	string
@@ -319,7 +346,7 @@
 		// --------------------------------------------------------------------
 
 		// Set the output data
-		if ($output == '')
+		if ($output === '')
 		{
 			$output =& $this->final_output;
 		}
@@ -343,7 +370,7 @@
 
 		if ($this->parse_exec_vars === TRUE)
 		{
-			$memory	 = ( ! function_exists('memory_get_usage')) ? '0' : round(memory_get_usage()/1024/1024, 2).'MB';
+			$memory	= round(memory_get_usage() / 1024 / 1024, 2).'MB';
 
 			$output = str_replace(array('{elapsed_time}', '{memory_usage}'), array($elapsed, $memory), $output);
 		}
@@ -351,7 +378,7 @@
 		// --------------------------------------------------------------------
 
 		// Is compression requested?
-		if ($CFG->item('compress_output') === TRUE && $this->_zlib_oc == FALSE
+		if ($CFG->item('compress_output') === TRUE && $this->_zlib_oc === FALSE
 			&& extension_loaded('zlib')
 			&& isset($_SERVER['HTTP_ACCEPT_ENCODING']) && strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== FALSE)
 		{
@@ -386,7 +413,7 @@
 
 		// Do we need to generate profile data?
 		// If so, load the Profile class and run it.
-		if ($this->enable_profiler == TRUE)
+		if ($this->enable_profiler === TRUE)
 		{
 			$CI->load->library('profiler');
 			if ( ! empty($this->_profiler_sections))
@@ -430,7 +457,7 @@
 	{
 		$CI =& get_instance();
 		$path = $CI->config->item('cache_path');
-		$cache_path = ($path == '') ? APPPATH.'cache/' : $path;
+		$cache_path = ($path === '') ? APPPATH.'cache/' : $path;
 
 		if ( ! is_dir($cache_path) OR ! is_really_writable($cache_path))
 		{
@@ -475,11 +502,11 @@
 	 *
 	 * @param 	object	config class
 	 * @param 	object	uri class
-	 * @return	void
+	 * @return	bool
 	 */
 	public function _display_cache(&$CFG, &$URI)
 	{
-		$cache_path = ($CFG->item('cache_path') == '') ? APPPATH.'cache/' : $CFG->item('cache_path');
+		$cache_path = ($CFG->item('cache_path') === '') ? APPPATH.'cache/' : $CFG->item('cache_path');
 
 		// Build the file path. The file name is an MD5 hash of the full URI
 		$uri =	$CFG->item('base_url').$CFG->item('index_page').$URI->uri_string;
@@ -520,4 +547,4 @@
 }
 
 /* End of file Output.php */
-/* Location: ./system/core/Output.php */
+/* Location: ./system/core/Output.php */
\ No newline at end of file
diff --git a/system/core/Router.php b/system/core/Router.php
old mode 100755
new mode 100644
index d213195..5bc0530
--- a/system/core/Router.php
+++ b/system/core/Router.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * Router Class
  *
@@ -34,8 +32,8 @@
  *
  * @package		CodeIgniter
  * @subpackage	Libraries
- * @author		EllisLab Dev Team
  * @category	Libraries
+ * @author		EllisLab Dev Team
  * @link		http://codeigniter.com/user_guide/general/routing.html
  */
 class CI_Router {
@@ -46,36 +44,42 @@
 	 * @var object
 	 */
 	public $config;
+
 	/**
 	 * List of routes
 	 *
 	 * @var array
 	 */
-	public $routes			= array();
+	public $routes =	array();
+
 	/**
 	 * List of error routes
 	 *
 	 * @var array
 	 */
-	public $error_routes	= array();
+	public $error_routes =	array();
+
 	/**
 	 * Current class name
 	 *
 	 * @var string
 	 */
-	public $class			= '';
+	public $class =		'';
+
 	/**
 	 * Current method name
 	 *
 	 * @var string
 	 */
-	public $method			= 'index';
+	public $method =	'index';
+
 	/**
 	 * Sub-directory that contains the requested controller class
 	 *
 	 * @var string
 	 */
-	public $directory		= '';
+	public $directory =	'';
+
 	/**
 	 * Default controller (and method if specific)
 	 *
@@ -87,6 +91,8 @@
 	 * Constructor
 	 *
 	 * Runs the route mapping function.
+	 *
+	 * @return	void
 	 */
 	public function __construct()
 	{
@@ -111,7 +117,7 @@
 		// 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 AND isset($_GET[$this->config->item('controller_trigger')]))
+		if ($this->config->item('enable_query_strings') === TRUE && isset($_GET[$this->config->item('controller_trigger')]))
 		{
 			if (isset($_GET[$this->config->item('directory_trigger')]))
 			{
@@ -133,7 +139,7 @@
 		}
 
 		// Load the routes.php file.
-		if (defined('ENVIRONMENT') AND is_file(APPPATH.'config/'.ENVIRONMENT.'/routes.php'))
+		if (defined('ENVIRONMENT') && is_file(APPPATH.'config/'.ENVIRONMENT.'/routes.php'))
 		{
 			include(APPPATH.'config/'.ENVIRONMENT.'/routes.php');
 		}
@@ -147,7 +153,7 @@
 
 		// Set the default controller so we can display it in the event
 		// the URI doesn't correlated to a valid controller.
-		$this->default_controller = ( ! isset($this->routes['default_controller']) OR $this->routes['default_controller'] == '') ? FALSE : strtolower($this->routes['default_controller']);
+		$this->default_controller = empty($this->routes['default_controller']) ? FALSE : strtolower($this->routes['default_controller']);
 
 		// Were there any query string segments? If so, we'll validate them and bail out since we're done.
 		if (count($segments) > 0)
@@ -213,7 +219,6 @@
 	 * input, and sets the current class/method
 	 *
 	 * @param	array
-	 * @param	bool
 	 * @return	void
 	 */
 	protected function _set_request($segments = array())
@@ -248,8 +253,8 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 * Validates the supplied segments.  Attempts to determine the path to
-	 * the controller.
+	 * Validates the supplied segments.
+	 * Attempts to determine the path to the controller.
 	 *
 	 * @param	array
 	 * @return	array
@@ -340,7 +345,7 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 *  Parse Routes
+	 * Parse Routes
 	 *
 	 * This function matches any routes that may exist in
 	 * the config/routes.php file against the URI to
@@ -369,7 +374,7 @@
 			if (preg_match('#^'.$key.'$#', $uri))
 			{
 				// Do we have a back-reference?
-				if (strpos($val, '$') !== FALSE AND strpos($key, '(') !== FALSE)
+				if (strpos($val, '$') !== FALSE && strpos($key, '(') !== FALSE)
 				{
 					$val = preg_replace('#^'.$key.'$#', $val, $uri);
 				}
@@ -411,7 +416,7 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 *  Set the method name
+	 * Set the method name
 	 *
 	 * @param	string
 	 * @return	void
@@ -424,24 +429,19 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 *  Fetch the current method
+	 * Fetch the current method
 	 *
 	 * @return	string
 	 */
 	public function fetch_method()
 	{
-		if ($this->method == $this->fetch_class())
-		{
-			return 'index';
-		}
-
-		return $this->method;
+		return ($this->method === $this->fetch_class()) ? 'index' : $this->method;
 	}
 
 	// --------------------------------------------------------------------
 
 	/**
-	 *  Set the directory name
+	 * Set the directory name
 	 *
 	 * @param	string
 	 * @return	void
@@ -454,7 +454,7 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 *  Fetch the sub-directory (if any) that contains the requested controller class
+	 * Fetch the sub-directory (if any) that contains the requested controller class
 	 *
 	 * @return	string
 	 */
@@ -466,10 +466,10 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 *  Set the controller overrides
+	 * Set the controller overrides
 	 *
 	 * @param	array
-	 * @return	null
+	 * @return	void
 	 */
 	public function _set_overrides($routing)
 	{
@@ -483,7 +483,7 @@
 			$this->set_directory($routing['directory']);
 		}
 
-		if (isset($routing['controller']) AND $routing['controller'] != '')
+		if ( ! empty($routing['controller']))
 		{
 			$this->set_class($routing['controller']);
 		}
@@ -498,4 +498,4 @@
 }
 
 /* End of file Router.php */
-/* Location: ./system/core/Router.php */
+/* Location: ./system/core/Router.php */
\ No newline at end of file
diff --git a/system/core/Security.php b/system/core/Security.php
old mode 100755
new mode 100644
index 1007f61..4593a10
--- a/system/core/Security.php
+++ b/system/core/Security.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * Security Class
  *
@@ -43,14 +41,14 @@
 	 *
 	 * @var string
 	 */
-	protected $_xss_hash			= '';
+	protected $_xss_hash =	'';
 
 	/**
 	 * Random Hash for Cross Site Request Forgery Protection Cookie
 	 *
 	 * @var string
 	 */
-	protected $_csrf_hash			= '';
+	protected $_csrf_hash =	'';
 
 	/**
 	 * Expiration time for Cross Site Request Forgery Protection Cookie
@@ -58,39 +56,39 @@
 	 *
 	 * @var int
 	 */
-	protected $_csrf_expire			= 7200;
+	protected $_csrf_expire =	7200;
 
 	/**
 	 * Token name for Cross Site Request Forgery Protection Cookie
 	 *
 	 * @var string
 	 */
-	protected $_csrf_token_name		= 'ci_csrf_token';
+	protected $_csrf_token_name =	'ci_csrf_token';
 
 	/**
 	 * Cookie name for Cross Site Request Forgery Protection Cookie
 	 *
 	 * @var string
 	 */
-	protected $_csrf_cookie_name		= 'ci_csrf_token';
+	protected $_csrf_cookie_name =	'ci_csrf_token';
 
 	/**
 	 * List of never allowed strings
 	 *
 	 * @var array
 	 */
-	protected $_never_allowed_str = array(
-						'document.cookie'	=> '[removed]',
-						'document.write'	=> '[removed]',
-						'.parentNode'		=> '[removed]',
-						'.innerHTML'		=> '[removed]',
-						'window.location'	=> '[removed]',
-						'-moz-binding'		=> '[removed]',
-						'<!--'				=> '&lt;!--',
-						'-->'				=> '--&gt;',
-						'<![CDATA['			=> '&lt;![CDATA[',
-						'<comment>'			=> '&lt;comment&gt;'
-					);
+	protected $_never_allowed_str =	array(
+		'document.cookie'	=> '[removed]',
+		'document.write'	=> '[removed]',
+		'.parentNode'		=> '[removed]',
+		'.innerHTML'		=> '[removed]',
+		'window.location'	=> '[removed]',
+		'-moz-binding'		=> '[removed]',
+		'<!--'				=> '&lt;!--',
+		'-->'				=> '--&gt;',
+		'<![CDATA['			=> '&lt;![CDATA[',
+		'<comment>'			=> '&lt;comment&gt;'
+	);
 
 	/**
 	 * List of never allowed regex replacement
@@ -98,31 +96,41 @@
 	 * @var array
 	 */
 	protected $_never_allowed_regex = array(
-						'javascript\s*:',
-						'expression\s*(\(|&\#40;)', // CSS and IE
-						'vbscript\s*:', // IE, surprise!
-						'Redirect\s+302'
-					);
+		'javascript\s*:',
+		'expression\s*(\(|&\#40;)', // CSS and IE
+		'vbscript\s*:', // IE, surprise!
+		'Redirect\s+302',
+		"([\"'])?data\s*:[^\\1]*?base64[^\\1]*?,[^\\1]*?\\1?"
+	);
 
+	/**
+	 * Initialize security class
+	 *
+	 * @return	void
+	 */
 	public function __construct()
 	{
-		// CSRF config
-		foreach(array('csrf_expire', 'csrf_token_name', 'csrf_cookie_name') as $key)
+		// Is CSRF protection enabled?
+		if (config_item('csrf_protection') === TRUE)
 		{
-			if (FALSE !== ($val = config_item($key)))
+			// CSRF config
+			foreach (array('csrf_expire', 'csrf_token_name', 'csrf_cookie_name') as $key)
 			{
-				$this->{'_'.$key} = $val;
+				if (FALSE !== ($val = config_item($key)))
+				{
+					$this->{'_'.$key} = $val;
+				}
 			}
-		}
 
-		// Append application specific cookie prefix
-		if (config_item('cookie_prefix'))
-		{
-			$this->_csrf_cookie_name = config_item('cookie_prefix').$this->_csrf_cookie_name;
-		}
+			// Append application specific cookie prefix
+			if (config_item('cookie_prefix'))
+			{
+				$this->_csrf_cookie_name = config_item('cookie_prefix').$this->_csrf_cookie_name;
+			}
 
-		// Set the CSRF hash
-		$this->_csrf_set_hash();
+			// Set the CSRF hash
+			$this->_csrf_set_hash();
+		}
 
 		log_message('debug', 'Security Class Initialized');
 	}
@@ -136,8 +144,8 @@
 	 */
 	public function csrf_verify()
 	{
-		// If no POST data exists we will set the CSRF cookie
-		if (count($_POST) === 0)
+		// If it's not a POST request we will set the CSRF cookie
+		if (strtoupper($_SERVER['REQUEST_METHOD']) !== 'POST')
 		{
 			return $this->csrf_set_cookie();
 		}
@@ -154,7 +162,7 @@
 
 		// Do the tokens exist in both the _POST and _COOKIE arrays?
 		if ( ! isset($_POST[$this->_csrf_token_name]) OR ! isset($_COOKIE[$this->_csrf_cookie_name])
-			OR $_POST[$this->_csrf_token_name] != $_COOKIE[$this->_csrf_cookie_name]) // Do the tokens match?
+			OR $_POST[$this->_csrf_token_name] !== $_COOKIE[$this->_csrf_cookie_name]) // Do the tokens match?
 		{
 			$this->csrf_show_error();
 		}
@@ -183,18 +191,27 @@
 	 * Set Cross Site Request Forgery Protection Cookie
 	 *
 	 * @return	object
+	 * @codeCoverageIgnore
 	 */
 	public function csrf_set_cookie()
 	{
 		$expire = time() + $this->_csrf_expire;
 		$secure_cookie = (bool) config_item('cookie_secure');
 
-		if ($secure_cookie && ( ! isset($_SERVER['HTTPS']) OR $_SERVER['HTTPS'] == 'off' OR ! $_SERVER['HTTPS']))
+		if ($secure_cookie && (empty($_SERVER['HTTPS']) OR strtolower($_SERVER['HTTPS']) === 'off'))
 		{
 			return FALSE;
 		}
 
-		setcookie($this->_csrf_cookie_name, $this->_csrf_hash, $expire, config_item('cookie_path'), config_item('cookie_domain'), $secure_cookie);
+		setcookie(
+			$this->_csrf_cookie_name,
+			$this->_csrf_hash,
+			$expire,
+			config_item('cookie_path'),
+			config_item('cookie_domain'),
+			$secure_cookie,
+			config_item('cookie_httponly')
+		);
 		log_message('debug', 'CRSF cookie Set');
 
 		return $this;
@@ -352,13 +369,14 @@
 		 * These words are compacted back to their correct state.
 		 */
 		$words = array(
-				'javascript', 'expression', 'vbscript', 'script',
-				'applet', 'alert', 'document', 'write', 'cookie', 'window'
-			);
+			'javascript', 'expression', 'vbscript', 'script', 'base64',
+			'applet', 'alert', 'document', 'write', 'cookie', 'window'
+		);
+
 
 		foreach ($words as $word)
 		{
-			$word = implode("\s*", str_split($word)) . "\s*";
+			$word = implode('\s*', str_split($word)).'\s*';
 
 			// We only want to do this when it is followed by a non-word character
 			// That way valid stuff like "dealer to" does not become "dealerto"
@@ -390,7 +408,7 @@
 				$str = preg_replace('#<(/*)(script|xss)(.*?)\>#si', '[removed]', $str);
 			}
 		}
-		while($original != $str);
+		while($original !== $str);
 
 		unset($original);
 
@@ -425,7 +443,6 @@
 					'\\1\\2&#40;\\3&#41;',
 					$str);
 
-
 		// Final clean up
 		// This adds a bit of extra precaution in case
 		// something got through the above filters
@@ -458,7 +475,7 @@
 	 */
 	public function xss_hash()
 	{
-		if ($this->_xss_hash == '')
+		if ($this->_xss_hash === '')
 		{
 			mt_srand();
 			$this->_xss_hash = md5(time() + mt_rand(0, 1999999999));
@@ -513,23 +530,23 @@
 	public function sanitize_filename($str, $relative_path = FALSE)
 	{
 		$bad = array(
-				'../', '<!--', '-->', '<', '>',
-				"'", '"', '&', '$', '#',
-				'{', '}', '[', ']', '=',
-				';', '?', '%20', '%22',
-				'%3c',		// <
-				'%253c',	// <
-				'%3e',		// >
-				'%0e',		// >
-				'%28',		// (
-				'%29',		// )
-				'%2528',	// (
-				'%26',		// &
-				'%24',		// $
-				'%3f',		// ?
-				'%3b',		// ;
-				'%3d'		// =
-			);
+			'../', '<!--', '-->', '<', '>',
+			"'", '"', '&', '$', '#',
+			'{', '}', '[', ']', '=',
+			';', '?', '%20', '%22',
+			'%3c',		// <
+			'%253c',	// <
+			'%3e',		// >
+			'%0e',		// >
+			'%28',		// (
+			'%29',		// )
+			'%2528',	// (
+			'%26',		// &
+			'%24',		// $
+			'%3f',		// ?
+			'%3b',		// ;
+			'%3d'		// =
+		);
 
 		if ( ! $relative_path)
 		{
@@ -549,8 +566,8 @@
 	 * Callback function for xss_clean() to remove whitespace from
 	 * things like j a v a s c r i p t
 	 *
-	 * @param	type
-	 * @return	type
+	 * @param	array
+	 * @return	string
 	 */
 	protected function _compact_exploded_words($matches)
 	{
@@ -559,8 +576,8 @@
 
 	// --------------------------------------------------------------------
 
-	/*
-	 * Remove Evil HTML Attributes (like evenhandlers and style)
+	/**
+	 * Remove Evil HTML Attributes (like event handlers and style)
 	 *
 	 * It removes the evil attribute and either:
 	 * 	- Everything up until a space
@@ -593,15 +610,16 @@
 			$attribs = array();
 
 			// find occurrences of illegal attribute strings without quotes
-			preg_match_all('/('.implode('|', $evil_attributes).')\s*=\s*([^\s]*)/is', $str, $matches, PREG_SET_ORDER);
+			preg_match_all('/('.implode('|', $evil_attributes).')\s*=\s*([^\s>]*)/is', $str, $matches, PREG_SET_ORDER);
 
 			foreach ($matches as $attr)
 			{
+
 				$attribs[] = preg_quote($attr[0], '/');
 			}
 
 			// find occurrences of illegal attribute strings with quotes (042 and 047 are octal quotes)
-			preg_match_all('/('.implode('|', $evil_attributes).')\s*=\s*(\042|\047)([^\\2]*?)(\\2)/is',  $str, $matches, PREG_SET_ORDER);
+			preg_match_all('/('.implode('|', $evil_attributes).')\s*=\s*(\042|\047)([^\\2]*?)(\\2)/is', $str, $matches, PREG_SET_ORDER);
 
 			foreach ($matches as $attr)
 			{
@@ -611,7 +629,7 @@
 			// replace illegal attribute strings that are inside an html tag
 			if (count($attribs) > 0)
 			{
-				$str = preg_replace('/<(\/?[^><]+?)([^A-Za-z\-])('.implode('|', $attribs).')([\s><])([><]*)/i', '<$1$2$4$5', $str, -1, $count);
+				$str = preg_replace('/<(\/?[^><]+?)([^A-Za-z<>\-])(.*?)('.implode('|', $attribs).')(.*?)([\s><])([><]*)/i', '<$1 $3$5$6$7', $str, -1, $count);
 			}
 
 		} while ($count);
@@ -633,7 +651,7 @@
 	{
 		return '&lt;'.$matches[1].$matches[2].$matches[3] // encode opening brace
 			// encode captured opening or closing brace to prevent recursive vectors:
-			. str_replace(array('>', '<'), array('&gt;', '&lt;'), $matches[4]);
+			.str_replace(array('>', '<'), array('&gt;', '&lt;'), $matches[4]);
 	}
 
 	// --------------------------------------------------------------------
@@ -652,7 +670,7 @@
 	protected function _js_link_removal($match)
 	{
 		return str_replace($match[1],
-					preg_replace('#href=.*?(alert\(|alert&\#40;|javascript\:|livescript\:|mocha\:|charset\=|window\.|document\.|\.cookie|<script|<xss|base64\s*,)#si',
+					preg_replace('#href=.*?(alert\(|alert&\#40;|javascript\:|livescript\:|mocha\:|charset\=|window\.|document\.|\.cookie|<script|<xss|data\s*:)#si',
 							'',
 							$this->_filter_attributes(str_replace(array('<', '>'), '', $match[1]))
 					),
@@ -792,7 +810,7 @@
 
 		foreach ($this->_never_allowed_regex as $regex)
 		{
-			$str = preg_replace('#'.$regex.'#i', '[removed]', $str);
+			$str = preg_replace('#'.$regex.'#is', '[removed]', $str);
 		}
 
 		return $str;
@@ -807,14 +825,14 @@
 	 */
 	protected function _csrf_set_hash()
 	{
-		if ($this->_csrf_hash == '')
+		if ($this->_csrf_hash === '')
 		{
 			// If the cookie exists we will use it's 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
 			if (isset($_COOKIE[$this->_csrf_cookie_name]) &&
-				$_COOKIE[$this->_csrf_cookie_name] != '')
+				preg_match('#^[0-9a-f]{32}$#iS', $_COOKIE[$this->_csrf_cookie_name]) === 1)
 			{
 				return $this->_csrf_hash = $_COOKIE[$this->_csrf_cookie_name];
 			}
@@ -829,4 +847,4 @@
 }
 
 /* End of file Security.php */
-/* Location: ./system/core/Security.php */
+/* Location: ./system/core/Security.php */
\ No newline at end of file
diff --git a/system/core/URI.php b/system/core/URI.php
old mode 100755
new mode 100644
index b28ee19..a575bc3
--- a/system/core/URI.php
+++ b/system/core/URI.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * URI Class
  *
@@ -45,26 +43,29 @@
 	 *
 	 * @var array
 	 */
-	public $keyval		= array();
+	public $keyval =	array();
+
 	/**
 	 * Current uri string
 	 *
 	 * @var string
 	 */
 	public $uri_string;
+
 	/**
 	 * List of uri segments
 	 *
 	 * @var array
 	 */
-	public $segments	= array();
+	public $segments =	array();
+
 	/**
 	 * Re-indexed list of uri segments
 	 * Starts at 1 instead of 0
 	 *
 	 * @var array
 	 */
-	public $rsegments	= array();
+	public $rsegments =	array();
 
 	/**
 	 * Constructor
@@ -72,6 +73,8 @@
 	 * 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()
 	{
@@ -93,7 +96,7 @@
 		if (strtoupper($this->config->item('uri_protocol')) === 'AUTO')
 		{
 			// Is the request coming from the command line?
-			if (php_sapi_name() === 'cli' OR defined('STDIN'))
+			if ($this->_is_cli_request())
 			{
 				$this->_set_uri_string($this->_parse_cli_args());
 				return;
@@ -108,8 +111,8 @@
 
 			// Is there a PATH_INFO variable?
 			// Note: some servers seem to have trouble with getenv() so we'll test it two ways
-			$path = (isset($_SERVER['PATH_INFO'])) ? $_SERVER['PATH_INFO'] : @getenv('PATH_INFO');
-			if (trim($path, '/') != '' && $path !== '/'.SELF)
+			$path = isset($_SERVER['PATH_INFO']) ? $_SERVER['PATH_INFO'] : @getenv('PATH_INFO');
+			if (trim($path, '/') !== '' && $path !== '/'.SELF)
 			{
 				$this->_set_uri_string($path);
 				return;
@@ -117,14 +120,14 @@
 
 			// No PATH_INFO?... What about QUERY_STRING?
 			$path = (isset($_SERVER['QUERY_STRING'])) ? $_SERVER['QUERY_STRING'] : @getenv('QUERY_STRING');
-			if (trim($path, '/') != '')
+			if (trim($path, '/') !== '')
 			{
 				$this->_set_uri_string($path);
 				return;
 			}
 
 			// As a last ditch effort lets try using the $_GET array
-			if (is_array($_GET) && count($_GET) === 1 && trim(key($_GET), '/') != '')
+			if (is_array($_GET) && count($_GET) === 1 && trim(key($_GET), '/') !== '')
 			{
 				$this->_set_uri_string(key($_GET));
 				return;
@@ -148,7 +151,7 @@
 			return;
 		}
 
-		$path = (isset($_SERVER[$uri])) ? $_SERVER[$uri] : @getenv($uri);
+		$path = isset($_SERVER[$uri]) ? $_SERVER[$uri] : @getenv($uri);
 		$this->_set_uri_string($path);
 	}
 
@@ -181,7 +184,7 @@
 	 */
 	protected function _detect_uri()
 	{
-		if ( ! isset($_SERVER['REQUEST_URI']) OR ! isset($_SERVER['SCRIPT_NAME']))
+		if ( ! isset($_SERVER['REQUEST_URI'], $_SERVER['SCRIPT_NAME']))
 		{
 			return '';
 		}
@@ -215,7 +218,7 @@
 			$_GET = array();
 		}
 
-		if ($uri == '/' OR empty($uri))
+		if ($uri === '/' OR empty($uri))
 		{
 			return '/';
 		}
@@ -229,6 +232,20 @@
 	// --------------------------------------------------------------------
 
 	/**
+	 * Is cli Request?
+	 *
+	 * Duplicate of function from the Input class to test to see if a request was made from the command line
+	 *
+	 * @return 	bool
+	 */
+	protected function _is_cli_request()
+	{
+		return (php_sapi_name() === 'cli') OR defined('STDIN');
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
 	 * Parse cli arguments
 	 *
 	 * Take each command line argument and assume it is a URI segment.
@@ -238,7 +255,7 @@
 	protected function _parse_cli_args()
 	{
 		$args = array_slice($_SERVER['argv'], 1);
-		return $args ? '/' . implode('/', $args) : '';
+		return $args ? '/'.implode('/', $args) : '';
 	}
 
 	// --------------------------------------------------------------------
@@ -253,7 +270,7 @@
 	 */
 	public function _filter_uri($str)
 	{
-		if ($str != '' && $this->config->item('permitted_uri_chars') != '' && $this->config->item('enable_query_strings') == FALSE)
+		if ($str !== '' && $this->config->item('permitted_uri_chars') != '' && $this->config->item('enable_query_strings') === FALSE)
 		{
 			// 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
@@ -281,7 +298,7 @@
 	 */
 	public function _remove_url_suffix()
 	{
-		if  ($this->config->item('url_suffix') != '')
+		if  ($this->config->item('url_suffix') !== '')
 		{
 			$this->uri_string = preg_replace('|'.preg_quote($this->config->item('url_suffix')).'$|', '', $this->uri_string);
 		}
@@ -304,7 +321,7 @@
 			// Filter segments for security
 			$val = trim($this->_filter_uri($val));
 
-			if ($val != '')
+			if ($val !== '')
 			{
 				$this->segments[] = $val;
 			}
@@ -312,6 +329,7 @@
 	}
 
 	// --------------------------------------------------------------------
+
 	/**
 	 * Re-index Segments
 	 *
@@ -339,13 +357,13 @@
 	 *
 	 * This function returns the URI segment based on the number provided.
 	 *
-	 * @param	integer
-	 * @param	bool
+	 * @param	int
+	 * @param	mixed
 	 * @return	string
 	 */
-	public function segment($n, $no_result = FALSE)
+	public function segment($n, $no_result = NULL)
 	{
-		return ( ! isset($this->segments[$n])) ? $no_result : $this->segments[$n];
+		return isset($this->segments[$n]) ? $this->segments[$n] : $no_result;
 	}
 
 	// --------------------------------------------------------------------
@@ -354,16 +372,16 @@
 	 * Fetch a URI "routed" Segment
 	 *
 	 * This function returns the re-routed URI segment (assuming routing rules are used)
-	 * based on the number provided.  If there is no routing this function returns the
+	 * based on the number provided. If there is no routing this function returns the
 	 * same result as $this->segment()
 	 *
-	 * @param	integer
-	 * @param	bool
+	 * @param	int
+	 * @param	mixed
 	 * @return	string
 	 */
-	public function rsegment($n, $no_result = FALSE)
+	public function rsegment($n, $no_result = NULL)
 	{
-		return ( ! isset($this->rsegments[$n])) ? $no_result : $this->rsegments[$n];
+		return isset($this->rsegments[$n]) ? $this->rsegments[$n] : $no_result;
 	}
 
 	// --------------------------------------------------------------------
@@ -384,7 +402,7 @@
 	 *			gender => male
 	 *		 )
 	 *
-	 * @param	integer	the starting segment number
+	 * @param	int	the starting segment number
 	 * @param	array	an array of default values
 	 * @return	array
 	 */
@@ -392,10 +410,13 @@
 	{
 		return $this->_uri_to_assoc($n, $default, 'segment');
 	}
+
+	// --------------------------------------------------------------------
+
 	/**
 	 * Identical to above only it uses the re-routed segment array
 	 *
-	 * @param 	integer	the starting segment number
+	 * @param 	int	the starting segment number
 	 * @param 	array	an array of default values
 	 * @return 	array
 	 */
@@ -409,7 +430,7 @@
 	/**
 	 * Generate a key value pair from the URI string or Re-routed URI string
 	 *
-	 * @param	integer	the starting segment number
+	 * @param	int	the starting segment number
 	 * @param	array	an array of default values
 	 * @param	string	which array we should use
 	 * @return	array
@@ -439,14 +460,9 @@
 
 		if ($this->$total_segments() < $n)
 		{
-			if (count($default) === 0)
-			{
-				return array();
-			}
-
-			return function_exists('array_fill_keys')
-				? array_fill_keys($default, FALSE)
-				: array_combine($default, array_fill(0, count($default), FALSE));
+			return (count($default) === 0)
+				? array()
+				: array_fill_keys($default, NULL);
 		}
 
 		$segments = array_slice($this->$segment_array(), ($n - 1));
@@ -461,7 +477,7 @@
 			}
 			else
 			{
-				$retval[$seg] = FALSE;
+				$retval[$seg] = NULL;
 				$lastval = $seg;
 			}
 
@@ -474,7 +490,7 @@
 			{
 				if ( ! array_key_exists($val, $retval))
 				{
-					$retval[$val] = FALSE;
+					$retval[$val] = NULL;
 				}
 			}
 		}
@@ -489,14 +505,13 @@
 	/**
 	 * Generate a URI string from an associative array
 	 *
-	 *
 	 * @param	array	an associative array of key/values
 	 * @return	array
 	 */
 	public function assoc_to_uri($array)
 	{
 		$temp = array();
-		foreach ((array)$array as $key => $val)
+		foreach ((array) $array as $key => $val)
 		{
 			$temp[] = $key;
 			$temp[] = $val;
@@ -510,7 +525,7 @@
 	/**
 	 * Fetch a URI Segment and add a trailing slash
 	 *
-	 * @param	integer
+	 * @param	int
 	 * @param	string
 	 * @return	string
 	 */
@@ -524,7 +539,7 @@
 	/**
 	 * Fetch a URI Segment and add a trailing slash
 	 *
-	 * @param	integer
+	 * @param	int
 	 * @param	string
 	 * @return	string
 	 */
@@ -538,7 +553,7 @@
 	/**
 	 * Fetch a URI Segment and add a trailing slash - helper function
 	 *
-	 * @param	integer
+	 * @param	int
 	 * @param	string
 	 * @param	string
 	 * @return	string
@@ -588,7 +603,7 @@
 	/**
 	 * Total number of segments
 	 *
-	 * @return	integer
+	 * @return	int
 	 */
 	public function total_segments()
 	{
@@ -600,7 +615,7 @@
 	/**
 	 * Total number of routed segments
 	 *
-	 * @return	integer
+	 * @return	int
 	 */
 	public function total_rsegments()
 	{
@@ -629,10 +644,10 @@
 	 */
 	public function ruri_string()
 	{
-		return '/'.implode('/', $this->rsegment_array());
+		return implode('/', $this->rsegment_array());
 	}
 
 }
 
 /* End of file URI.php */
-/* Location: ./system/core/URI.php */
+/* Location: ./system/core/URI.php */
\ No newline at end of file
diff --git a/system/core/Utf8.php b/system/core/Utf8.php
index 0e180d3..0a7ec50 100644
--- a/system/core/Utf8.php
+++ b/system/core/Utf8.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * Utf8 Class
  *
@@ -44,6 +42,8 @@
 	 * Constructor
 	 *
 	 * Determines if UTF-8 support is to be enabled
+	 *
+	 * @return	void
 	 */
 	public function __construct()
 	{
@@ -54,7 +54,7 @@
 		if (
 			@preg_match('/./u', 'é') === 1		// PCRE must support UTF-8
 			&& function_exists('iconv')			// iconv must be installed
-			&& @ini_get('mbstring.func_overload') != 1	// Multibyte string function overloading cannot be enabled
+			&& (bool) @ini_get('mbstring.func_overload') !== TRUE	// Multibyte string function overloading cannot be enabled
 			&& $CFG->item('charset') === 'UTF-8'		// Application charset must be UTF-8
 			)
 		{
@@ -126,7 +126,7 @@
 	 * Attempts to convert a string to UTF-8
 	 *
 	 * @param	string
-	 * @param	string	- input encoding
+	 * @param	string	input encoding
 	 * @return	string
 	 */
 	public function convert_to_utf8($str, $encoding)
@@ -161,4 +161,4 @@
 }
 
 /* End of file Utf8.php */
-/* Location: ./system/core/Utf8.php */
+/* Location: ./system/core/Utf8.php */
\ No newline at end of file
diff --git a/system/database/DB.php b/system/database/DB.php
old mode 100755
new mode 100644
index ed6afd7..00d14b4
--- a/system/database/DB.php
+++ b/system/database/DB.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -32,16 +32,16 @@
  * @author		EllisLab Dev Team
  * @link		http://codeigniter.com/user_guide/database/
  * @param 	string
- * @param 	bool	Determines if active record should be used or not
+ * @param 	bool	Determines if query builder should be used or not
  */
-function &DB($params = '', $active_record_override = NULL)
+function &DB($params = '', $query_builder_override = NULL)
 {
 	// Load the DB config file if a DSN string wasn't passed
-	if (is_string($params) AND strpos($params, '://') === FALSE)
+	if (is_string($params) && strpos($params, '://') === FALSE)
 	{
 		// Is the config file in the environment folder?
 		if (( ! defined('ENVIRONMENT') OR ! file_exists($file_path = APPPATH.'config/'.ENVIRONMENT.'/database.php'))
-			AND ! file_exists($file_path = APPPATH.'config/database.php'))
+			&& ! file_exists($file_path = APPPATH.'config/database.php'))
 		{
 			show_error('The configuration file database.php does not exist.');
 		}
@@ -53,7 +53,7 @@
 			show_error('No database connection settings were found in the database config file.');
 		}
 
-		if ($params != '')
+		if ($params !== '')
 		{
 			$active_group = $params;
 		}
@@ -74,33 +74,30 @@
 		 *  parameter. DSNs must have this prototype:
 		 *  $dsn = 'driver://username:password@hostname/database';
 		 */
-		if (($dns = @parse_url($params)) === FALSE)
+		if (($dsn = @parse_url($params)) === FALSE)
 		{
 			show_error('Invalid DB Connection String');
 		}
 
 		$params = array(
-				'dbdriver'	=> $dns['scheme'],
-				'hostname'	=> (isset($dns['host'])) ? rawurldecode($dns['host']) : '',
-				'username'	=> (isset($dns['user'])) ? rawurldecode($dns['user']) : '',
-				'password'	=> (isset($dns['pass'])) ? rawurldecode($dns['pass']) : '',
-				'database'	=> (isset($dns['path'])) ? rawurldecode(substr($dns['path'], 1)) : ''
+				'dbdriver'	=> $dsn['scheme'],
+				'hostname'	=> isset($dsn['host']) ? rawurldecode($dsn['host']) : '',
+				'port'		=> isset($dsn['port']) ? rawurldecode($dsn['port']) : '',
+				'username'	=> isset($dsn['user']) ? rawurldecode($dsn['user']) : '',
+				'password'	=> isset($dsn['pass']) ? rawurldecode($dsn['pass']) : '',
+				'database'	=> isset($dsn['path']) ? rawurldecode(substr($dsn['path'], 1)) : ''
 			);
 
 		// were additional config items set?
-		if (isset($dns['query']))
+		if (isset($dsn['query']))
 		{
-			parse_str($dns['query'], $extra);
+			parse_str($dsn['query'], $extra);
+
 			foreach ($extra as $key => $val)
 			{
-				// booleans please
-				if (strtoupper($val) === 'TRUE')
+				if (is_string($val) && in_array(strtoupper($val), array('TRUE', 'FALSE', 'NULL')))
 				{
-					$val = TRUE;
-				}
-				elseif (strtoupper($val) === 'FALSE')
-				{
-					$val = FALSE;
+					$val = var_export($val);
 				}
 
 				$params[$key] = $val;
@@ -109,27 +106,34 @@
 	}
 
 	// No DB specified yet? Beat them senseless...
-	if ( ! isset($params['dbdriver']) OR $params['dbdriver'] == '')
+	if (empty($params['dbdriver']))
 	{
 		show_error('You have not selected a database type to connect to.');
 	}
 
-	// Load the DB classes. Note: Since the active record class is optional
+	// Load the DB classes. Note: Since the query builder class is optional
 	// we need to dynamically create a class that extends proper parent class
-	// based on whether we're using the active record class or not.
-	if ($active_record_override !== NULL)
+	// based on whether we're using the query builder class or not.
+	if ($query_builder_override !== NULL)
 	{
-		$active_record = $active_record_override;
+		$query_builder = $query_builder_override;
+	}
+	// Backwards compatibility work-around for keeping the
+	// $active_record config variable working. Should be
+	// removed in v3.1
+	elseif ( ! isset($query_builder) && isset($active_record))
+	{
+		$query_builder = $active_record;
 	}
 
 	require_once(BASEPATH.'database/DB_driver.php');
 
-	if ( ! isset($active_record) OR $active_record == TRUE)
+	if ( ! isset($query_builder) OR $query_builder === TRUE)
 	{
-		require_once(BASEPATH.'database/DB_active_rec.php');
+		require_once(BASEPATH.'database/DB_query_builder.php');
 		if ( ! class_exists('CI_DB'))
 		{
-			class CI_DB extends CI_DB_active_record { }
+			class CI_DB extends CI_DB_query_builder { }
 		}
 	}
 	elseif ( ! class_exists('CI_DB'))
@@ -137,18 +141,23 @@
 		class CI_DB extends CI_DB_driver { }
 	}
 
-	require_once(BASEPATH.'database/drivers/'.$params['dbdriver'].'/'.$params['dbdriver'].'_driver.php');
+	// Load the DB driver
+	$driver_file = BASEPATH.'database/drivers/'.$params['dbdriver'].'/'.$params['dbdriver'].'_driver.php';
+
+	if ( ! file_exists($driver_file)) show_error('Invalid DB driver');
+
+	require_once($driver_file);
 
 	// Instantiate the DB adapter
 	$driver = 'CI_DB_'.$params['dbdriver'].'_driver';
 	$DB = new $driver($params);
 
-	if ($DB->autoinit == TRUE)
+	if ($DB->autoinit === TRUE)
 	{
 		$DB->initialize();
 	}
 
-	if (isset($params['stricton']) && $params['stricton'] == TRUE)
+	if ( ! empty($params['stricton']))
 	{
 		$DB->query('SET SESSION sql_mode="STRICT_ALL_TABLES"');
 	}
@@ -157,4 +166,4 @@
 }
 
 /* End of file DB.php */
-/* Location: ./system/database/DB.php */
+/* Location: ./system/database/DB.php */
\ No newline at end of file
diff --git a/system/database/DB_cache.php b/system/database/DB_cache.php
index 79651fc..ba91103 100644
--- a/system/database/DB_cache.php
+++ b/system/database/DB_cache.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -55,9 +55,9 @@
 	 */
 	public function check_path($path = '')
 	{
-		if ($path == '')
+		if ($path === '')
 		{
-			if ($this->db->cachedir == '')
+			if ($this->db->cachedir === '')
 			{
 				return $this->db->cache_off();
 			}
@@ -99,7 +99,7 @@
 		$segment_two = ($this->CI->uri->segment(2) == FALSE) ? 'index' : $this->CI->uri->segment(2);
 		$filepath = $this->db->cachedir.$segment_one.'+'.$segment_two.'/'.md5($sql);
 
-		if (FALSE === ($cachedata = read_file($filepath)))
+		if (FALSE === ($cachedata = file_get_contents($filepath)))
 		{
 			return FALSE;
 		}
@@ -154,12 +154,12 @@
 	 */
 	public function delete($segment_one = '', $segment_two = '')
 	{
-		if ($segment_one == '')
+		if ($segment_one === '')
 		{
 			$segment_one  = ($this->CI->uri->segment(1) == FALSE) ? 'default' : $this->CI->uri->segment(1);
 		}
 
-		if ($segment_two == '')
+		if ($segment_two === '')
 		{
 			$segment_two = ($this->CI->uri->segment(2) == FALSE) ? 'index' : $this->CI->uri->segment(2);
 		}
@@ -177,10 +177,10 @@
 	 */
 	public function delete_all()
 	{
-		delete_files($this->db->cachedir, TRUE);
+		delete_files($this->db->cachedir, TRUE, 0, TRUE);
 	}
 
 }
 
 /* End of file DB_cache.php */
-/* Location: ./system/database/DB_cache.php */
+/* Location: ./system/database/DB_cache.php */
\ No newline at end of file
diff --git a/system/database/DB_driver.php b/system/database/DB_driver.php
index 7445a50..079ee8d 100644
--- a/system/database/DB_driver.php
+++ b/system/database/DB_driver.php
@@ -1,13 +1,13 @@
-<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
- * 
+ *
  * Licensed under the Open Software License version 3.0
- * 
+ *
  * This source file is subject to the Open Software License (OSL 3.0) that is
  * bundled with this package in the files license.txt / license.rst.  It is
  * also available through the world wide web at this URL:
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * Database Driver Class
  *
@@ -40,57 +38,46 @@
  * @author		EllisLab Dev Team
  * @link		http://codeigniter.com/user_guide/database/
  */
-class CI_DB_driver {
+abstract class CI_DB_driver {
 
-	var $username;
-	var $password;
-	var $hostname;
-	var $database;
-	var $dbdriver		= 'mysql';
-	var $dbprefix		= '';
-	var $char_set		= 'utf8';
-	var $dbcollat		= 'utf8_general_ci';
-	var $autoinit		= TRUE; // Whether to automatically initialize the DB
-	var $swap_pre		= '';
-	var $port			= '';
-	var $pconnect		= FALSE;
-	var $conn_id		= FALSE;
-	var $result_id		= FALSE;
-	var $db_debug		= FALSE;
-	var $benchmark		= 0;
-	var $query_count	= 0;
-	var $bind_marker	= '?';
-	var $save_queries	= TRUE;
-	var $queries		= array();
-	var $query_times	= array();
-	var $data_cache		= array();
-	var $trans_enabled	= TRUE;
-	var $trans_strict	= TRUE;
-	var $_trans_depth	= 0;
-	var $_trans_status	= TRUE; // Used with transactions to determine if a rollback should occur
-	var $cache_on		= FALSE;
-	var $cachedir		= '';
-	var $cache_autodel	= FALSE;
-	var $CACHE; // The cache class object
+	public $dsn;
+	public $username;
+	public $password;
+	public $hostname;
+	public $database;
+	public $dbdriver		= 'mysql';
+	public $dbprefix		= '';
+	public $char_set		= 'utf8';
+	public $dbcollat		= 'utf8_general_ci';
+	public $autoinit		= TRUE; // Whether to automatically initialize the DB
+	public $swap_pre		= '';
+	public $port			= '';
+	public $pconnect		= FALSE;
+	public $conn_id			= FALSE;
+	public $result_id		= FALSE;
+	public $db_debug		= FALSE;
+	public $benchmark		= 0;
+	public $query_count		= 0;
+	public $bind_marker		= '?';
+	public $save_queries		= TRUE;
+	public $queries			= array();
+	public $query_times		= array();
+	public $data_cache		= array();
 
-	// Private variables
-	var $_protect_identifiers	= TRUE;
-	var $_reserved_identifiers	= array('*'); // Identifiers that should NOT be escaped
+	public $trans_enabled		= TRUE;
+	public $trans_strict		= TRUE;
+	protected $_trans_depth		= 0;
+	protected $_trans_status	= TRUE; // Used with transactions to determine if a rollback should occur
 
-	// These are use with Oracle
-	var $stmt_id;
-	var $curs_id;
-	var $limit_used;
+	public $cache_on		= FALSE;
+	public $cachedir		= '';
+	public $cache_autodel		= FALSE;
+	public $CACHE; // The cache class object
 
+	protected $_protect_identifiers		= TRUE;
+	protected $_reserved_identifiers	= array('*'); // Identifiers that should NOT be escaped
 
-
-	/**
-	 * Constructor.  Accepts one parameter containing the database
-	 * connection settings.
-	 *
-	 * @param array
-	 */
-	function __construct($params)
+	public function __construct($params)
 	{
 		if (is_array($params))
 		{
@@ -108,15 +95,17 @@
 	/**
 	 * Initialize Database Settings
 	 *
-	 * @access	private Called by the constructor
-	 * @param	mixed
-	 * @return	void
+	 * @return	bool
 	 */
-	function initialize()
+	public function initialize()
 	{
-		// If an existing connection resource is available
-		// there is no need to connect and select the database
-		if (is_resource($this->conn_id) OR is_object($this->conn_id))
+		/* If an established connection is available, then there's
+		 * no need to connect and select the database.
+		 *
+		 * Depending on the database driver, conn_id can be either
+		 * boolean TRUE, a resource or an object.
+		 */
+		if ($this->conn_id)
 		{
 			return TRUE;
 		}
@@ -124,9 +113,9 @@
 		// ----------------------------------------------------------------
 
 		// Connect to the database and set the connection ID
-		$this->conn_id = ($this->pconnect == FALSE) ? $this->db_connect() : $this->db_pconnect();
+		$this->conn_id = ($this->pconnect === FALSE) ? $this->db_connect() : $this->db_pconnect();
 
-		// No connection resource?  Check if there is a failover else throw an error
+		// No connection resource? Check if there is a failover else throw an error
 		if ( ! $this->conn_id)
 		{
 			// Check if there is a failover set
@@ -142,7 +131,7 @@
 					}
 
 					// Try to connect
-					$this->conn_id = ($this->pconnect == FALSE) ? $this->db_connect() : $this->db_pconnect();
+					$this->conn_id = ($this->pconnect === FALSE) ? $this->db_connect() : $this->db_pconnect();
 
 					// If a connection is made break the foreach loop
 					if ($this->conn_id)
@@ -168,30 +157,50 @@
 		// ----------------------------------------------------------------
 
 		// Select the DB... assuming a database name is specified in the config file
-		if ($this->database != '')
+		if ($this->database !== '' && ! $this->db_select())
 		{
-			if ( ! $this->db_select())
-			{
-				log_message('error', 'Unable to select database: '.$this->database);
+			log_message('error', 'Unable to select database: '.$this->database);
 
-				if ($this->db_debug)
-				{
-					$this->display_error('db_unable_to_select', $this->database);
-				}
-				return FALSE;
-			}
-			else
+			if ($this->db_debug)
 			{
-				// We've selected the DB. Now we set the character set
-				if ( ! $this->db_set_charset($this->char_set, $this->dbcollat))
-				{
-					return FALSE;
-				}
-
-				return TRUE;
+				$this->display_error('db_unable_to_select', $this->database);
 			}
+			return FALSE;
 		}
 
+		// Now we set the character set and that's all
+		return $this->db_set_charset($this->char_set);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Reconnect
+	 *
+	 * Keep / reestablish the db connection if no queries have been
+	 * sent for a length of time exceeding the server's idle timeout.
+	 *
+	 * This is just a dummy method to allow drivers without such
+	 * functionality to not declare it, while others will override it.
+	 *
+	 * @return      void
+	 */
+	public function reconnect()
+	{
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Select database
+	 *
+	 * This is just a dummy method to allow drivers without such
+	 * functionality to not declare it, while others will override it.
+	 *
+	 * @return      bool
+	 */
+	public function db_select()
+	{
 		return TRUE;
 	}
 
@@ -200,20 +209,18 @@
 	/**
 	 * Set client character set
 	 *
-	 * @access	public
 	 * @param	string
-	 * @param	string
-	 * @return	resource
+	 * @return	bool
 	 */
-	function db_set_charset($charset, $collation)
+	public function db_set_charset($charset)
 	{
-		if ( ! $this->_db_set_charset($this->char_set, $this->dbcollat))
+		if (method_exists($this, '_db_set_charset') && ! $this->_db_set_charset($charset))
 		{
-			log_message('error', 'Unable to set database connection charset: '.$this->char_set);
+			log_message('error', 'Unable to set database connection charset: '.$charset);
 
 			if ($this->db_debug)
 			{
-				$this->display_error('db_unable_to_set_charset', $this->char_set);
+				$this->display_error('db_unable_to_set_charset', $charset);
 			}
 
 			return FALSE;
@@ -227,10 +234,9 @@
 	/**
 	 * The name of the platform in use (mysql, mssql, etc...)
 	 *
-	 * @access	public
 	 * @return	string
 	 */
-	function platform()
+	public function platform()
 	{
 		return $this->dbdriver;
 	}
@@ -238,36 +244,40 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 * Database Version Number.  Returns a string containing the
-	 * version of the database being used
+	 * Database version number
 	 *
-	 * @access	public
+	 * Returns a string containing the version of the database being used.
+	 * Most drivers will override this method.
+	 *
 	 * @return	string
 	 */
-	function version()
+	public function version()
 	{
+		if (isset($this->data_cache['version']))
+		{
+			return $this->data_cache['version'];
+		}
+
 		if (FALSE === ($sql = $this->_version()))
 		{
-			if ($this->db_debug)
-			{
-				return $this->display_error('db_unsupported_function');
-			}
-			return FALSE;
+			return ($this->db_debug) ? $this->display_error('db_unsupported_function') : FALSE;
 		}
 
-		// Some DBs have functions that return the version, and don't run special
-		// SQL queries per se. In these instances, just return the result.
-		$driver_version_exceptions = array('oci8', 'sqlite', 'cubrid', 'pdo', 'mysqli');
+		$query = $this->query($sql);
+		$query = $query->row();
+		return $this->data_cache['version'] = $query->ver;
+	}
 
-		if (in_array($this->dbdriver, $driver_version_exceptions))
-		{
-			return $sql;
-		}
-		else
-		{
-			$query = $this->query($sql);
-			return $query->row('ver');
-		}
+	// --------------------------------------------------------------------
+
+	/**
+	 * Version number query string
+	 *
+	 * @return	string
+	 */
+	protected function _version()
+	{
+		return 'SELECT VERSION() AS ver';
 	}
 
 	// --------------------------------------------------------------------
@@ -276,48 +286,28 @@
 	 * Execute the query
 	 *
 	 * Accepts an SQL string as input and returns a result object upon
-	 * successful execution of a "read" type query.  Returns boolean TRUE
+	 * successful execution of a "read" type query. Returns boolean TRUE
 	 * upon successful execution of a "write" type query. Returns boolean
 	 * FALSE upon failure, and if the $db_debug variable is set to TRUE
 	 * will raise an error.
 	 *
-	 * @access	public
 	 * @param	string	An SQL query string
 	 * @param	array	An array of binding data
 	 * @return	mixed
 	 */
-	function query($sql, $binds = FALSE, $return_object = TRUE)
+	public function query($sql, $binds = FALSE, $return_object = TRUE)
 	{
-		if ($sql == '')
+		if ($sql === '')
 		{
 			log_message('error', 'Invalid query: '.$sql);
 
-			if ($this->db_debug)
-			{
-				return $this->display_error('db_invalid_query');
-			}
-			return FALSE;
+			return ($this->db_debug) ? $this->display_error('db_invalid_query') : FALSE;
 		}
 
 		// Verify table prefix and replace if necessary
-		if ( ($this->dbprefix != '' AND $this->swap_pre != '') AND ($this->dbprefix != $this->swap_pre) )
+		if ($this->dbprefix !== '' && $this->swap_pre !== '' && $this->dbprefix !== $this->swap_pre)
 		{
-			$sql = preg_replace("/(\W)".$this->swap_pre."(\S+?)/", "\\1".$this->dbprefix."\\2", $sql);
-		}
-
-		// Is query caching enabled?  If the query is a "read type"
-		// we will load the caching class and return the previously
-		// cached query if it exists
-		if ($this->cache_on == TRUE AND stristr($sql, 'SELECT'))
-		{
-			if ($this->_cache_init())
-			{
-				$this->load_rdriver();
-				if (FALSE !== ($cache = $this->CACHE->read($sql)))
-				{
-					return $cache;
-				}
-			}
+			$sql = preg_replace('/(\W)'.$this->swap_pre.'(\S+?)/', '\\1'.$this->dbprefix.'\\2', $sql);
 		}
 
 		// Compile binds if needed
@@ -326,19 +316,31 @@
 			$sql = $this->compile_binds($sql, $binds);
 		}
 
+		// Is query caching enabled? If the query is a "read type"
+		// we will load the caching class and return the previously
+		// cached query if it exists
+		if ($this->cache_on === TRUE && stripos($sql, 'SELECT') !== FALSE && $this->_cache_init())
+		{
+			$this->load_rdriver();
+			if (FALSE !== ($cache = $this->CACHE->read($sql)))
+			{
+				return $cache;
+			}
+		}
+
 		// Save the  query for debugging
-		if ($this->save_queries == TRUE)
+		if ($this->save_queries === TRUE)
 		{
 			$this->queries[] = $sql;
 		}
 
 		// Start the Query Timer
-		$time_start = list($sm, $ss) = explode(' ', microtime());
+		$time_start = microtime(TRUE);
 
 		// Run the Query
 		if (FALSE === ($this->result_id = $this->simple_query($sql)))
 		{
-			if ($this->save_queries == TRUE)
+			if ($this->save_queries === TRUE)
 			{
 				$this->query_times[] = 0;
 			}
@@ -346,42 +348,34 @@
 			// This will trigger a rollback if transactions are being used
 			$this->_trans_status = FALSE;
 
-			// Grab the error number and message now, as we might run some
-			// additional queries before displaying the error
-			$error_no = $this->_error_number();
-			$error_msg = $this->_error_message();
+			// Grab the error now, as we might run some additional queries before displaying the error
+			$error = $this->error();
 
 			// Log errors
-			log_message('error', 'Query error: '.$error_msg);
+			log_message('error', 'Query error: '.$error['message']);
 
 			if ($this->db_debug)
 			{
 				// We call this function in order to roll-back queries
-				// if transactions are enabled.  If we don't call this here
+				// if transactions are enabled. If we don't call this here
 				// the error message will trigger an exit, causing the
 				// transactions to remain in limbo.
 				$this->trans_complete();
 
 				// Display errors
-				return $this->display_error(
-										array(
-												'Error Number: '.$error_no,
-												$error_msg,
-												$sql
-											)
-										);
+				return $this->display_error(array('Error Number: '.$error['code'], $error['message'], $sql));
 			}
 
 			return FALSE;
 		}
 
 		// Stop and aggregate the query time results
-		$time_end = list($em, $es) = explode(' ', microtime());
-		$this->benchmark += ($em + $es) - ($sm + $ss);
+		$time_end = microtime(TRUE);
+		$this->benchmark += $time_end - $time_start;
 
-		if ($this->save_queries == TRUE)
+		if ($this->save_queries === TRUE)
 		{
-			$this->query_times[] = ($em + $es) - ($sm + $ss);
+			$this->query_times[] = $time_end - $time_start;
 		}
 
 		// Increment the query counter
@@ -393,7 +387,7 @@
 		{
 			// If caching is enabled we'll auto-cleanup any
 			// existing files related to this particular URI
-			if ($this->cache_on == TRUE AND $this->cache_autodel == TRUE AND $this->_cache_init())
+			if ($this->cache_on === TRUE && $this->cache_autodel === TRUE && $this->_cache_init())
 			{
 				$this->CACHE->delete();
 			}
@@ -410,26 +404,12 @@
 		}
 
 		// Load and instantiate the result driver
+		$driver		= $this->load_rdriver();
+		$RES		= new $driver($this);
 
-		$driver			= $this->load_rdriver();
-		$RES			= new $driver();
-		$RES->conn_id	= $this->conn_id;
-		$RES->result_id	= $this->result_id;
-
-		if ($this->dbdriver == 'oci8')
-		{
-			$RES->stmt_id		= $this->stmt_id;
-			$RES->curs_id		= NULL;
-			$RES->limit_used	= $this->limit_used;
-			$this->stmt_id		= FALSE;
-		}
-
-		// oci8 vars must be set before calling this
-		$RES->num_rows	= $RES->num_rows();
-
-		// Is query caching enabled?  If so, we'll serialize the
+		// Is query caching enabled? If so, we'll serialize the
 		// result object and save it to a cache file.
-		if ($this->cache_on == TRUE AND $this->_cache_init())
+		if ($this->cache_on === TRUE && $this->_cache_init())
 		{
 			// We'll create a new instance of the result object
 			// only without the platform specific driver since
@@ -438,9 +418,9 @@
 			// result object, so we'll have to compile the data
 			// and save it)
 			$CR = new CI_DB_result();
-			$CR->num_rows		= $RES->num_rows();
 			$CR->result_object	= $RES->result_object();
 			$CR->result_array	= $RES->result_array();
+			$CR->num_rows		= $RES->num_rows();
 
 			// Reset these since cached objects can not utilize resource IDs.
 			$CR->conn_id		= NULL;
@@ -457,10 +437,9 @@
 	/**
 	 * Load the result drivers
 	 *
-	 * @access	public
 	 * @return	string	the name of the result class
 	 */
-	function load_rdriver()
+	public function load_rdriver()
 	{
 		$driver = 'CI_DB_'.$this->dbdriver.'_result';
 
@@ -477,15 +456,14 @@
 
 	/**
 	 * Simple Query
-	 * This is a simplified version of the query() function.  Internally
+	 * This is a simplified version of the query() function. Internally
 	 * we only use it when running transaction commands since they do
 	 * not require all the features of the main query() function.
 	 *
-	 * @access	public
 	 * @param	string	the sql query
 	 * @return	mixed
 	 */
-	function simple_query($sql)
+	public function simple_query($sql)
 	{
 		if ( ! $this->conn_id)
 		{
@@ -501,10 +479,9 @@
 	 * Disable Transactions
 	 * This permits transactions to be disabled at run-time.
 	 *
-	 * @access	public
 	 * @return	void
 	 */
-	function trans_off()
+	public function trans_off()
 	{
 		$this->trans_enabled = FALSE;
 	}
@@ -518,10 +495,9 @@
 	 * If strict mode is disabled, each group is treated autonomously, meaning
 	 * a failure of one group will not affect any others
 	 *
-	 * @access	public
 	 * @return	void
 	 */
-	function trans_strict($mode = TRUE)
+	public function trans_strict($mode = TRUE)
 	{
 		$this->trans_strict = is_bool($mode) ? $mode : TRUE;
 	}
@@ -531,10 +507,9 @@
 	/**
 	 * Start Transaction
 	 *
-	 * @access	public
 	 * @return	void
 	 */
-	function trans_start($test_mode = FALSE)
+	public function trans_start($test_mode = FALSE)
 	{
 		if ( ! $this->trans_enabled)
 		{
@@ -557,10 +532,9 @@
 	/**
 	 * Complete Transaction
 	 *
-	 * @access	public
 	 * @return	bool
 	 */
-	function trans_complete()
+	public function trans_complete()
 	{
 		if ( ! $this->trans_enabled)
 		{
@@ -604,10 +578,9 @@
 	/**
 	 * Lets you retrieve the transaction flag to determine if it has failed
 	 *
-	 * @access	public
 	 * @return	bool
 	 */
-	function trans_status()
+	public function trans_status()
 	{
 		return $this->_trans_status;
 	}
@@ -617,12 +590,11 @@
 	/**
 	 * Compile Bindings
 	 *
-	 * @access	public
 	 * @param	string	the sql statement
 	 * @param	array	an array of bind data
 	 * @return	string
 	 */
-	function compile_binds($sql, $binds)
+	public function compile_binds($sql, $binds)
 	{
 		if (strpos($sql, $this->bind_marker) === FALSE)
 		{
@@ -639,7 +611,8 @@
 
 		// The count of bind should be 1 less then the count of segments
 		// If there are more bind arguments trim it down
-		if (count($binds) >= count($segments)) {
+		if (count($binds) >= count($segments))
+		{
 			$binds = array_slice($binds, 0, count($segments)-1);
 		}
 
@@ -648,8 +621,7 @@
 		$i = 0;
 		foreach ($binds as $bind)
 		{
-			$result .= $this->escape($bind);
-			$result .= $segments[++$i];
+			$result .= $this->escape($bind).$segments[++$i];
 		}
 
 		return $result;
@@ -660,17 +632,12 @@
 	/**
 	 * Determines if a query is a "write" type.
 	 *
-	 * @access	public
 	 * @param	string	An SQL query string
-	 * @return	boolean
+	 * @return	bool
 	 */
-	function is_write_type($sql)
+	public function is_write_type($sql)
 	{
-		if ( ! preg_match('/^\s*"?(SET|INSERT|UPDATE|DELETE|REPLACE|CREATE|DROP|TRUNCATE|LOAD DATA|COPY|ALTER|GRANT|REVOKE|LOCK|UNLOCK)\s+/i', $sql))
-		{
-			return FALSE;
-		}
-		return TRUE;
+		return (bool) preg_match('/^\s*"?(SET|INSERT|UPDATE|DELETE|REPLACE|CREATE|DROP|TRUNCATE|LOAD DATA|COPY|ALTER|RENAME|GRANT|REVOKE|LOCK|UNLOCK|REINDEX)\s+/i', $sql);
 	}
 
 	// --------------------------------------------------------------------
@@ -678,11 +645,10 @@
 	/**
 	 * Calculate the aggregate query elapsed time
 	 *
-	 * @access	public
-	 * @param	integer	The number of decimal places
-	 * @return	integer
+	 * @param	int	The number of decimal places
+	 * @return	int
 	 */
-	function elapsed_time($decimals = 6)
+	public function elapsed_time($decimals = 6)
 	{
 		return number_format($this->benchmark, $decimals);
 	}
@@ -692,10 +658,9 @@
 	/**
 	 * Returns the total number of queries
 	 *
-	 * @access	public
-	 * @return	integer
+	 * @return	int
 	 */
-	function total_queries()
+	public function total_queries()
 	{
 		return $this->query_count;
 	}
@@ -705,10 +670,9 @@
 	/**
 	 * Returns the last query that was executed
 	 *
-	 * @access	public
-	 * @return	void
+	 * @return	string
 	 */
-	function last_query()
+	public function last_query()
 	{
 		return end($this->queries);
 	}
@@ -721,23 +685,22 @@
 	 * Escapes data based on type
 	 * Sets boolean and null types
 	 *
-	 * @access	public
 	 * @param	string
 	 * @return	mixed
 	 */
-	function escape($str)
+	public function escape($str)
 	{
-		if (is_string($str))
+		if (is_string($str) OR method_exists($str, '__toString'))
 		{
-			$str = "'".$this->escape_str($str)."'";
+			return "'".$this->escape_str($str)."'";
 		}
 		elseif (is_bool($str))
 		{
-			$str = ($str === FALSE) ? 0 : 1;
+			return ($str === FALSE) ? 0 : 1;
 		}
 		elseif (is_null($str))
 		{
-			$str = 'NULL';
+			return 'NULL';
 		}
 
 		return $str;
@@ -751,11 +714,10 @@
 	 * Calls the individual driver for platform
 	 * specific escaping for LIKE conditions
 	 *
-	 * @access	public
 	 * @param	string
 	 * @return	mixed
 	 */
-	function escape_like_str($str)
+	public function escape_like_str($str)
 	{
 		return $this->escape_str($str, TRUE);
 	}
@@ -765,23 +727,45 @@
 	/**
 	 * Primary
 	 *
-	 * Retrieves the primary key.  It assumes that the row in the first
+	 * Retrieves the primary key. It assumes that the row in the first
 	 * position is the primary key
 	 *
-	 * @access	public
 	 * @param	string	the table name
 	 * @return	string
 	 */
-	function primary($table = '')
+	public function primary($table = '')
 	{
 		$fields = $this->list_fields($table);
+		return is_array($fields) ? current($fields) : FALSE;
+	}
 
-		if ( ! is_array($fields))
+	// --------------------------------------------------------------------
+
+	/**
+	 * "Count All" query
+	 *
+	 * Generates a platform-specific query string that counts all records in
+	 * the specified database
+	 *
+	 * @param	string
+	 * @return	int
+	 */
+	public function count_all($table = '')
+	{
+		if ($table === '')
 		{
-			return FALSE;
+			return 0;
 		}
 
-		return current($fields);
+		$query = $this->query($this->_count_string.$this->escape_identifiers('numrows').' FROM '.$this->protect_identifiers($table, TRUE, NULL, FALSE));
+		if ($query->num_rows() === 0)
+		{
+			return 0;
+		}
+
+		$query = $query->row();
+		$this->_reset_select();
+		return (int) $query->numrows;
 	}
 
 	// --------------------------------------------------------------------
@@ -789,10 +773,9 @@
 	/**
 	 * Returns an array of table names
 	 *
-	 * @access	public
 	 * @return	array
 	 */
-	function list_tables($constrain_by_prefix = FALSE)
+	public function list_tables($constrain_by_prefix = FALSE)
 	{
 		// Is there a cached result?
 		if (isset($this->data_cache['table_names']))
@@ -802,32 +785,40 @@
 
 		if (FALSE === ($sql = $this->_list_tables($constrain_by_prefix)))
 		{
-			if ($this->db_debug)
-			{
-				return $this->display_error('db_unsupported_function');
-			}
-			return FALSE;
+			return ($this->db_debug) ? $this->display_error('db_unsupported_function') : FALSE;
 		}
 
-		$retval = array();
+		$this->data_cache['table_names'] = array();
 		$query = $this->query($sql);
 
-		if ($query->num_rows() > 0)
+		foreach ($query->result_array() as $row)
 		{
-			foreach ($query->result_array() as $row)
+			// Do we know from which column to get the table name?
+			if ( ! isset($key))
 			{
-				if (isset($row['TABLE_NAME']))
+				if (isset($row['table_name']))
 				{
-					$retval[] = $row['TABLE_NAME'];
+					$key = 'table_name';
+				}
+				elseif (isset($row['TABLE_NAME']))
+				{
+					$key = 'TABLE_NAME';
 				}
 				else
 				{
-					$retval[] = array_shift($row);
+					/* 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
+					 * E_STRICT is on, this would trigger a warning. So we'll have to
+					 * assign it first.
+					 */
+					$key = array_keys($row);
+					$key = array_shift($key);
 				}
 			}
+
+			$this->data_cache['table_names'][] = $row[$key];
 		}
 
-		$this->data_cache['table_names'] = $retval;
 		return $this->data_cache['table_names'];
 	}
 
@@ -835,12 +826,12 @@
 
 	/**
 	 * Determine if a particular table exists
-	 * @access	public
-	 * @return	boolean
+	 *
+	 * @return	bool
 	 */
-	function table_exists($table_name)
+	public function table_exists($table_name)
 	{
-		return ( ! in_array($this->_protect_identifiers($table_name, TRUE, FALSE, FALSE), $this->list_tables())) ? FALSE : TRUE;
+		return in_array($this->protect_identifiers($table_name, TRUE, FALSE, FALSE), $this->list_tables());
 	}
 
 	// --------------------------------------------------------------------
@@ -848,11 +839,10 @@
 	/**
 	 * Fetch MySQL Field Names
 	 *
-	 * @access	public
 	 * @param	string	the table name
 	 * @return	array
 	 */
-	function list_fields($table = '')
+	public function list_fields($table = '')
 	{
 		// Is there a cached result?
 		if (isset($this->data_cache['field_names'][$table]))
@@ -860,40 +850,47 @@
 			return $this->data_cache['field_names'][$table];
 		}
 
-		if ($table == '')
+		if ($table === '')
 		{
-			if ($this->db_debug)
-			{
-				return $this->display_error('db_field_param_missing');
-			}
-			return FALSE;
+			return ($this->db_debug) ? $this->display_error('db_field_param_missing') : FALSE;
 		}
 
 		if (FALSE === ($sql = $this->_list_columns($table)))
 		{
-			if ($this->db_debug)
-			{
-				return $this->display_error('db_unsupported_function');
-			}
-			return FALSE;
+			return ($this->db_debug) ? $this->display_error('db_unsupported_function') : FALSE;
 		}
 
 		$query = $this->query($sql);
+		$this->data_cache['field_names'][$table] = array();
 
-		$retval = array();
 		foreach ($query->result_array() as $row)
 		{
-			if (isset($row['COLUMN_NAME']))
+			// Do we know from where to get the column's name?
+			if ( ! isset($key))
 			{
-				$retval[] = $row['COLUMN_NAME'];
+				if (isset($row['column_name']))
+				{
+					$key = 'column_name';
+				}
+				elseif (isset($row['COLUMN_NAME']))
+				{
+					$key = 'COLUMN_NAME';
+				}
+				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
+					 * E_STRICT is on, this would trigger a warning. So we'll have to
+					 * assign it first.
+					 */
+					$key = array_keys($row);
+					$key = array_shift($key);
+				}
 			}
-			else
-			{
-				$retval[] = current($row);
-			}
+
+			$this->data_cache['field_names'][$table][] = $row[$key];
 		}
 
-		$this->data_cache['field_names'][$table] = $retval;
 		return $this->data_cache['field_names'][$table];
 	}
 
@@ -901,14 +898,14 @@
 
 	/**
 	 * Determine if a particular field exists
-	 * @access	public
+	 *
 	 * @param	string
 	 * @param	string
-	 * @return	boolean
+	 * @return	bool
 	 */
-	function field_exists($field_name, $table_name)
+	public function field_exists($field_name, $table_name)
 	{
-		return ( ! in_array($field_name, $this->list_fields($table_name))) ? FALSE : TRUE;
+		return in_array($field_name, $this->list_fields($table_name));
 	}
 
 	// --------------------------------------------------------------------
@@ -916,48 +913,91 @@
 	/**
 	 * Returns an object with field data
 	 *
-	 * @access	public
 	 * @param	string	the table name
 	 * @return	object
 	 */
-	function field_data($table = '')
+	public function field_data($table = '')
 	{
-		if ($table == '')
+		if ($table === '')
 		{
-			if ($this->db_debug)
-			{
-				return $this->display_error('db_field_param_missing');
-			}
-			return FALSE;
+			return ($this->db_debug) ? $this->display_error('db_field_param_missing') : FALSE;
 		}
 
-		$query = $this->query($this->_field_data($this->_protect_identifiers($table, TRUE, NULL, FALSE)));
-
+		$query = $this->query($this->_field_data($this->protect_identifiers($table, TRUE, NULL, FALSE)));
 		return $query->field_data();
 	}
 
 	// --------------------------------------------------------------------
 
 	/**
+	 * Escape the SQL Identifiers
+	 *
+	 * This function escapes column and table names
+	 *
+	 * @param	mixed
+	 * @return	mixed
+	 */
+	public function escape_identifiers($item)
+	{
+		if ($this->_escape_char === '')
+		{
+			return $item;
+		}
+		elseif (is_array($item))
+		{
+			foreach ($item as $key => $value)
+			{
+				$item[$key] = $this->escape_identifiers($value);
+			}
+
+			return $item;
+		}
+
+		static $preg_ec = array();
+
+		if (empty($preg_ec))
+		{
+			if (is_array($this->_escape_char))
+			{
+				$preg_ec = array(preg_quote($this->_escape_char[0]), preg_quote($this->_escape_char[1]));
+			}
+			else
+			{
+				$preg_ec[0] = $preg_ec[1] = preg_quote($this->_escape_char);
+			}
+		}
+
+		foreach ($this->_reserved_identifiers as $id)
+		{
+			if (strpos($item, '.'.$id) !== FALSE)
+			{
+				return preg_replace('/'.$preg_ec[0].'?([^'.$preg_ec[1].'\.]+)'.$preg_ec[1].'?\./i', $preg_ec[0].'$1'.$preg_ec[1].'.', $item);
+			}
+		}
+
+		return preg_replace('/'.$preg_ec[0].'?([^'.$preg_ec[1].'\.]+)'.$preg_ec[1].'?(\.)?/i', $preg_ec[0].'$1'.$preg_ec[1].'$2', $item);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
 	 * Generate an insert string
 	 *
-	 * @access	public
 	 * @param	string	the table upon which the query will be performed
 	 * @param	array	an associative array data of key/values
 	 * @return	string
 	 */
-	function insert_string($table, $data)
+	public function insert_string($table, $data)
 	{
-		$fields = array();
-		$values = array();
+		$fields = $values = array();
 
 		foreach ($data as $key => $val)
 		{
-			$fields[] = $this->_escape_identifiers($key);
+			$fields[] = $this->escape_identifiers($key);
 			$values[] = $this->escape($val);
 		}
 
-		return $this->_insert($this->_protect_identifiers($table, TRUE, NULL, FALSE), $fields, $values);
+		return $this->_insert($this->protect_identifiers($table, TRUE, NULL, FALSE), $fields, $values);
 	}
 
 	// --------------------------------------------------------------------
@@ -965,23 +1005,22 @@
 	/**
 	 * Generate an update string
 	 *
-	 * @access	public
 	 * @param	string	the table upon which the query will be performed
 	 * @param	array	an associative array data of key/values
 	 * @param	mixed	the "where" statement
 	 * @return	string
 	 */
-	function update_string($table, $data, $where)
+	public function update_string($table, $data, $where)
 	{
-		if ($where == '')
+		if ($where === '')
 		{
-			return false;
+			return FALSE;
 		}
 
 		$fields = array();
 		foreach ($data as $key => $val)
 		{
-			$fields[$this->_protect_identifiers($key)] = $this->escape($val);
+			$fields[$this->protect_identifiers($key)] = $this->escape($val);
 		}
 
 		if ( ! is_array($where))
@@ -993,8 +1032,8 @@
 			$dest = array();
 			foreach ($where as $key => $val)
 			{
-				$prefix = (count($dest) == 0) ? '' : ' AND ';
-				$key = $this->_protect_identifiers($key);
+				$prefix = (count($dest) === 0) ? '' : ' AND ';
+				$key = $this->protect_identifiers($key);
 
 				if ($val !== '')
 				{
@@ -1010,7 +1049,7 @@
 			}
 		}
 
-		return $this->_update($this->_protect_identifiers($table, TRUE, NULL, FALSE), $fields, $dest);
+		return $this->_update($this->protect_identifiers($table, TRUE, NULL, FALSE), $fields, $dest);
 	}
 
 	// --------------------------------------------------------------------
@@ -1018,19 +1057,12 @@
 	/**
 	 * Tests whether the string has an SQL operator
 	 *
-	 * @access	private
 	 * @param	string
 	 * @return	bool
 	 */
-	function _has_operator($str)
+	protected function _has_operator($str)
 	{
-		$str = trim($str);
-		if ( ! preg_match("/(\s|<|>|!|=|is null|is not null)/i", $str))
-		{
-			return FALSE;
-		}
-
-		return TRUE;
+		return (bool) preg_match('/(\s|<|>|!|=|IS NULL|IS NOT NULL|BETWEEN)/i', trim($str));
 	}
 
 	// --------------------------------------------------------------------
@@ -1038,14 +1070,13 @@
 	/**
 	 * Enables a native PHP function to be run, using a platform agnostic wrapper.
 	 *
-	 * @access	public
 	 * @param	string	the function name
 	 * @param	mixed	any parameters needed by the function
 	 * @return	mixed
 	 */
-	function call_function($function)
+	public function call_function($function)
 	{
-		$driver = ($this->dbdriver == 'postgre') ? 'pg_' : $this->dbdriver.'_';
+		$driver = ($this->dbdriver === 'postgre') ? 'pg_' : $this->dbdriver.'_';
 
 		if (FALSE === strpos($driver, $function))
 		{
@@ -1054,25 +1085,12 @@
 
 		if ( ! function_exists($function))
 		{
-			if ($this->db_debug)
-			{
-				return $this->display_error('db_unsupported_function');
-			}
-			return FALSE;
+			return ($this->db_debug) ? $this->display_error('db_unsupported_function') : FALSE;
 		}
-		else
-		{
-			$args = (func_num_args() > 1) ? array_splice(func_get_args(), 1) : null;
 
-			if (is_null($args))
-			{
-				return call_user_func($function);
-			}
-			else
-			{
-				return call_user_func_array($function, $args);
-			}
-		}
+		return (func_num_args() > 1)
+			? call_user_func_array($function, array_splice(func_get_args(), 1))
+			: call_user_func($function);
 	}
 
 	// --------------------------------------------------------------------
@@ -1080,11 +1098,10 @@
 	/**
 	 * Set Cache Directory Path
 	 *
-	 * @access	public
 	 * @param	string	the path to the cache directory
 	 * @return	void
 	 */
-	function cache_set_path($path = '')
+	public function cache_set_path($path = '')
 	{
 		$this->cachedir = $path;
 	}
@@ -1094,13 +1111,11 @@
 	/**
 	 * Enable Query Caching
 	 *
-	 * @access	public
-	 * @return	void
+	 * @return	bool	cache_on value
 	 */
-	function cache_on()
+	public function cache_on()
 	{
-		$this->cache_on = TRUE;
-		return TRUE;
+		return $this->cache_on = TRUE;
 	}
 
 	// --------------------------------------------------------------------
@@ -1108,13 +1123,11 @@
 	/**
 	 * Disable Query Caching
 	 *
-	 * @access	public
-	 * @return	void
+	 * @return	bool	cache_on value
 	 */
-	function cache_off()
+	public function cache_off()
 	{
-		$this->cache_on = FALSE;
-		return FALSE;
+		return $this->cache_on = FALSE;
 	}
 
 
@@ -1123,16 +1136,13 @@
 	/**
 	 * Delete the cache files associated with a particular URI
 	 *
-	 * @access	public
-	 * @return	void
+	 * @return	bool
 	 */
-	function cache_delete($segment_one = '', $segment_two = '')
+	public function cache_delete($segment_one = '', $segment_two = '')
 	{
-		if ( ! $this->_cache_init())
-		{
-			return FALSE;
-		}
-		return $this->CACHE->delete($segment_one, $segment_two);
+		return ($this->_cache_init())
+			? $this->CACHE->delete($segment_one, $segment_two)
+			: FALSE;
 	}
 
 	// --------------------------------------------------------------------
@@ -1140,17 +1150,13 @@
 	/**
 	 * Delete All cache files
 	 *
-	 * @access	public
-	 * @return	void
+	 * @return	bool
 	 */
-	function cache_delete_all()
+	public function cache_delete_all()
 	{
-		if ( ! $this->_cache_init())
-		{
-			return FALSE;
-		}
-
-		return $this->CACHE->delete_all();
+		return ($this->_cache_init())
+			? $this->CACHE->delete_all()
+			: FALSE;
 	}
 
 	// --------------------------------------------------------------------
@@ -1158,23 +1164,21 @@
 	/**
 	 * Initialize the Cache Class
 	 *
-	 * @access	private
-	 * @return	void
+	 * @return	bool
 	 */
-	function _cache_init()
+	protected function _cache_init()
 	{
-		if (is_object($this->CACHE) AND class_exists('CI_DB_Cache'))
+		if (class_exists('CI_DB_Cache'))
 		{
-			return TRUE;
-		}
-
-		if ( ! class_exists('CI_DB_Cache'))
-		{
-			if ( ! @include(BASEPATH.'database/DB_cache.php'))
+			if (is_object($this->CACHE))
 			{
-				return $this->cache_off();
+				return TRUE;
 			}
 		}
+		elseif ( ! @include_once(BASEPATH.'database/DB_cache.php'))
+		{
+			return $this->cache_off();
+		}
 
 		$this->CACHE = new CI_DB_Cache($this); // pass db object to support multiple db connections and returned db objects
 		return TRUE;
@@ -1185,15 +1189,28 @@
 	/**
 	 * Close DB Connection
 	 *
-	 * @access	public
 	 * @return	void
 	 */
-	function close()
+	public function close()
 	{
-		if (is_resource($this->conn_id) OR is_object($this->conn_id))
+		if ($this->conn_id)
 		{
-			$this->_close($this->conn_id);
+			$this->_close();
+			$this->conn_id = FALSE;
 		}
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Close DB Connection
+	 *
+	 * This method would be overriden by most of the drivers.
+	 *
+	 * @return	void
+	 */
+	protected function _close()
+	{
 		$this->conn_id = FALSE;
 	}
 
@@ -1202,20 +1219,19 @@
 	/**
 	 * Display an error message
 	 *
-	 * @access	public
 	 * @param	string	the error message
 	 * @param	string	any "swap" values
-	 * @param	boolean	whether to localize the message
+	 * @param	bool	whether to localize the message
 	 * @return	string	sends the application/error_db.php template
 	 */
-	function display_error($error = '', $swap = '', $native = FALSE)
+	public function display_error($error = '', $swap = '', $native = FALSE)
 	{
 		$LANG =& load_class('Lang', 'core');
 		$LANG->load('db');
 
 		$heading = $LANG->line('db_error_heading');
 
-		if ($native == TRUE)
+		if ($native === TRUE)
 		{
 			$message = (array) $error;
 		}
@@ -1227,9 +1243,7 @@
 		// Find the most likely culprit of the error by going through
 		// the backtrace until the source file is no longer in the
 		// database folder.
-
 		$trace = debug_backtrace();
-
 		foreach ($trace as $call)
 		{
 			if (isset($call['file']) && strpos($call['file'], BASEPATH.'database') === FALSE)
@@ -1237,7 +1251,6 @@
 				// Found it - use a relative path for safety
 				$message[] = 'Filename: '.str_replace(array(BASEPATH, APPPATH), '', $call['file']);
 				$message[] = 'Line Number: '.$call['line'];
-
 				break;
 			}
 		}
@@ -1252,27 +1265,11 @@
 	/**
 	 * Protect Identifiers
 	 *
-	 * This function adds backticks if appropriate based on db type
-	 *
-	 * @access	private
-	 * @param	mixed	the item to escape
-	 * @return	mixed	the item with backticks
-	 */
-	function protect_identifiers($item, $prefix_single = FALSE)
-	{
-		return $this->_protect_identifiers($item, $prefix_single);
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Protect Identifiers
-	 *
-	 * This function is used extensively by the Active Record class, and by
+	 * This function is used extensively by the Query Builder class, and by
 	 * a couple functions in this class.
 	 * It takes a column or table name (optionally with an alias) and inserts
-	 * the table prefix onto it.  Some logic is necessary in order to deal with
-	 * column names that include the path.  Consider a query like this:
+	 * the table prefix onto it. Some logic is necessary in order to deal with
+	 * column names that include the path. Consider a query like this:
 	 *
 	 * SELECT * FROM hostname.database.table.column AS c FROM hostname.database.table
 	 *
@@ -1285,14 +1282,13 @@
 	 * insert the table prefix (if it exists) in the proper position, and escape only
 	 * the correct identifiers.
 	 *
-	 * @access	private
 	 * @param	string
 	 * @param	bool
 	 * @param	mixed
 	 * @param	bool
 	 * @return	string
 	 */
-	function _protect_identifiers($item, $prefix_single = FALSE, $protect_identifiers = NULL, $field_exists = TRUE)
+	public function protect_identifiers($item, $prefix_single = FALSE, $protect_identifiers = NULL, $field_exists = TRUE)
 	{
 		if ( ! is_bool($protect_identifiers))
 		{
@@ -1302,34 +1298,63 @@
 		if (is_array($item))
 		{
 			$escaped_array = array();
-
 			foreach ($item as $k => $v)
 			{
-				$escaped_array[$this->_protect_identifiers($k)] = $this->_protect_identifiers($v);
+				$escaped_array[$this->protect_identifiers($k)] = $this->protect_identifiers($v, $prefix_single, $protect_identifiers, $field_exists);
 			}
 
 			return $escaped_array;
 		}
 
-		// Convert tabs or multiple spaces into single spaces
-		$item = preg_replace('/[\t ]+/', ' ', $item);
-
-		// If the item has an alias declaration we remove it and set it aside.
-		// Basically we remove everything to the right of the first space
-		$alias = '';
-		if (strpos($item, ' ') !== FALSE)
-		{
-			$alias = strstr($item, " ");
-			$item = substr($item, 0, - strlen($alias));
-		}
-
 		// This is basically a bug fix for queries that use MAX, MIN, etc.
 		// If a parenthesis is found we know that we do not need to
-		// escape the data or add a prefix.  There's probably a more graceful
+		// escape the data or add a prefix. There's probably a more graceful
 		// way to deal with this, but I'm not thinking of it -- Rick
 		if (strpos($item, '(') !== FALSE)
 		{
-			return $item.$alias;
+			return $item;
+		}
+
+		// Convert tabs or multiple spaces into single spaces
+		$item = preg_replace('/\s+/', ' ', $item);
+
+		static $preg_ec = array();
+
+		if (empty($preg_ec))
+		{
+			if (is_array($this->_escape_char))
+			{
+				$preg_ec = array(preg_quote($this->_escape_char[0]), preg_quote($this->_escape_char[1]));
+			}
+			else
+			{
+				$preg_ec[0] = $preg_ec[1] = preg_quote($this->_escape_char);
+			}
+		}
+
+		// If the item has an alias declaration we remove it and set it aside.
+		// Basically we remove everything to the right of the first space
+		preg_match('/^(('.$preg_ec[0].'[^'.$preg_ec[1].']+'.$preg_ec[1].')|([^'.$preg_ec[0].'][^\s]+))( AS)*(.+)*$/i', $item, $matches);
+
+		if (isset($matches[4]))
+		{
+			$item = $matches[1];
+
+			// Escape the alias, if needed
+			if ($protect_identifiers === TRUE)
+			{
+				$alias = empty($matches[5])
+					? ' '.$this->escape_identifiers(ltrim($matches[4]))
+					: $matches[4].' '.$this->escape_identifiers(ltrim($matches[5]));
+			}
+			else
+			{
+				$alias = $matches[4].$matches[5];
+			}
+		}
+		else
+		{
+			$alias = '';
 		}
 
 		// Break the string apart if it contains periods, then insert the table prefix
@@ -1340,9 +1365,9 @@
 			$parts	= explode('.', $item);
 
 			// Does the first segment of the exploded item match
-			// one of the aliases previously identified?  If so,
+			// one of the aliases previously identified? If so,
 			// we have nothing more to do other than escape the item
-			if (in_array($parts[0], $this->ar_aliased_tables))
+			if (in_array($parts[0], $this->qb_aliased_tables))
 			{
 				if ($protect_identifiers === TRUE)
 				{
@@ -1350,17 +1375,18 @@
 					{
 						if ( ! in_array($val, $this->_reserved_identifiers))
 						{
-							$parts[$key] = $this->_escape_identifiers($val);
+							$parts[$key] = $this->escape_identifiers($val);
 						}
 					}
 
 					$item = implode('.', $parts);
 				}
+
 				return $item.$alias;
 			}
 
-			// Is there a table prefix defined in the config file?  If not, no need to do anything
-			if ($this->dbprefix != '')
+			// Is there a table prefix defined in the config file? If not, no need to do anything
+			if ($this->dbprefix !== '')
 			{
 				// We now add the table prefix based on some logic.
 				// Do we have 4 segments (hostname.database.table.column)?
@@ -1384,19 +1410,18 @@
 
 				// This flag is set when the supplied $item does not contain a field name.
 				// This can happen when this function is being called from a JOIN.
-				if ($field_exists == FALSE)
+				if ($field_exists === FALSE)
 				{
 					$i++;
 				}
 
 				// Verify table prefix and replace if necessary
-				if ($this->swap_pre != '' && strncmp($parts[$i], $this->swap_pre, strlen($this->swap_pre)) === 0)
+				if ($this->swap_pre !== '' && strpos($parts[$i], $this->swap_pre) === 0)
 				{
-					$parts[$i] = preg_replace("/^".$this->swap_pre."(\S+?)/", $this->dbprefix."\\1", $parts[$i]);
+					$parts[$i] = preg_replace('/^'.$this->swap_pre.'(\S+?)/', $this->dbprefix.'\\1', $parts[$i]);
 				}
-
 				// We only add the table prefix if it does not already exist
-				if (substr($parts[$i], 0, strlen($this->dbprefix)) != $this->dbprefix)
+				elseif (strpos($parts[$i], $this->dbprefix) !== 0)
 				{
 					$parts[$i] = $this->dbprefix.$parts[$i];
 				}
@@ -1407,39 +1432,48 @@
 
 			if ($protect_identifiers === TRUE)
 			{
-				$item = $this->_escape_identifiers($item);
+				$item = $this->escape_identifiers($item);
 			}
 
 			return $item.$alias;
 		}
 
-		// Is there a table prefix?  If not, no need to insert it
-		if ($this->dbprefix != '')
+		// Is there a table prefix? If not, no need to insert it
+		if ($this->dbprefix !== '')
 		{
 			// Verify table prefix and replace if necessary
-			if ($this->swap_pre != '' && strncmp($item, $this->swap_pre, strlen($this->swap_pre)) === 0)
+			if ($this->swap_pre !== '' && strpos($item, $this->swap_pre) === 0)
 			{
-				$item = preg_replace("/^".$this->swap_pre."(\S+?)/", $this->dbprefix."\\1", $item);
+				$item = preg_replace('/^'.$this->swap_pre.'(\S+?)/', $this->dbprefix.'\\1', $item);
 			}
-
 			// Do we prefix an item with no segments?
-			if ($prefix_single == TRUE AND substr($item, 0, strlen($this->dbprefix)) != $this->dbprefix)
+			elseif ($prefix_single === TRUE && strpos($item, $this->dbprefix) !== 0)
 			{
 				$item = $this->dbprefix.$item;
 			}
 		}
 
-		if ($protect_identifiers === TRUE AND ! in_array($item, $this->_reserved_identifiers))
+		if ($protect_identifiers === TRUE && ! in_array($item, $this->_reserved_identifiers))
 		{
-			$item = $this->_escape_identifiers($item);
+			$item = $this->escape_identifiers($item);
 		}
 
 		return $item.$alias;
 	}
 
+	// --------------------------------------------------------------------
+
+	/**
+	 * Dummy method that allows Query Builder class to be disabled
+	 * and keep count_all() working.
+	 *
+	 * @return	void
+	 */
+	protected function _reset_select()
+	{
+	}
 
 }
 
-
 /* End of file DB_driver.php */
-/* Location: ./system/database/DB_driver.php */
+/* Location: ./system/database/DB_driver.php */
\ No newline at end of file
diff --git a/system/database/DB_forge.php b/system/database/DB_forge.php
index 336e949..9b76392 100644
--- a/system/database/DB_forge.php
+++ b/system/database/DB_forge.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -25,22 +25,26 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
- * Database Utility Class
+ * Database Forge Class
  *
  * @category	Database
  * @author		EllisLab Dev Team
  * @link		http://codeigniter.com/user_guide/database/
  */
-class CI_DB_forge {
+abstract class CI_DB_forge {
 
 	public $fields		= array();
 	public $keys		= array();
 	public $primary_keys	= array();
 	public $db_char_set	=	'';
 
+	// Platform specific SQL strings
+	protected $_create_database	= 'CREATE DATABASE %s';
+	protected $_drop_database	= 'DROP DATABASE %s';
+	protected $_drop_table		= 'DROP TABLE IF EXISTS %s';
+	protected $_rename_table	= 'ALTER TABLE %s RENAME TO %s';
+
 	public function __construct()
 	{
 		// Assign the main database object to $this->db
@@ -59,8 +63,21 @@
 	 */
 	public function create_database($db_name)
 	{
-		$sql = $this->_create_database($db_name);
-		return is_bool($sql) ? $sql : $this->db->query($sql);
+		if ($this->_create_database === FALSE)
+		{
+			return ($this->db->db_debug) ? $this->db->display_error('db_unsuported_feature') : FALSE;
+		}
+		elseif ( ! $this->db->query(sprintf($this->_create_database, $db_name, $this->db->char_set, $this->db->dbcollat)))
+		{
+			return ($this->db->db_debug) ? $this->db->display_error('db_unable_to_drop') : FALSE;
+		}
+
+		if ( ! empty($this->db->data_cache['db_names']))
+		{
+			$this->db->data_cache['db_names'][] = $db_name;
+		}
+
+		return TRUE;
 	}
 
 	// --------------------------------------------------------------------
@@ -73,8 +90,30 @@
 	 */
 	public function drop_database($db_name)
 	{
-		$sql = $this->_drop_database($db_name);
-		return is_bool($sql) ? $sql : $this->db->query($sql);
+		if ($db_name === '')
+		{
+			show_error('A table name is required for that operation.');
+			return FALSE;
+		}
+		elseif ($this->_drop_database === FALSE)
+		{
+			return ($this->db->db_debug) ? $this->db->display_error('db_unsuported_feature') : FALSE;
+		}
+		elseif ( ! $this->db->query(sprintf($this->_drop_database, $db_name)))
+		{
+			return ($this->db->db_debug) ? $this->db->display_error('db_unable_to_drop') : FALSE;
+		}
+
+		if ( ! empty($this->db->data_cache['db_names']))
+		{
+			$key = array_search(strtolower($db_name), array_map('strtolower', $this->db->data_cache['db_names']), TRUE);
+			if ($key !== FALSE)
+			{
+				unset($this->db->data_cache['db_names'][$key]);
+			}
+		}
+
+		return TRUE;
 	}
 
 	// --------------------------------------------------------------------
@@ -98,7 +137,7 @@
 			return;
 		}
 
-		if ($key == '')
+		if ($key === '')
 		{
 			show_error('Key information is required for that operation.');
 		}
@@ -125,7 +164,7 @@
 	 */
 	public function add_field($field = '')
 	{
-		if ($field == '')
+		if ($field === '')
 		{
 			show_error('Field information is required.');
 		}
@@ -172,7 +211,7 @@
 	 */
 	public function create_table($table = '', $if_not_exists = FALSE)
 	{
-		if ($table == '')
+		if ($table === '')
 		{
 			show_error('A table name is required for that operation.');
 		}
@@ -184,7 +223,18 @@
 
 		$sql = $this->_create_table($this->db->dbprefix.$table, $this->fields, $this->primary_keys, $this->keys, $if_not_exists);
 		$this->_reset();
-		return is_bool($sql) ? $sql : $this->db->query($sql);
+
+		if (is_bool($sql))
+		{
+			return $sql;
+		}
+
+		if (($result = $this->db->query($sql)) !== FALSE && ! empty($this->db->data_cache['table_names']))
+		{
+			$this->db->data_cache['table_names'][] = $$this->db->dbprefix.$table;
+		}
+
+		return $result;
 	}
 
 	// --------------------------------------------------------------------
@@ -197,8 +247,28 @@
 	 */
 	public function drop_table($table_name)
 	{
-		$sql = $this->_drop_table($this->db->dbprefix.$table_name);
-		return is_bool($sql) ? $sql : $this->db->query($sql);
+		if ($table_name === '')
+		{
+			return ($this->db->db_debug) ? $this->db->display_error('db_table_name_required') : FALSE;
+		}
+		elseif ($this->_drop_table === FALSE)
+		{
+			return ($this->db->db_debug) ? $this->db->display_error('db_unsuported_feature') : FALSE;
+		}
+
+		$result = $this->db->query(sprintf($this->_drop_table, $this->db->escape_identifiers($this->db->dbprefix.$table_name)));
+
+		// Update table list cache
+		if ($result && ! empty($this->db->data_cache['table_names']))
+		{
+			$key = array_search(strtolower($this->db->dbprefix.$table_name), array_map('strtolower', $this->db->data_cache['table_names']), TRUE);
+			if ($key !== FALSE)
+			{
+				unset($this->db->data_cache['table_names'][$key]);
+			}
+		}
+
+		return $result;
 	}
 
 	// --------------------------------------------------------------------
@@ -212,12 +282,31 @@
 	 */
 	public function rename_table($table_name, $new_table_name)
 	{
-		if ($table_name == '' OR $new_table_name == '')
+		if ($table_name === '' OR $new_table_name === '')
 		{
 			show_error('A table name is required for that operation.');
+			return FALSE;
+		}
+		elseif ($this->_rename_table === FALSE)
+		{
+			return ($this->db->db_debug) ? $this->db->display_error('db_unsuported_feature') : FALSE;
 		}
 
-		return $this->db->query($this->_rename_table($this->db->dbprefix.$table_name, $this->db->dbprefix.$new_table_name));
+		$result = $this->db->query(sprintf($this->_rename_table,
+						$this->db->escape_identifiers($this->db->dbprefix.$table_name),
+						$this->db->escape_identifiers($this->db->dbprefix.$new_table_name))
+					);
+
+		if ($result && ! empty($this->db->data_cache['table_names']))
+		{
+			$key = array_search(strtolower($this->db->dbprefix.$table_name), array_map('strtolower', $this->db->data_cache['table_names']), TRUE);
+			if ($key !== FALSE)
+			{
+				$this->db->data_cache['table_names'][$key] = $this->db->dbprefix.$new_table_name;
+			}
+		}
+
+		return $result;
 	}
 
 	// --------------------------------------------------------------------
@@ -232,7 +321,7 @@
 	 */
 	public function add_column($table = '', $field = array(), $after_field = '')
 	{
-		if ($table == '')
+		if ($table === '')
 		{
 			show_error('A table name is required for that operation.');
 		}
@@ -243,7 +332,7 @@
 		{
 			$this->add_field(array($k => $field[$k]));
 
-			if (count($this->fields) == 0)
+			if (count($this->fields) === 0)
 			{
 				show_error('Field information is required.');
 			}
@@ -271,12 +360,12 @@
 	 */
 	public function drop_column($table = '', $column_name = '')
 	{
-		if ($table == '')
+		if ($table === '')
 		{
 			show_error('A table name is required for that operation.');
 		}
 
-		if ($column_name == '')
+		if ($column_name === '')
 		{
 			show_error('A column name is required for that operation.');
 		}
@@ -296,7 +385,7 @@
 	 */
 	public function modify_column($table = '', $field = array())
 	{
-		if ($table == '')
+		if ($table === '')
 		{
 			show_error('A table name is required for that operation.');
 		}
@@ -346,4 +435,4 @@
 }
 
 /* End of file DB_forge.php */
-/* Location: ./system/database/DB_forge.php */
+/* Location: ./system/database/DB_forge.php */
\ No newline at end of file
diff --git a/system/database/DB_active_rec.php b/system/database/DB_query_builder.php
similarity index 63%
rename from system/database/DB_active_rec.php
rename to system/database/DB_query_builder.php
index 4247351..488b294 100644
--- a/system/database/DB_active_rec.php
+++ b/system/database/DB_query_builder.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -25,12 +25,10 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
- * Active Record Class
+ * Query Builder Class
  *
- * This is the platform-independent base Active Record implementation class.
+ * This is the platform-independent base Query Builder implementation class.
  *
  * @package		CodeIgniter
  * @subpackage	Drivers
@@ -38,46 +36,46 @@
  * @author		EllisLab Dev Team
  * @link		http://codeigniter.com/user_guide/database/
  */
-class CI_DB_active_record extends CI_DB_driver {
+
+abstract class CI_DB_query_builder extends CI_DB_driver {
 
 	protected $return_delete_sql		= FALSE;
 	protected $reset_delete_data		= FALSE;
 
-	protected $ar_select			= array();
-	protected $ar_distinct			= FALSE;
-	protected $ar_from			= array();
-	protected $ar_join			= array();
-	protected $ar_where			= array();
-	protected $ar_like			= array();
-	protected $ar_groupby			= array();
-	protected $ar_having			= array();
-	protected $ar_keys			= array();
-	protected $ar_limit			= FALSE;
-	protected $ar_offset			= FALSE;
-	protected $ar_order			= FALSE;
-	protected $ar_orderby			= array();
-	protected $ar_set			= array();
-	protected $ar_wherein			= array();
-	protected $ar_aliased_tables		= array();
-	protected $ar_store_array		= array();
-	protected $ar_where_group_started	= FALSE;
-	protected $ar_where_group_count		= 0;
+	protected $qb_select			= array();
+	protected $qb_distinct			= FALSE;
+	protected $qb_from			= array();
+	protected $qb_join			= array();
+	protected $qb_where			= array();
+	protected $qb_like			= array();
+	protected $qb_groupby			= array();
+	protected $qb_having			= array();
+	protected $qb_keys			= array();
+	protected $qb_limit			= FALSE;
+	protected $qb_offset			= FALSE;
+	protected $qb_orderby			= array();
+	protected $qb_set			= array();
+	protected $qb_wherein			= array();
+	protected $qb_aliased_tables		= array();
+	protected $qb_store_array		= array();
+	protected $qb_where_group_started	= FALSE;
+	protected $qb_where_group_count		= 0;
 
-	// Active Record Caching variables
-	protected $ar_caching				= FALSE;
-	protected $ar_cache_exists			= array();
-	protected $ar_cache_select			= array();
-	protected $ar_cache_from			= array();
-	protected $ar_cache_join			= array();
-	protected $ar_cache_where			= array();
-	protected $ar_cache_like			= array();
-	protected $ar_cache_groupby			= array();
-	protected $ar_cache_having			= array();
-	protected $ar_cache_orderby			= array();
-	protected $ar_cache_set				= array();
+	// Query Builder Caching variables
+	protected $qb_caching				= FALSE;
+	protected $qb_cache_exists			= array();
+	protected $qb_cache_select			= array();
+	protected $qb_cache_from			= array();
+	protected $qb_cache_join			= array();
+	protected $qb_cache_where			= array();
+	protected $qb_cache_like			= array();
+	protected $qb_cache_groupby			= array();
+	protected $qb_cache_having			= array();
+	protected $qb_cache_orderby			= array();
+	protected $qb_cache_set				= array();
 
-	protected $ar_no_escape 			= array();
-	protected $ar_cache_no_escape			= array();
+	protected $qb_no_escape 			= array();
+	protected $qb_cache_no_escape			= array();
 
 	/**
 	 * Select
@@ -85,6 +83,7 @@
 	 * Generates the SELECT portion of the query
 	 *
 	 * @param	string
+	 * @param	mixed
 	 * @return	object
 	 */
 	public function select($select = '*', $escape = NULL)
@@ -94,20 +93,23 @@
 			$select = explode(',', $select);
 		}
 
+		// If the escape value was not set will will base it on the global setting
+		is_bool($escape) OR $escape = $this->_protect_identifiers;
+
 		foreach ($select as $val)
 		{
 			$val = trim($val);
 
-			if ($val != '')
+			if ($val !== '')
 			{
-				$this->ar_select[] = $val;
-				$this->ar_no_escape[] = $escape;
+				$this->qb_select[] = $val;
+				$this->qb_no_escape[] = $escape;
 
-				if ($this->ar_caching === TRUE)
+				if ($this->qb_caching === TRUE)
 				{
-					$this->ar_cache_select[] = $val;
-					$this->ar_cache_exists[] = 'select';
-					$this->ar_cache_no_escape[] = $escape;
+					$this->qb_cache_select[] = $val;
+					$this->qb_cache_exists[] = 'select';
+					$this->qb_cache_no_escape[] = $escape;
 				}
 			}
 		}
@@ -195,7 +197,7 @@
 	 */
 	protected function _max_min_avg_sum($select = '', $alias = '', $type = 'MAX')
 	{
-		if ( ! is_string($select) OR $select == '')
+		if ( ! is_string($select) OR $select === '')
 		{
 			$this->display_error('db_invalid_query');
 		}
@@ -207,18 +209,20 @@
 			show_error('Invalid function type: '.$type);
 		}
 
-		if ($alias == '')
+		if ($alias === '')
 		{
 			$alias = $this->_create_alias_from_table(trim($select));
 		}
 
-		$sql = $this->_protect_identifiers($type.'('.trim($select).')').' AS '.$this->_protect_identifiers(trim($alias));
-		$this->ar_select[] = $sql;
+		$sql = $this->protect_identifiers($type.'('.trim($select).')').' AS '.$this->escape_identifiers(trim($alias));
 
-		if ($this->ar_caching === TRUE)
+		$this->qb_select[] = $sql;
+		$this->qb_no_escape[] = NULL;
+
+		if ($this->qb_caching === TRUE)
 		{
-			$this->ar_cache_select[] = $sql;
-			$this->ar_cache_exists[] = 'select';
+			$this->qb_cache_select[] = $sql;
+			$this->qb_cache_exists[] = 'select';
 		}
 
 		return $this;
@@ -236,7 +240,8 @@
 	{
 		if (strpos($item, '.') !== FALSE)
 		{
-			return end(explode('.', $item));
+			$item = explode('.', $item);
+			return end($item);
 		}
 
 		return $item;
@@ -254,7 +259,7 @@
 	 */
 	public function distinct($val = TRUE)
 	{
-		$this->ar_distinct = (is_bool($val)) ? $val : TRUE;
+		$this->qb_distinct = is_bool($val) ? $val : TRUE;
 		return $this;
 	}
 
@@ -270,7 +275,7 @@
 	 */
 	public function from($from)
 	{
-		foreach ((array)$from as $val)
+		foreach ((array) $from as $val)
 		{
 			if (strpos($val, ',') !== FALSE)
 			{
@@ -278,12 +283,13 @@
 				{
 					$v = trim($v);
 					$this->_track_aliases($v);
-					$v = $this->ar_from[] = $this->_protect_identifiers($v, TRUE, NULL, FALSE);
 
-					if ($this->ar_caching === TRUE)
+					$this->qb_from[] = $v = $this->protect_identifiers($v, TRUE, NULL, FALSE);
+
+					if ($this->qb_caching === TRUE)
 					{
-						$this->ar_cache_from[] = $v;
-						$this->ar_cache_exists[] = 'from';
+						$this->qb_cache_from[] = $v;
+						$this->qb_cache_exists[] = 'from';
 					}
 				}
 			}
@@ -292,14 +298,15 @@
 				$val = trim($val);
 
 				// Extract any aliases that might exist. We use this information
-				// in the _protect_identifiers to know whether to add a table prefix
+				// in the protect_identifiers to know whether to add a table prefix
 				$this->_track_aliases($val);
-				$this->ar_from[] = $val = $this->_protect_identifiers($val, TRUE, NULL, FALSE);
 
-				if ($this->ar_caching === TRUE)
+				$this->qb_from[] = $val = $this->protect_identifiers($val, TRUE, NULL, FALSE);
+
+				if ($this->qb_caching === TRUE)
 				{
-					$this->ar_cache_from[] = $val;
-					$this->ar_cache_exists[] = 'from';
+					$this->qb_cache_from[] = $val;
+					$this->qb_cache_exists[] = 'from';
 				}
 			}
 		}
@@ -317,15 +324,16 @@
 	 * @param	string
 	 * @param	string	the join condition
 	 * @param	string	the type of join
+	 * @param	string	wether not to try to escape identifiers
 	 * @return	object
 	 */
-	public function join($table, $cond, $type = '')
+	public function join($table, $cond, $type = '', $escape = TRUE)
 	{
-		if ($type != '')
+		if ($type !== '')
 		{
 			$type = strtoupper(trim($type));
 
-			if ( ! in_array($type, array('LEFT', 'RIGHT', 'OUTER', 'INNER', 'LEFT OUTER', 'RIGHT OUTER')))
+			if ( ! in_array($type, array('LEFT', 'RIGHT', 'OUTER', 'INNER', 'LEFT OUTER', 'RIGHT OUTER'), TRUE))
 			{
 				$type = '';
 			}
@@ -336,22 +344,49 @@
 		}
 
 		// Extract any aliases that might exist. We use this information
-		// in the _protect_identifiers to know whether to add a table prefix
+		// in the protect_identifiers to know whether to add a table prefix
 		$this->_track_aliases($table);
 
-		// Strip apart the condition and protect the identifiers
-		if (preg_match('/([\w\.]+)([\W\s]+)(.+)/', $cond, $match))
+		// Split multiple conditions
+		if ($escape === TRUE && preg_match_all('/\sAND\s|\sOR\s/i', $cond, $m, PREG_SET_ORDER | PREG_OFFSET_CAPTURE))
 		{
-			$cond = $this->_protect_identifiers($match[1]).$match[2].$this->_protect_identifiers($match[3]);
+			$newcond = '';
+			$m[0][] = array('', strlen($cond));
+
+			for ($i = 0, $c = count($m[0]), $s = 0;
+				$i < $c;
+				$s += $m[0][$i][1] + strlen($m[0][$i][0]), $i++)
+			{
+				$temp = substr($cond, $s, $m[0][$i][1]);
+
+				$newcond .= preg_match('/([\[\w\.-]+)([\W\s]+)(.+)/i', $temp, $match)
+						? $this->protect_identifiers($match[1]).$match[2].$this->protect_identifiers($match[3])
+						: $temp;
+
+				$newcond .= $m[0][$i][0];
+			}
+
+			$cond = $newcond;
+		}
+		// Split apart the condition and protect the identifiers
+		elseif ($escape === TRUE && preg_match('/([\[\w\.-]+)([\W\s]+)(.+)/i', $cond, $match))
+		{
+			$cond = $this->protect_identifiers($match[1]).$match[2].$this->protect_identifiers($match[3]);
+		}
+
+		// Do we want to escape the table name?
+		if ($escape === TRUE)
+		{
+			$table = $this->protect_identifiers($table, TRUE, NULL, FALSE);
 		}
 
 		// Assemble the JOIN statement
-		$this->ar_join[] = $join = $type.'JOIN '.$this->_protect_identifiers($table, TRUE, NULL, FALSE).' ON '.$cond;
+		$this->qb_join[] = $join = $type.'JOIN '.$this->protect_identifiers($table, TRUE, NULL, FALSE).' ON '.$cond;
 
-		if ($this->ar_caching === TRUE)
+		if ($this->qb_caching === TRUE)
 		{
-			$this->ar_cache_join[] = $join;
-			$this->ar_cache_exists[] = 'join';
+			$this->qb_cache_join[] = $join;
+			$this->qb_cache_exists[] = 'join';
 		}
 
 		return $this;
@@ -367,6 +402,7 @@
 	 *
 	 * @param	mixed
 	 * @param	mixed
+	 * @param	bool
 	 * @return	object
 	 */
 	public function where($key, $value = NULL, $escape = TRUE)
@@ -384,6 +420,7 @@
 	 *
 	 * @param	mixed
 	 * @param	mixed
+	 * @param	bool
 	 * @return	object
 	 */
 	public function or_where($key, $value = NULL, $escape = TRUE)
@@ -401,6 +438,7 @@
 	 * @param	mixed
 	 * @param	mixed
 	 * @param	string
+	 * @param	mixed
 	 * @return	object
 	 */
 	protected function _where($key, $value = NULL, $type = 'AND ', $escape = NULL)
@@ -413,14 +451,15 @@
 		}
 
 		// If the escape value was not set will will base it on the global setting
-		if ( ! is_bool($escape))
-		{
-			$escape = $this->_protect_identifiers;
-		}
+		$escape = $this->_protect_identifiers;
 
 		foreach ($key as $k => $v)
 		{
-			$prefix = (count($this->ar_where) === 0 AND count($this->ar_cache_where) === 0) ? '' : $type;
+			$prefix = (count($this->qb_where) === 0 && count($this->qb_cache_where) === 0) ? '' : $type;
+
+			$k = $this->_has_operator($k)
+				? $this->protect_identifiers(substr($k, 0, strpos(rtrim($k), ' ')), FALSE, $escape).strchr(rtrim($k), ' ')
+				: $this->protect_identifiers($k, FALSE, $escape);
 
 			if (is_null($v) && ! $this->_has_operator($k))
 			{
@@ -432,7 +471,6 @@
 			{
 				if ($escape === TRUE)
 				{
-					$k = $this->_protect_identifiers($k, FALSE, $escape);
 					$v = ' '.$this->escape($v);
 				}
 
@@ -441,16 +479,12 @@
 					$k .= ' = ';
 				}
 			}
-			else
-			{
-				$k = $this->_protect_identifiers($k, FALSE, $escape);
-			}
 
-			$this->ar_where[] = $prefix.$k.$v;
-			if ($this->ar_caching === TRUE)
+			$this->qb_where[] = $prefix.$k.$v;
+			if ($this->qb_caching === TRUE)
 			{
-				$this->ar_cache_where[] = $prefix.$k.$v;
-				$this->ar_cache_exists[] = 'where';
+				$this->qb_cache_where[] = $prefix.$k.$v;
+				$this->qb_cache_exists[] = 'where';
 			}
 
 		}
@@ -535,7 +569,7 @@
 	 *
 	 * @param	string	The field to search
 	 * @param	array	The values searched on
-	 * @param	boolean	If the statement would be IN or NOT IN
+	 * @param	bool	If the statement would be IN or NOT IN
 	 * @param	string
 	 * @return	object
 	 */
@@ -543,7 +577,7 @@
 	{
 		if ($key === NULL OR $values === NULL)
 		{
-			return;
+			return $this;
 		}
 
 		$type = $this->_group_get_type($type);
@@ -557,20 +591,20 @@
 
 		foreach ($values as $value)
 		{
-			$this->ar_wherein[] = $this->escape($value);
+			$this->qb_wherein[] = $this->escape($value);
 		}
 
-		$prefix = (count($this->ar_where) === 0) ? '' : $type;
-		$this->ar_where[] = $where_in = $prefix.$this->_protect_identifiers($key).$not.' IN ('.implode(', ', $this->ar_wherein).') ';
+		$prefix = (count($this->qb_where) === 0) ? '' : $type;
+		$this->qb_where[] = $where_in = $prefix.$this->protect_identifiers($key).$not.' IN ('.implode(', ', $this->qb_wherein).') ';
 
-		if ($this->ar_caching === TRUE)
+		if ($this->qb_caching === TRUE)
 		{
-			$this->ar_cache_where[] = $where_in;
-			$this->ar_cache_exists[] = 'where';
+			$this->qb_cache_where[] = $where_in;
+			$this->qb_cache_exists[] = 'where';
 		}
 
 		// reset the array for multiple calls
-		$this->ar_wherein = array();
+		$this->qb_wherein = array();
 		return $this;
 	}
 
@@ -665,38 +699,38 @@
 
 		foreach ($field as $k => $v)
 		{
-			$k = $this->_protect_identifiers($k);
-			$prefix = (count($this->ar_like) === 0) ? '' : $type;
+			$k = $this->protect_identifiers($k);
+			$prefix = (count($this->qb_like) === 0) ? '' : $type;
 			$v = $this->escape_like_str($v);
 
 			if ($side === 'none')
 			{
-				$like_statement = $prefix." $k $not LIKE '{$v}'";
+				$like_statement = "{$prefix} $k $not LIKE '{$v}'";
 			}
 			elseif ($side === 'before')
 			{
-				$like_statement = $prefix." $k $not LIKE '%{$v}'";
+				$like_statement = "{$prefix} $k $not LIKE '%{$v}'";
 			}
 			elseif ($side === 'after')
 			{
-				$like_statement = $prefix." $k $not LIKE '{$v}%'";
+				$like_statement = "{$prefix} $k $not LIKE '{$v}%'";
 			}
 			else
 			{
-				$like_statement = $prefix." $k $not LIKE '%{$v}%'";
+				$like_statement = "{$prefix} $k $not LIKE '%{$v}%'";
 			}
 
 			// some platforms require an escape sequence definition for LIKE wildcards
-			if ($this->_like_escape_str != '')
+			if ($this->_like_escape_str !== '')
 			{
 				$like_statement = $like_statement.sprintf($this->_like_escape_str, $this->_like_escape_chr);
 			}
 
-			$this->ar_like[] = $like_statement;
-			if ($this->ar_caching === TRUE)
+			$this->qb_like[] = $like_statement;
+			if ($this->qb_caching === TRUE)
 			{
-				$this->ar_cache_like[] = $like_statement;
-				$this->ar_cache_exists[] = 'like';
+				$this->qb_cache_like[] = $like_statement;
+				$this->qb_cache_exists[] = 'like';
 			}
 
 		}
@@ -716,13 +750,14 @@
 	public function group_start($not = '', $type = 'AND ')
 	{
 		$type = $this->_group_get_type($type);
-		$this->ar_where_group_started = TRUE;
-		$prefix = (count($this->ar_where) === 0 AND count($this->ar_cache_where) === 0) ? '' : $type;
-		$this->ar_where[] = $value = $prefix.$not.str_repeat(' ', ++$this->ar_where_group_count).' (';
 
-		if ($this->ar_caching)
+		$this->qb_where_group_started = TRUE;
+		$prefix = (count($this->qb_where) === 0 && count($this->qb_cache_where) === 0) ? '' : $type;
+		$this->qb_where[] = $value = $prefix.$not.str_repeat(' ', ++$this->qb_where_group_count).' (';
+
+		if ($this->qb_caching)
 		{
-			$this->ar_cache_where[] = $value;
+			$this->qb_cache_where[] = $value;
 		}
 
 		return $this;
@@ -773,12 +808,12 @@
 	 */
 	public function group_end()
 	{
-		$this->ar_where_group_started = FALSE;
-		$this->ar_where[] = $value = str_repeat(' ', $this->ar_where_group_count--) . ')';
+		$this->qb_where_group_started = FALSE;
+		$this->qb_where[] = $value = str_repeat(' ', $this->qb_where_group_count--) . ')';
 
-		if ($this->ar_caching)
+		if ($this->qb_caching)
 		{
-			$this->ar_cache_where[] = $value;
+			$this->qb_cache_where[] = $value;
 		}
 
 		return $this;
@@ -796,10 +831,10 @@
 	 */
 	protected function _group_get_type($type)
 	{
-		if ($this->ar_where_group_started)
+		if ($this->qb_where_group_started)
 		{
 			$type = '';
-			$this->ar_where_group_started = FALSE;
+			$this->qb_where_group_started = FALSE;
 		}
 
 		return $type;
@@ -824,14 +859,14 @@
 		{
 			$val = trim($val);
 
-			if ($val != '')
+			if ($val !== '')
 			{
-				$this->ar_groupby[] = $val = $this->_protect_identifiers($val);
+				$this->qb_groupby[] = $val = $this->protect_identifiers($val);
 
-				if ($this->ar_caching === TRUE)
+				if ($this->qb_caching === TRUE)
 				{
-					$this->ar_cache_groupby[] = $val;
-					$this->ar_cache_exists[] = 'groupby';
+					$this->qb_cache_groupby[] = $val;
+					$this->qb_cache_exists[] = 'groupby';
 				}
 			}
 		}
@@ -848,6 +883,7 @@
 	 *
 	 * @param	string
 	 * @param	string
+	 * @param	bool
 	 * @return	object
 	 */
 	public function having($key, $value = '', $escape = TRUE)
@@ -864,6 +900,7 @@
 	 *
 	 * @param	string
 	 * @param	string
+	 * @param	bool
 	 * @return	object
 	 */
 	public function or_having($key, $value = '', $escape = TRUE)
@@ -880,6 +917,8 @@
 	 *
 	 * @param	string
 	 * @param	string
+	 * @param	string
+	 * @param	bool
 	 * @return	object
 	 */
 	protected function _having($key, $value = '', $type = 'AND ', $escape = TRUE)
@@ -891,11 +930,11 @@
 
 		foreach ($key as $k => $v)
 		{
-			$prefix = (count($this->ar_having) === 0) ? '' : $type;
+			$prefix = (count($this->qb_having) === 0) ? '' : $type;
 
 			if ($escape === TRUE)
 			{
-				$k = $this->_protect_identifiers($k);
+				$k = $this->protect_identifiers($k);
 			}
 
 			if ( ! $this->_has_operator($k))
@@ -903,16 +942,16 @@
 				$k .= ' = ';
 			}
 
-			if ($v != '')
+			if ($v !== '')
 			{
 				$v = ' '.$this->escape($v);
 			}
 
-			$this->ar_having[] = $prefix.$k.$v;
-			if ($this->ar_caching === TRUE)
+			$this->qb_having[] = $prefix.$k.$v;
+			if ($this->qb_caching === TRUE)
 			{
-				$this->ar_cache_having[] = $prefix.$k.$v;
-				$this->ar_cache_exists[] = 'having';
+				$this->qb_cache_having[] = $prefix.$k.$v;
+				$this->qb_cache_exists[] = 'having';
 			}
 		}
 
@@ -936,9 +975,9 @@
 			$orderby = ''; // Random results want or don't need a field name
 			$direction = $this->_random_keyword;
 		}
-		elseif (trim($direction) != '')
+		elseif (trim($direction) !== '')
 		{
-			$direction = (in_array(strtoupper(trim($direction)), array('ASC', 'DESC'), TRUE)) ? ' '.$direction : ' ASC';
+			$direction = in_array(strtoupper(trim($direction)), array('ASC', 'DESC'), TRUE) ? ' '.$direction : ' ASC';
 		}
 
 
@@ -948,9 +987,11 @@
 			foreach (explode(',', $orderby) as $part)
 			{
 				$part = trim($part);
-				if ( ! in_array($part, $this->ar_aliased_tables))
+				if ( ! in_array($part, $this->qb_aliased_tables))
 				{
-					$part = $this->_protect_identifiers(trim($part));
+					$part = preg_match('/^(.+)\s+(ASC|DESC)$/i', $part, $matches)
+						? $this->protect_identifiers(rtrim($matches[1])).' '.$matches[2]
+						: $this->protect_identifiers($part);
 				}
 
 				$temp[] = $part;
@@ -958,20 +999,19 @@
 
 			$orderby = implode(', ', $temp);
 		}
-		elseif ($direction != $this->_random_keyword)
+		elseif ($direction !== $this->_random_keyword && $escape === TRUE)
 		{
-			if ($escape === TRUE)
-			{
-				$orderby = $this->_protect_identifiers($orderby);
-			}
+			$orderby = preg_match('/^(.+)\s+(ASC|DESC)$/i', $orderby, $matches)
+				? $this->protect_identifiers(rtrim($matches[1])).' '.$matches[2]
+				: $this->protect_identifiers($orderby);
 		}
 
-		$this->ar_orderby[] = $orderby_statement = $orderby.$direction;
+		$this->qb_orderby[] = $orderby_statement = $orderby.$direction;
 
-		if ($this->ar_caching === TRUE)
+		if ($this->qb_caching === TRUE)
 		{
-			$this->ar_cache_orderby[] = $orderby_statement;
-			$this->ar_cache_exists[] = 'orderby';
+			$this->qb_cache_orderby[] = $orderby_statement;
+			$this->qb_cache_exists[] = 'orderby';
 		}
 
 		return $this;
@@ -982,17 +1022,17 @@
 	/**
 	 * Sets the LIMIT value
 	 *
-	 * @param	integer	the limit value
-	 * @param	integer	the offset value
+	 * @param	int	the limit value
+	 * @param	int	the offset value
 	 * @return	object
 	 */
 	public function limit($value, $offset = NULL)
 	{
-		$this->ar_limit = (int) $value;
+		$this->qb_limit = (int) $value;
 
-		if ( ! is_null($offset))
+		if ( ! empty($offset))
 		{
-			$this->ar_offset = (int) $offset;
+			$this->qb_offset = (int) $offset;
 		}
 
 		return $this;
@@ -1003,12 +1043,12 @@
 	/**
 	 * Sets the OFFSET value
 	 *
-	 * @param	integer	the offset value
+	 * @param	int	the offset value
 	 * @return	object
 	 */
 	public function offset($offset)
 	{
-		$this->ar_offset = (int) $offset;
+		$this->qb_offset = (int) $offset;
 		return $this;
 	}
 
@@ -1019,7 +1059,7 @@
 	 *
 	 * @param	mixed
 	 * @param	string
-	 * @param	boolean
+	 * @param	bool
 	 * @return	object
 	 */
 	public function set($key, $value = '', $escape = TRUE)
@@ -1035,11 +1075,11 @@
 		{
 			if ($escape === FALSE)
 			{
-				$this->ar_set[$this->_protect_identifiers($k)] = $v;
+				$this->qb_set[$this->protect_identifiers($k)] = $v;
 			}
 			else
 			{
-				$this->ar_set[$this->_protect_identifiers($k, FALSE, TRUE)] = $this->escape($v);
+				$this->qb_set[$this->protect_identifiers($k, FALSE, TRUE)] = $this->escape($v);
 			}
 		}
 
@@ -1053,20 +1093,19 @@
 	 *
 	 * Compiles a SELECT query string and returns the sql.
 	 *
-	 * @access	public
 	 * @param	string	the table name to select from (optional)
-	 * @param	boolean	TRUE: resets AR values; FALSE: leave AR vaules alone
+	 * @param	bool	TRUE: resets QB values; FALSE: leave QB vaules alone
 	 * @return	string
 	 */
 	public function get_compiled_select($table = '', $reset = TRUE)
 	{
-		if ($table != '')
+		if ($table !== '')
 		{
 			$this->_track_aliases($table);
 			$this->from($table);
 		}
 
-		$select =  $this->_compile_select();
+		$select = $this->_compile_select();
 
 		if ($reset === TRUE)
 		{
@@ -1089,15 +1128,15 @@
 	 * @param	string	the offset clause
 	 * @return	object
 	 */
-	public function get($table = '', $limit = null, $offset = null)
+	public function get($table = '', $limit = NULL, $offset = NULL)
 	{
-		if ($table != '')
+		if ($table !== '')
 		{
 			$this->_track_aliases($table);
 			$this->from($table);
 		}
 
-		if ( ! is_null($limit))
+		if ( ! empty($limit))
 		{
 			$this->limit($limit, $offset);
 		}
@@ -1107,24 +1146,26 @@
 		return $result;
 	}
 
+	// --------------------------------------------------------------------
+
 	/**
 	 * "Count All Results" query
 	 *
 	 * Generates a platform-specific query string that counts all records
-	 * returned by an Active Record query.
+	 * returned by an Query Builder query.
 	 *
 	 * @param	string
 	 * @return	string
 	 */
 	public function count_all_results($table = '')
 	{
-		if ($table != '')
+		if ($table !== '')
 		{
 			$this->_track_aliases($table);
 			$this->from($table);
 		}
 
-		$result = $this->query($this->_compile_select($this->_count_string.$this->_protect_identifiers('numrows')));
+		$result = $this->query($this->_compile_select($this->_count_string.$this->protect_identifiers('numrows')));
 		$this->_reset_select();
 
 		if ($result->num_rows() === 0)
@@ -1135,6 +1176,7 @@
 		$row = $result->row();
 		return (int) $row->numrows;
 	}
+
 	// --------------------------------------------------------------------
 
 	/**
@@ -1149,7 +1191,7 @@
 	 */
 	public function get_where($table = '', $where = null, $limit = null, $offset = null)
 	{
-		if ($table != '')
+		if ($table !== '')
 		{
 			$this->from($table);
 		}
@@ -1159,7 +1201,7 @@
 			$this->where($where);
 		}
 
-		if ( ! is_null($limit))
+		if ( ! empty($limit))
 		{
 			$this->limit($limit, $offset);
 		}
@@ -1187,7 +1229,7 @@
 			$this->set_insert_batch($set);
 		}
 
-		if (count($this->ar_set) === 0)
+		if (count($this->qb_set) === 0)
 		{
 			if ($this->db_debug)
 			{
@@ -1197,20 +1239,20 @@
 			return FALSE;
 		}
 
-		if ($table == '')
+		if ($table === '')
 		{
-			if ( ! isset($this->ar_from[0]))
+			if ( ! isset($this->qb_from[0]))
 			{
 				return ($this->db_debug) ? $this->display_error('db_must_set_table') : FALSE;
 			}
 
-			$table = $this->ar_from[0];
+			$table = $this->qb_from[0];
 		}
 
 		// Batch this baby
-		for ($i = 0, $total = count($this->ar_set); $i < $total; $i += 100)
+		for ($i = 0, $total = count($this->qb_set); $i < $total; $i += 100)
 		{
-			$this->query($this->_insert_batch($this->_protect_identifiers($table, TRUE, NULL, FALSE), $this->ar_keys, array_slice($this->ar_set, $i, 100)));
+			$this->query($this->_insert_batch($this->protect_identifiers($table, TRUE, NULL, FALSE), $this->qb_keys, array_slice($this->qb_set, $i, 100)));
 		}
 
 		$this->_reset_write();
@@ -1220,11 +1262,28 @@
 	// --------------------------------------------------------------------
 
 	/**
+	 * Insert_batch statement
+	 *
+	 * Generates a platform-specific insert string from the supplied data.
+	 *
+	 * @param	string	the table name
+	 * @param	array	the insert keys
+	 * @param	array	the insert values
+	 * @return	string
+	 */
+	protected function _insert_batch($table, $keys, $values)
+	{
+		return 'INSERT INTO '.$table.' ('.implode(', ', $keys).') VALUES '.implode(', ', $values);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
 	 * The "set_insert_batch" function.  Allows key/value pairs to be set for batch inserts
 	 *
 	 * @param	mixed
 	 * @param	string
-	 * @param	boolean
+	 * @param	bool
 	 * @return	object
 	 */
 	public function set_insert_batch($key, $value = '', $escape = TRUE)
@@ -1236,25 +1295,22 @@
 			$key = array($key => $value);
 		}
 
-		$keys = array_keys(current($key));
+		$keys = array_keys($this->_object_to_array(current($key)));
 		sort($keys);
 
 		foreach ($key as $row)
 		{
+			$row = $this->_object_to_array($row);
 			if (count(array_diff($keys, array_keys($row))) > 0 OR count(array_diff(array_keys($row), $keys)) > 0)
 			{
 				// batch function above returns an error on an empty array
-				$this->ar_set[] = array();
+				$this->qb_set[] = array();
 				return;
 			}
 
 			ksort($row); // puts $row in the same order as our keys
 
-			if ($escape === FALSE)
-			{
-				$this->ar_set[] =  '('.implode(',', $row).')';
-			}
-			else
+			if ($escape !== FALSE)
 			{
 				$clean = array();
 				foreach ($row as $value)
@@ -1262,13 +1318,15 @@
 					$clean[] = $this->escape($value);
 				}
 
-				$this->ar_set[] =  '('.implode(',', $clean).')';
+				$row = $clean;
 			}
+
+			$this->qb_set[] =  '('.implode(',', $row).')';
 		}
 
 		foreach ($keys as $k)
 		{
-			$this->ar_keys[] = $this->_protect_identifiers($k);
+			$this->qb_keys[] = $this->protect_identifiers($k);
 		}
 
 		return $this;
@@ -1281,9 +1339,8 @@
 	 *
 	 * Compiles an insert query and returns the sql
 	 *
-	 * @access	public
 	 * @param	string	the table to insert into
-	 * @param	boolean	TRUE: reset AR values; FALSE: leave AR values alone
+	 * @param	bool	TRUE: reset QB values; FALSE: leave QB values alone
 	 * @return	string
 	 */
 	public function get_compiled_insert($table = '', $reset = TRUE)
@@ -1294,11 +1351,11 @@
 		}
 
 		$sql = $this->_insert(
-			$this->_protect_identifiers(
-				$this->ar_from[0], TRUE, NULL, FALSE
+			$this->protect_identifiers(
+				$this->qb_from[0], TRUE, NULL, FALSE
 			),
-			array_keys($this->ar_set),
-			array_values($this->ar_set)
+			array_keys($this->qb_set),
+			array_values($this->qb_set)
 		);
 
 		if ($reset === TRUE)
@@ -1316,7 +1373,6 @@
 	 *
 	 * Compiles an insert string and runs the query
 	 *
-	 * @access	public
 	 * @param	string	the table to insert data into
 	 * @param	array	an associative array of insert values
 	 * @return	object
@@ -1334,11 +1390,11 @@
 		}
 
 		$sql = $this->_insert(
-			$this->_protect_identifiers(
-				$this->ar_from[0], TRUE, NULL, FALSE
+			$this->protect_identifiers(
+				$this->qb_from[0], TRUE, NULL, FALSE
 			),
-			array_keys($this->ar_set),
-			array_values($this->ar_set)
+			array_keys($this->qb_set),
+			array_values($this->qb_set)
 		);
 
 		$this->_reset_write();
@@ -1348,33 +1404,46 @@
 	// --------------------------------------------------------------------
 
 	/**
+	 * Insert statement
+	 *
+	 * Generates a platform-specific insert string from the supplied data
+	 *
+	 * @param	string	the table name
+	 * @param	array	the insert keys
+	 * @param	array	the insert values
+	 * @return	string
+	 */
+	protected function _insert($table, $keys, $values)
+	{
+		return 'INSERT INTO '.$table.' ('.implode(', ', $keys).') VALUES ('.implode(', ', $values).')';
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
 	 * Validate Insert
 	 *
 	 * This method is used by both insert() and get_compiled_insert() to
 	 * validate that the there data is actually being set and that table
 	 * has been chosen to be inserted into.
 	 *
-	 * @access	public
 	 * @param	string	the table to insert data into
 	 * @return	string
 	 */
 	protected function _validate_insert($table = '')
 	{
-		if (count($this->ar_set) === 0)
+		if (count($this->qb_set) === 0)
 		{
 			return ($this->db_debug) ? $this->display_error('db_must_use_set') : FALSE;
 		}
 
-		if ($table == '')
+		if ($table !== '')
 		{
-			if ( ! isset($this->ar_from[0]))
-			{
-				return ($this->db_debug) ? $this->display_error('db_must_set_table') : FALSE;
-			}
+			$this->qb_from[0] = $table;
 		}
-		else
+		elseif ( ! isset($this->qb_from[0]))
 		{
-			$this->ar_from[0] = $table;
+			return ($this->db_debug) ? $this->display_error('db_must_set_table') : FALSE;
 		}
 
 		return TRUE;
@@ -1398,22 +1467,23 @@
 			$this->set($set);
 		}
 
-		if (count($this->ar_set) === 0)
+		if (count($this->qb_set) === 0)
 		{
 			return ($this->db_debug) ? $this->display_error('db_must_use_set') : FALSE;
 		}
 
-		if ($table == '')
+		if ($table === '')
 		{
-			if ( ! isset($this->ar_from[0]))
+			if ( ! isset($this->qb_from[0]))
 			{
 				return ($this->db_debug) ? $this->display_error('db_must_set_table') : FALSE;
 			}
 
-			$table = $this->ar_from[0];
+			$table = $this->qb_from[0];
 		}
 
-		$sql = $this->_replace($this->_protect_identifiers($table, TRUE, NULL, FALSE), array_keys($this->ar_set), array_values($this->ar_set));
+		$sql = $this->_replace($this->protect_identifiers($table, TRUE, NULL, FALSE), array_keys($this->qb_set), array_values($this->qb_set));
+
 		$this->_reset_write();
 		return $this->query($sql);
 	}
@@ -1421,13 +1491,47 @@
 	// --------------------------------------------------------------------
 
 	/**
+	 * Replace statement
+	 *
+	 * Generates a platform-specific replace string from the supplied data
+	 *
+	 * @param	string	the table name
+	 * @param	array	the insert keys
+	 * @param	array	the insert values
+	 * @return	string
+	 */
+	protected function _replace($table, $keys, $values)
+	{
+		return 'REPLACE INTO '.$table.' ('.implode(', ', $keys).') VALUES ('.implode(', ', $values).')';
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * From Tables
+	 *
+	 * This public function implicitly groups FROM tables so there is no confusion
+	 * about operator precedence in harmony with SQL standards
+	 *
+	 * @param       array
+	 * @return      string
+	 */
+	protected function _from_tables($tables)
+	{
+		is_array($tables) OR $tables = array($tables);
+
+		return (count($tables) === 1) ? $tables[0] : '('.implode(', ', $tables).')';
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
 	 * Get UPDATE query string
 	 *
 	 * Compiles an update query and returns the sql
 	 *
-	 * @access	public
 	 * @param	string	the table to update
-	 * @param	boolean	TRUE: reset AR values; FALSE: leave AR values alone
+	 * @param	bool	TRUE: reset QB values; FALSE: leave QB values alone
 	 * @return	string
 	 */
 	public function get_compiled_update($table = '', $reset = TRUE)
@@ -1440,7 +1544,7 @@
 			return FALSE;
 		}
 
-		$sql = $this->_update($this->_protect_identifiers($this->ar_from[0], TRUE, NULL, FALSE), $this->ar_set, $this->ar_where, $this->ar_orderby, $this->ar_limit);
+		$sql = $this->_update($this->protect_identifiers($this->qb_from[0], TRUE, NULL, FALSE), $this->qb_set, $this->qb_where, $this->qb_orderby, $this->qb_limit);
 
 		if ($reset === TRUE)
 		{
@@ -1477,17 +1581,18 @@
 			return FALSE;
 		}
 
-		if ($where != NULL)
+		if ($where !== NULL)
 		{
 			$this->where($where);
 		}
 
-		if ($limit != NULL)
+		if ( ! empty($limit))
 		{
 			$this->limit($limit);
 		}
 
-		$sql = $this->_update($this->_protect_identifiers($this->ar_from[0], TRUE, NULL, FALSE), $this->ar_set, $this->ar_where, $this->ar_orderby, $this->ar_limit, $this->ar_like);
+		$sql = $this->_update($this->protect_identifiers($this->qb_from[0], TRUE, NULL, FALSE), $this->qb_set, $this->qb_where, $this->qb_orderby, $this->qb_limit, $this->qb_like);
+
 		$this->_reset_write();
 		return $this->query($sql);
 	}
@@ -1495,33 +1600,64 @@
 	// --------------------------------------------------------------------
 
 	/**
+	 * Update statement
+	 *
+	 * Generates a platform-specific update string from the supplied data
+	 *
+	 * @param	string	the table name
+	 * @param	array	the update data
+	 * @param	array	the where clause
+	 * @param	array	the orderby clause
+	 * @param	array	the limit clause
+	 * @param	array	the like clause
+	 * @return	string
+	 */
+	protected function _update($table, $values, $where, $orderby = array(), $limit = FALSE, $like = array())
+	{
+		foreach ($values as $key => $val)
+		{
+			$valstr[] = $key.' = '.$val;
+		}
+
+		$where = empty($where) ? '' : ' WHERE '.implode(' ', $where);
+
+		if ( ! empty($like))
+		{
+			$where .= ($where === '' ? ' WHERE ' : ' AND ').implode(' ', $like);
+		}
+
+		return 'UPDATE '.$table.' SET '.implode(', ', $valstr)
+			.$where
+			.(count($orderby) > 0 ? ' ORDER BY '.implode(', ', $orderby) : '')
+			.($limit ? ' LIMIT '.$limit : '');
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
 	 * Validate Update
 	 *
 	 * This method is used by both update() and get_compiled_update() to
 	 * validate that data is actually being set and that a table has been
 	 * chosen to be update.
 	 *
-	 * @access	public
 	 * @param	string	the table to update data on
 	 * @return	bool
 	 */
 	protected function _validate_update($table = '')
 	{
-		if (count($this->ar_set) == 0)
+		if (count($this->qb_set) === 0)
 		{
 			return ($this->db_debug) ? $this->display_error('db_must_use_set') : FALSE;
 		}
 
-		if ($table == '')
+		if ($table !== '')
 		{
-			if ( ! isset($this->ar_from[0]))
-			{
-				return ($this->db_debug) ? $this->display_error('db_must_set_table') : FALSE;
-			}
+			$this->qb_from[0] = $table;
 		}
-		else
+		elseif ( ! isset($this->qb_from[0]))
 		{
-			$this->ar_from[0] = $table;
+			return ($this->db_debug) ? $this->display_error('db_must_set_table') : FALSE;
 		}
 
 		return TRUE;
@@ -1554,25 +1690,25 @@
 			$this->set_update_batch($set, $index);
 		}
 
-		if (count($this->ar_set) === 0)
+		if (count($this->qb_set) === 0)
 		{
 			return ($this->db_debug) ? $this->display_error('db_must_use_set') : FALSE;
 		}
 
-		if ($table == '')
+		if ($table === '')
 		{
-			if ( ! isset($this->ar_from[0]))
+			if ( ! isset($this->qb_from[0]))
 			{
 				return ($this->db_debug) ? $this->display_error('db_must_set_table') : FALSE;
 			}
 
-			$table = $this->ar_from[0];
+			$table = $this->qb_from[0];
 		}
 
 		// Batch this baby
-		for ($i = 0, $total = count($this->ar_set); $i < $total; $i += 100)
+		for ($i = 0, $total = count($this->qb_set); $i < $total; $i += 100)
 		{
-			$this->query($this->_update_batch($this->_protect_identifiers($table, TRUE, NULL, FALSE), array_slice($this->ar_set, $i, 100), $this->_protect_identifiers($index), $this->ar_where));
+			$this->query($this->_update_batch($this->protect_identifiers($table, TRUE, NULL, FALSE), array_slice($this->qb_set, $i, 100), $this->protect_identifiers($index), $this->qb_where));
 		}
 
 		$this->_reset_write();
@@ -1586,7 +1722,7 @@
 	 *
 	 * @param	array
 	 * @param	string
-	 * @param	boolean
+	 * @param	bool
 	 * @return	object
 	 */
 	public function set_update_batch($key, $index = '', $escape = TRUE)
@@ -1604,24 +1740,20 @@
 			$clean = array();
 			foreach ($v as $k2 => $v2)
 			{
-				if ($k2 == $index)
+				if ($k2 === $index)
 				{
 					$index_set = TRUE;
 				}
-				else
-				{
-					$not[] = $k.'-'.$v;
-				}
 
-				$clean[$this->_protect_identifiers($k2)] = ($escape === FALSE) ? $v2 : $this->escape($v2);
+				$clean[$this->protect_identifiers($k2)] = ($escape === FALSE) ? $v2 : $this->escape($v2);
 			}
 
-			if ($index_set == FALSE)
+			if ($index_set === FALSE)
 			{
 				return $this->display_error('db_batch_missing_index');
 			}
 
-			$this->ar_set[] = $clean;
+			$this->qb_set[] = $clean;
 		}
 
 		return $this;
@@ -1639,18 +1771,18 @@
 	 */
 	public function empty_table($table = '')
 	{
-		if ($table == '')
+		if ($table === '')
 		{
-			if ( ! isset($this->ar_from[0]))
+			if ( ! isset($this->qb_from[0]))
 			{
 				return ($this->db_debug) ? $this->display_error('db_must_set_table') : FALSE;
 			}
 
-			$table = $this->ar_from[0];
+			$table = $this->qb_from[0];
 		}
 		else
 		{
-			$table = $this->_protect_identifiers($table, TRUE, NULL, FALSE);
+			$table = $this->protect_identifiers($table, TRUE, NULL, FALSE);
 		}
 
 		$sql = $this->_delete($table);
@@ -1672,18 +1804,18 @@
 	 */
 	public function truncate($table = '')
 	{
-		if ($table == '')
+		if ($table === '')
 		{
-			if ( ! isset($this->ar_from[0]))
+			if ( ! isset($this->qb_from[0]))
 			{
 				return ($this->db_debug) ? $this->display_error('db_must_set_table') : FALSE;
 			}
 
-			$table = $this->ar_from[0];
+			$table = $this->qb_from[0];
 		}
 		else
 		{
-			$table = $this->_protect_identifiers($table, TRUE, NULL, FALSE);
+			$table = $this->protect_identifiers($table, TRUE, NULL, FALSE);
 		}
 
 		$sql = $this->_truncate($table);
@@ -1694,13 +1826,30 @@
 	// --------------------------------------------------------------------
 
 	/**
+	 * Truncate statement
+	 *
+	 * Generates a platform-specific truncate string from the supplied data
+	 *
+	 * If the database does not support the truncate() command,
+	 * then this method maps to 'DELETE FROM table'
+	 *
+	 * @param	string	the table name
+	 * @return	string
+	 */
+	protected function _truncate($table)
+	{
+		return 'TRUNCATE '.$table;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
 	 * Get DELETE query string
 	 *
 	 * Compiles a delete query string and returns the sql
 	 *
-	 * @access	public
 	 * @param	string	the table to delete from
-	 * @param	boolean	TRUE: reset AR values; FALSE: leave AR values alone
+	 * @param	bool	TRUE: reset QB values; FALSE: leave QB values alone
 	 * @return	string
 	 */
 	public function get_compiled_delete($table = '', $reset = TRUE)
@@ -1721,7 +1870,7 @@
 	 * @param	mixed	the table(s) to delete from. String or array
 	 * @param	mixed	the where clause
 	 * @param	mixed	the limit clause
-	 * @param	boolean
+	 * @param	bool
 	 * @return	object
 	 */
 	public function delete($table = '', $where = '', $limit = NULL, $reset_data = TRUE)
@@ -1729,14 +1878,14 @@
 		// Combine any cached components with the current statements
 		$this->_merge_cache();
 
-		if ($table == '')
+		if ($table === '')
 		{
-			if ( ! isset($this->ar_from[0]))
+			if ( ! isset($this->qb_from[0]))
 			{
 				return ($this->db_debug) ? $this->display_error('db_must_set_table') : FALSE;
 			}
 
-			$table = $this->ar_from[0];
+			$table = $this->qb_from[0];
 		}
 		elseif (is_array($table))
 		{
@@ -1750,25 +1899,25 @@
 		}
 		else
 		{
-			$table = $this->_protect_identifiers($table, TRUE, NULL, FALSE);
+			$table = $this->protect_identifiers($table, TRUE, NULL, FALSE);
 		}
 
-		if ($where != '')
+		if ($where !== '')
 		{
 			$this->where($where);
 		}
 
-		if ($limit != NULL)
+		if ( ! empty($limit))
 		{
 			$this->limit($limit);
 		}
 
-		if (count($this->ar_where) === 0 && count($this->ar_wherein) === 0 && count($this->ar_like) === 0)
+		if (count($this->qb_where) === 0 && count($this->qb_wherein) === 0 && count($this->qb_like) === 0)
 		{
 			return ($this->db_debug) ? $this->display_error('db_del_must_use_where') : FALSE;
 		}
 
-		$sql = $this->_delete($table, $this->ar_where, $this->ar_like, $this->ar_limit);
+		$sql = $this->_delete($table, $this->qb_where, $this->qb_like, $this->qb_limit);
 		if ($reset_data)
 		{
 			$this->_reset_write();
@@ -1780,6 +1929,31 @@
 	// --------------------------------------------------------------------
 
 	/**
+	 * Delete statement
+	 *
+	 * Generates a platform-specific delete string from the supplied data
+	 *
+	 * @param	string	the table name
+	 * @param	array	the where clause
+	 * @param	array	the like clause
+	 * @param	string	the limit clause
+	 * @return	string
+	 */
+	protected function _delete($table, $where = array(), $like = array(), $limit = FALSE)
+	{
+		$conditions = array();
+
+		empty($where) OR $conditions[] = implode(' ', $where);
+		empty($like) OR $conditions[] = implode(' ', $like);
+
+		return 'DELETE FROM '.$table
+			.(count($conditions) > 0 ? ' WHERE '.implode(' AND ', $conditions) : '')
+			.($limit ? ' LIMIT '.(int) $limit : '');
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
 	 * DB Prefix
 	 *
 	 * Prepends a database prefix if one exists in configuration
@@ -1789,7 +1963,7 @@
 	 */
 	public function dbprefix($table = '')
 	{
-		if ($table == '')
+		if ($table === '')
 		{
 			$this->display_error('db_table_name_required');
 		}
@@ -1844,15 +2018,15 @@
 		if (strpos($table, ' ') !== FALSE)
 		{
 			// if the alias is written with the AS keyword, remove it
-			$table = preg_replace('/ AS /i', ' ', $table);
+			$table = preg_replace('/\s+AS\s+/i', ' ', $table);
 
 			// Grab the alias
 			$table = trim(strrchr($table, ' '));
 
 			// Store the alias, if it doesn't already exist
-			if ( ! in_array($table, $this->ar_aliased_tables))
+			if ( ! in_array($table, $this->qb_aliased_tables))
 			{
-				$this->ar_aliased_tables[] = $table;
+				$this->qb_aliased_tables[] = $table;
 			}
 		}
 	}
@@ -1879,9 +2053,9 @@
 		}
 		else
 		{
-			$sql = ( ! $this->ar_distinct) ? 'SELECT ' : 'SELECT DISTINCT ';
+			$sql = ( ! $this->qb_distinct) ? 'SELECT ' : 'SELECT DISTINCT ';
 
-			if (count($this->ar_select) === 0)
+			if (count($this->qb_select) === 0)
 			{
 				$sql .= '*';
 			}
@@ -1890,73 +2064,69 @@
 				// Cycle through the "select" portion of the query and prep each column name.
 				// The reason we protect identifiers here rather then in the select() function
 				// is because until the user calls the from() function we don't know if there are aliases
-				foreach ($this->ar_select as $key => $val)
+				foreach ($this->qb_select as $key => $val)
 				{
-					$no_escape = isset($this->ar_no_escape[$key]) ? $this->ar_no_escape[$key] : NULL;
-					$this->ar_select[$key] = $this->_protect_identifiers($val, FALSE, $no_escape);
+					$no_escape = isset($this->qb_no_escape[$key]) ? $this->qb_no_escape[$key] : NULL;
+					$this->qb_select[$key] = $this->protect_identifiers($val, FALSE, $no_escape);
 				}
 
-				$sql .= implode(', ', $this->ar_select);
+				$sql .= implode(', ', $this->qb_select);
 			}
 		}
 
 		// Write the "FROM" portion of the query
-		if (count($this->ar_from) > 0)
+		if (count($this->qb_from) > 0)
 		{
-			$sql .= "\nFROM ".$this->_from_tables($this->ar_from);
+			$sql .= "\nFROM ".$this->_from_tables($this->qb_from);
 		}
 
 		// Write the "JOIN" portion of the query
-		if (count($this->ar_join) > 0)
+		if (count($this->qb_join) > 0)
 		{
-			$sql .= "\n".implode("\n", $this->ar_join);
+			$sql .= "\n".implode("\n", $this->qb_join);
 		}
 
 		// Write the "WHERE" portion of the query
-		if (count($this->ar_where) > 0 OR count($this->ar_like) > 0)
+		if (count($this->qb_where) > 0 OR count($this->qb_like) > 0)
 		{
 			$sql .= "\nWHERE ";
 		}
 
-		$sql .= implode("\n", $this->ar_where);
+		$sql .= implode("\n", $this->qb_where);
 
 		// Write the "LIKE" portion of the query
-		if (count($this->ar_like) > 0)
+		if (count($this->qb_like) > 0)
 		{
-			if (count($this->ar_where) > 0)
+			if (count($this->qb_where) > 0)
 			{
 				$sql .= "\nAND ";
 			}
 
-			$sql .= implode("\n", $this->ar_like);
+			$sql .= implode("\n", $this->qb_like);
 		}
 
 		// Write the "GROUP BY" portion of the query
-		if (count($this->ar_groupby) > 0)
+		if (count($this->qb_groupby) > 0)
 		{
-			$sql .= "\nGROUP BY ".implode(', ', $this->ar_groupby);
+			$sql .= "\nGROUP BY ".implode(', ', $this->qb_groupby);
 		}
 
 		// Write the "HAVING" portion of the query
-		if (count($this->ar_having) > 0)
+		if (count($this->qb_having) > 0)
 		{
-			$sql .= "\nHAVING ".implode("\n", $this->ar_having);
+			$sql .= "\nHAVING ".implode("\n", $this->qb_having);
 		}
 
 		// Write the "ORDER BY" portion of the query
-		if (count($this->ar_orderby) > 0)
+		if (count($this->qb_orderby) > 0)
 		{
-			$sql .= "\nORDER BY ".implode(', ', $this->ar_orderby);
-			if ($this->ar_order !== FALSE)
-			{
-				$sql .= ($this->ar_order == 'desc') ? ' DESC' : ' ASC';
-			}
+			$sql .= "\nORDER BY ".implode(', ', $this->qb_orderby);
 		}
 
 		// Write the "LIMIT" portion of the query
-		if (is_numeric($this->ar_limit))
+		if (is_numeric($this->qb_limit))
 		{
-			return $this->_limit($sql."\n", $this->ar_limit, $this->ar_offset);
+			return $this->_limit($sql."\n", $this->qb_limit, $this->qb_offset);
 		}
 
 		return $sql;
@@ -1972,7 +2142,7 @@
 	 * @param	object
 	 * @return	array
 	 */
-	public function _object_to_array($object)
+	protected function _object_to_array($object)
 	{
 		if ( ! is_object($object))
 		{
@@ -1983,7 +2153,7 @@
 		foreach (get_object_vars($object) as $key => $val)
 		{
 			// There are some built in keys we need to ignore for this conversion
-			if ( ! is_object($val) && ! is_array($val) && $key != '_parent_name')
+			if ( ! is_object($val) && ! is_array($val) && $key !== '_parent_name')
 			{
 				$array[$key] = $val;
 			}
@@ -2002,7 +2172,7 @@
 	 * @param	object
 	 * @return	array
 	 */
-	public function _object_to_array_batch($object)
+	protected function _object_to_array_batch($object)
 	{
 		if ( ! is_object($object))
 		{
@@ -2034,13 +2204,13 @@
 	/**
 	 * Start Cache
 	 *
-	 * Starts AR caching
+	 * Starts QB caching
 	 *
 	 * @return	void
 	 */
 	public function start_cache()
 	{
-		$this->ar_caching = TRUE;
+		$this->qb_caching = TRUE;
 	}
 
 	// --------------------------------------------------------------------
@@ -2048,13 +2218,13 @@
 	/**
 	 * Stop Cache
 	 *
-	 * Stops AR caching
+	 * Stops QB caching
 	 *
 	 * @return	void
 	 */
 	public function stop_cache()
 	{
-		$this->ar_caching = FALSE;
+		$this->qb_caching = FALSE;
 	}
 
 	// --------------------------------------------------------------------
@@ -2062,25 +2232,24 @@
 	/**
 	 * Flush Cache
 	 *
-	 * Empties the AR cache
+	 * Empties the QB cache
 	 *
-	 * @access	public
 	 * @return	void
 	 */
 	public function flush_cache()
 	{
 		$this->_reset_run(array(
-			'ar_cache_select'		=> array(),
-			'ar_cache_from'			=> array(),
-			'ar_cache_join'			=> array(),
-			'ar_cache_where'		=> array(),
-			'ar_cache_like'			=> array(),
-			'ar_cache_groupby'		=> array(),
-			'ar_cache_having'		=> array(),
-			'ar_cache_orderby'		=> array(),
-			'ar_cache_set'			=> array(),
-			'ar_cache_exists'		=> array(),
-			'ar_cache_no_escape'	=> array()
+			'qb_cache_select'		=> array(),
+			'qb_cache_from'			=> array(),
+			'qb_cache_join'			=> array(),
+			'qb_cache_where'		=> array(),
+			'qb_cache_like'			=> array(),
+			'qb_cache_groupby'		=> array(),
+			'qb_cache_having'		=> array(),
+			'qb_cache_orderby'		=> array(),
+			'qb_cache_set'			=> array(),
+			'qb_cache_exists'		=> array(),
+			'qb_cache_no_escape'	=> array()
 		));
 	}
 
@@ -2089,47 +2258,47 @@
 	/**
 	 * Merge Cache
 	 *
-	 * When called, this function merges any cached AR arrays with
+	 * When called, this function merges any cached QB arrays with
 	 * locally called ones.
 	 *
 	 * @return	void
 	 */
 	protected function _merge_cache()
 	{
-		if (count($this->ar_cache_exists) === 0)
+		if (count($this->qb_cache_exists) === 0)
 		{
 			return;
 		}
 
-		foreach ($this->ar_cache_exists as $val)
+		foreach ($this->qb_cache_exists as $val)
 		{
-			$ar_variable	= 'ar_'.$val;
-			$ar_cache_var	= 'ar_cache_'.$val;
+			$qb_variable	= 'qb_'.$val;
+			$qb_cache_var	= 'qb_cache_'.$val;
 
-			if (count($this->$ar_cache_var) === 0)
+			if (count($this->$qb_cache_var) === 0)
 			{
 				continue;
 			}
 
-			$this->$ar_variable = array_unique(array_merge($this->$ar_cache_var, $this->$ar_variable));
+			$this->$qb_variable = array_unique(array_merge($this->$qb_cache_var, $this->$qb_variable));
 		}
 
 		// If we are "protecting identifiers" we need to examine the "from"
 		// portion of the query to determine if there are any aliases
-		if ($this->_protect_identifiers === TRUE AND count($this->ar_cache_from) > 0)
+		if ($this->_protect_identifiers === TRUE && count($this->qb_cache_from) > 0)
 		{
-			$this->_track_aliases($this->ar_from);
+			$this->_track_aliases($this->qb_from);
 		}
 
-		$this->ar_no_escape = $this->ar_cache_no_escape;
+		$this->qb_no_escape = $this->qb_cache_no_escape;
 	}
 
 	// --------------------------------------------------------------------
 
 	/**
-	 * Reset Active Record values.
+	 * Reset Query Builder values.
 	 *
-	 * Publicly-visible method to reset the AR values.
+	 * Publicly-visible method to reset the QB values.
 	 *
 	 * @return	void
 	 */
@@ -2142,16 +2311,16 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 * Resets the active record values.  Called by the get() function
+	 * Resets the query builder values.  Called by the get() function
 	 *
 	 * @param	array	An array of fields to reset
 	 * @return	void
 	 */
-	protected function _reset_run($ar_reset_items)
+	protected function _reset_run($qb_reset_items)
 	{
-		foreach ($ar_reset_items as $item => $default_value)
+		foreach ($qb_reset_items as $item => $default_value)
 		{
-			if ( ! in_array($item, $this->ar_store_array))
+			if ( ! in_array($item, $this->qb_store_array))
 			{
 				$this->$item = $default_value;
 			}
@@ -2161,28 +2330,27 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 * Resets the active record values.  Called by the get() function
+	 * Resets the query builder values.  Called by the get() function
 	 *
 	 * @return	void
 	 */
 	protected function _reset_select()
 	{
 		$this->_reset_run(array(
-					'ar_select'		=> array(),
-					'ar_from'		=> array(),
-					'ar_join'		=> array(),
-					'ar_where'		=> array(),
-					'ar_like'		=> array(),
-					'ar_groupby'		=> array(),
-					'ar_having'		=> array(),
-					'ar_orderby'		=> array(),
-					'ar_wherein'		=> array(),
-					'ar_aliased_tables'	=> array(),
-					'ar_no_escape'		=> array(),
-					'ar_distinct'		=> FALSE,
-					'ar_limit'		=> FALSE,
-					'ar_offset'		=> FALSE,
-					'ar_order'		=> FALSE
+					'qb_select'		=> array(),
+					'qb_from'		=> array(),
+					'qb_join'		=> array(),
+					'qb_where'		=> array(),
+					'qb_like'		=> array(),
+					'qb_groupby'		=> array(),
+					'qb_having'		=> array(),
+					'qb_orderby'		=> array(),
+					'qb_wherein'		=> array(),
+					'qb_aliased_tables'	=> array(),
+					'qb_no_escape'		=> array(),
+					'qb_distinct'		=> FALSE,
+					'qb_limit'		=> FALSE,
+					'qb_offset'		=> FALSE
 					)
 				);
 	}
@@ -2190,7 +2358,7 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 * Resets the active record "write" values.
+	 * Resets the query builder "write" values.
 	 *
 	 * Called by the insert() update() insert_batch() update_batch() and delete() functions
 	 *
@@ -2199,19 +2367,18 @@
 	protected function _reset_write()
 	{
 		$this->_reset_run(array(
-					'ar_set'	=> array(),
-					'ar_from'	=> array(),
-					'ar_where'	=> array(),
-					'ar_like'	=> array(),
-					'ar_orderby'	=> array(),
-					'ar_keys'	=> array(),
-					'ar_limit'	=> FALSE,
-					'ar_order'	=> FALSE
-					)
-				);
+			'qb_set'	=> array(),
+			'qb_from'	=> array(),
+			'qb_where'	=> array(),
+			'qb_like'	=> array(),
+			'qb_orderby'	=> array(),
+			'qb_keys'	=> array(),
+			'qb_limit'	=> FALSE
+			)
+		);
 	}
 
 }
 
-/* End of file DB_active_rec.php */
-/* Location: ./system/database/DB_active_rec.php */
+/* End of file DB_query_builder.php */
+/* Location: ./system/database/DB_query_builder.php */
\ No newline at end of file
diff --git a/system/database/DB_result.php b/system/database/DB_result.php
index 7304432..991f6ba 100644
--- a/system/database/DB_result.php
+++ b/system/database/DB_result.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -47,11 +47,17 @@
 	public $num_rows			= 0;
 	public $row_data			= NULL;
 
+	public function __construct(&$driver_object)
+	{
+		$this->conn_id = $driver_object->conn_id;
+		$this->result_id = $driver_object->result_id;
+	}
+
 	/**
 	 * Query result.  Acts as a wrapper function for the following functions.
 	 *
 	 * @param	string	can be "object" or "array"
-	 * @return	mixed	either a result object or array
+	 * @return	object
 	 */
 	public function result($type = 'object')
 	{
@@ -75,7 +81,7 @@
 			return $this->custom_result_object[$class_name];
 		}
 
-		if ($this->result_id === FALSE OR $this->num_rows() == 0)
+		if ($this->result_id === FALSE OR $this->num_rows() === 0)
 		{
 			return array();
 		}
@@ -102,9 +108,9 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 * Query result.  "object" version.
+	 * Query result. "object" version.
 	 *
-	 * @return	object
+	 * @return	array
 	 */
 	public function result_object()
 	{
@@ -116,7 +122,7 @@
 		// In the event that query caching is on the result_id variable
 		// will return FALSE since there isn't a valid SQL resource so
 		// we'll simply return an empty array.
-		if ($this->result_id === FALSE OR $this->num_rows() == 0)
+		if ($this->result_id === FALSE OR $this->num_rows() === 0)
 		{
 			return array();
 		}
@@ -147,7 +153,7 @@
 		// In the event that query caching is on the result_id variable
 		// will return FALSE since there isn't a valid SQL resource so
 		// we'll simply return an empty array.
-		if ($this->result_id === FALSE OR $this->num_rows() == 0)
+		if ($this->result_id === FALSE OR $this->num_rows() === 0)
 		{
 			return array();
 		}
@@ -218,7 +224,7 @@
 			return;
 		}
 
-		if ($key != '' AND ! is_null($value))
+		if ($key !== '' && ! is_null($value))
 		{
 			$this->row_data[$key] = $value;
 		}
@@ -236,10 +242,10 @@
 		$result = $this->custom_result_object($type);
 		if (count($result) === 0)
 		{
-			return $result;
+			return NULL;
 		}
 
-		if ($n != $this->current_row AND isset($result[$n]))
+		if ($n !== $this->current_row && isset($result[$n]))
 		{
 			$this->current_row = $n;
 		}
@@ -247,6 +253,8 @@
 		return $result[$this->current_row];
 	}
 
+	// --------------------------------------------------------------------
+
 	/**
 	 * Returns a single result row - object version
 	 *
@@ -257,10 +265,10 @@
 		$result = $this->result_object();
 		if (count($result) === 0)
 		{
-			return $result;
+			return NULL;
 		}
 
-		if ($n != $this->current_row AND isset($result[$n]))
+		if ($n !== $this->current_row && isset($result[$n]))
 		{
 			$this->current_row = $n;
 		}
@@ -280,10 +288,10 @@
 		$result = $this->result_array();
 		if (count($result) === 0)
 		{
-			return $result;
+			return NULL;
 		}
 
-		if ($n != $this->current_row AND isset($result[$n]))
+		if ($n !== $this->current_row && isset($result[$n]))
 		{
 			$this->current_row = $n;
 		}
@@ -291,7 +299,6 @@
 		return $result[$this->current_row];
 	}
 
-
 	// --------------------------------------------------------------------
 
 	/**
@@ -302,7 +309,7 @@
 	public function first_row($type = 'object')
 	{
 		$result = $this->result($type);
-		return (count($result) === 0) ? $result : $result[0];
+		return (count($result) === 0) ? NULL : $result[0];
 	}
 
 	// --------------------------------------------------------------------
@@ -315,7 +322,7 @@
 	public function last_row($type = 'object')
 	{
 		$result = $this->result($type);
-		return (count($result) === 0) ? $result : $result[count($result) - 1];
+		return (count($result) === 0) ? NULL : $result[count($result) - 1];
 	}
 
 	// --------------------------------------------------------------------
@@ -330,7 +337,7 @@
 		$result = $this->result($type);
 		if (count($result) === 0)
 		{
-			return $result;
+			return NULL;
 		}
 
 		if (isset($result[$this->current_row + 1]))
@@ -353,7 +360,7 @@
 		$result = $this->result($type);
 		if (count($result) === 0)
 		{
-			return $result;
+			return NULL;
 		}
 
 		if (isset($result[$this->current_row - 1]))
@@ -366,11 +373,23 @@
 	// --------------------------------------------------------------------
 
 	/**
+	 * Returns an unbuffered row and move pointer to next row
+	 *
+	 * @return	mixed	either a result object or array
+	 */
+	public function unbuffered_row($type = 'object')
+	{
+		return ($type !== 'array') ? $this->_fetch_object() : $this->_fetch_assoc();
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
 	 * The following functions are normally overloaded by the identically named
 	 * methods in the platform-specific driver -- except when query caching
-	 * is used.  When caching is enabled we do not load the other driver.
+	 * is used. When caching is enabled we do not load the other driver.
 	 * These functions are primarily here to prevent undefined function errors
-	 * when a cached result object is in use.  They are not otherwise fully
+	 * when a cached result object is in use. They are not otherwise fully
 	 * operational due to the unavailability of the database resource IDs with
 	 * cached results.
 	 */
@@ -378,12 +397,12 @@
 	public function num_fields() { return 0; }
 	public function list_fields() { return array(); }
 	public function field_data() { return array(); }
-	public function free_result() { return TRUE; }
-	protected function _data_seek() { return TRUE; }
+	public function free_result() { $this->result_id = FALSE; }
+	protected function _data_seek() { return FALSE; }
 	protected function _fetch_assoc() { return array(); }
 	protected function _fetch_object() { return array(); }
 
 }
 
 /* End of file DB_result.php */
-/* Location: ./system/database/DB_result.php */
+/* Location: ./system/database/DB_result.php */
\ No newline at end of file
diff --git a/system/database/DB_utility.php b/system/database/DB_utility.php
index 4c881d8..6a3b407 100644
--- a/system/database/DB_utility.php
+++ b/system/database/DB_utility.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -32,10 +32,14 @@
  * @author		EllisLab Dev Team
  * @link		http://codeigniter.com/user_guide/database/
  */
-class CI_DB_utility extends CI_DB_forge {
+abstract class CI_DB_utility extends CI_DB_forge {
 
 	public $db;
-	public $data_cache		= array();
+
+	// Platform specific SQL strings
+	// Just setting those defaults to FALSE as they are mostly MySQL-specific
+	protected $_optimize_table	= FALSE;
+	protected $_repair_table	= FALSE;
 
 	public function __construct()
 	{
@@ -50,27 +54,34 @@
 	/**
 	 * List databases
 	 *
-	 * @return	bool
+	 * @return	array
 	 */
 	public function list_databases()
 	{
 		// Is there a cached result?
-		if (isset($this->data_cache['db_names']))
+		if (isset($this->db->data_cache['db_names']))
 		{
-			return $this->data_cache['db_names'];
+			return $this->db->data_cache['db_names'];
+		}
+		elseif ($this->_list_databases === FALSE)
+		{
+			return ($this->db->db_debug) ? $this->db->display_error('db_unsuported_feature') : FALSE;
 		}
 
-		$query = $this->db->query($this->_list_databases());
-		$dbs = array();
-		if ($query->num_rows() > 0)
+		$this->db->data_cache['db_names'] = array();
+
+		$query = $this->db->query($this->_list_databases);
+		if ($query === FALSE)
 		{
-			foreach ($query->result_array() as $row)
-			{
-				$dbs[] = current($row);
-			}
+			return $this->db->data_cache['db_names'];
 		}
 
-		return $this->data_cache['db_names'] = $dbs;
+		for ($i = 0, $c = count($query); $i < $c; $i++)
+		{
+			$this->db->data_cache['db_names'] = current($query[$i]);
+		}
+
+		return $this->db->data_cache['db_names'];
 	}
 
 	// --------------------------------------------------------------------
@@ -79,48 +90,36 @@
 	 * Determine if a particular database exists
 	 *
 	 * @param	string
-	 * @return	boolean
+	 * @return	bool
 	 */
 	public function database_exists($database_name)
 	{
-		// Some databases won't have access to the list_databases() function, so
-		// this is intended to allow them to override with their own functions as
-		// defined in $driver_utility.php
-		if (method_exists($this, '_database_exists'))
-		{
-			return $this->_database_exists($database_name);
-		}
-		else
-		{
-			return ( ! in_array($database_name, $this->list_databases())) ? FALSE : TRUE;
-		}
+		return in_array($database_name, $this->list_databases());
 	}
 
-
 	// --------------------------------------------------------------------
 
 	/**
 	 * Optimize Table
 	 *
 	 * @param	string	the table name
-	 * @return	bool
+	 * @return	mixed
 	 */
 	public function optimize_table($table_name)
 	{
-		$sql = $this->_optimize_table($table_name);
-
-		if (is_bool($sql))
+		if ($this->_optimize_table === FALSE)
 		{
-			show_error('db_must_use_set');
-			return FALSE;
+			return ($this->db->db_debug) ? $this->db->display_error('db_unsuported_feature') : FALSE;
 		}
 
-		$query = $this->db->query($sql);
-		$res = $query->result_array();
+		$query = $this->db->query(sprintf($this->_optimize_table, $this->db->escape_identifiers($table_name)));
+		if ($query !== FALSE)
+		{
+			$query = $query->result_array();
+			return current($res);
+		}
 
-		// Note: Due to a bug in current() that affects some versions
-		// of PHP we can not pass function call directly into it
-		return current($res);
+		return FALSE;
 	}
 
 	// --------------------------------------------------------------------
@@ -128,26 +127,26 @@
 	/**
 	 * Optimize Database
 	 *
-	 * @return	array
+	 * @return	mixed
 	 */
 	public function optimize_database()
 	{
+		if ($this->_optimize_table === FALSE)
+		{
+			return ($this->db->db_debug) ? $this->db->display_error('db_unsuported_feature') : FALSE;
+		}
+
 		$result = array();
 		foreach ($this->db->list_tables() as $table_name)
 		{
-			$sql = $this->_optimize_table($table_name);
-
-			if (is_bool($sql))
+			$res = $this->db->query(sprintf($this->_optimize_table, $this->db->escape_identifiers($table_name)));
+			if (is_bool($res))
 			{
-				return $sql;
+				return $res;
 			}
 
-			$query = $this->db->query($sql);
-
 			// Build the result array...
-			// Note: Due to a bug in current() that affects some versions
-			// of PHP we can not pass function call directly into it
-			$res = $query->result_array();
+			$res = $res->result_array();
 			$res = current($res);
 			$key = str_replace($this->db->database.'.', '', current($res));
 			$keys = array_keys($res);
@@ -165,23 +164,23 @@
 	 * Repair Table
 	 *
 	 * @param	string	the table name
-	 * @return	bool
+	 * @return	mixed
 	 */
 	public function repair_table($table_name)
 	{
-		$sql = $this->_repair_table($table_name);
-
-		if (is_bool($sql))
+		if ($this->_repair_table === FALSE)
 		{
-			return $sql;
+			return ($this->db->db_debug) ? $this->db->display_error('db_unsuported_feature') : FALSE;
 		}
 
-		$query = $this->db->query($sql);
+		$query = $this->db->query(sprintf($this->_repair_table, $this->db->escape_identifiers($table_name)));
+		if (is_bool($query))
+		{
+			return $query;
+		}
 
-		// Note: Due to a bug in current() that affects some versions
-		// of PHP we can not pass function call directly into it
-		$res = $query->result_array();
-		return current($res);
+		$query = $query->result_array();
+		return current($query);
 	}
 
 	// --------------------------------------------------------------------
@@ -212,7 +211,7 @@
 		$out = rtrim($out).$newline;
 
 		// Next blast through the result array and build out the rows
-		foreach ($query->result_array() as $row)
+		while ($row = $query->unbuffered_row('array'))
 		{
 			foreach ($row as $item)
 			{
@@ -257,18 +256,18 @@
 		$CI->load->helper('xml');
 
 		// Generate the result
-		$xml = "<{$root}>".$newline;
-		foreach ($query->result_array() as $row)
+		$xml = '<'.$root.'>'.$newline;
+		while ($row = $query->unbuffered_row())
 		{
-			$xml .= $tab."<{$element}>".$newline;
+			$xml .= $tab.'<'.$element.'>'.$newline;
 			foreach ($row as $key => $val)
 			{
-				$xml .= $tab.$tab."<{$key}>".xml_convert($val)."</{$key}>".$newline;
+				$xml .= $tab.$tab.'<'.$key.'>'.xml_convert($val).'</'.$key.'>'.$newline;
 			}
-			$xml .= $tab."</{$element}>".$newline;
+			$xml .= $tab.'</'.$element.'>'.$newline;
 		}
 
-		return $xml .= "</$root>".$newline;
+		return $xml.'</'.$root.'>'.$newline;
 	}
 
 	// --------------------------------------------------------------------
@@ -328,8 +327,8 @@
 
 		// Is the encoder supported? If not, we'll either issue an
 		// error or use plain text depending on the debug settings
-		if (($prefs['format'] === 'gzip' AND ! @function_exists('gzencode'))
-			OR ($prefs['format'] === 'zip'  AND ! @function_exists('gzcompress')))
+		if (($prefs['format'] === 'gzip' && ! @function_exists('gzencode'))
+			OR ($prefs['format'] === 'zip' && ! @function_exists('gzcompress')))
 		{
 			if ($this->db->db_debug)
 			{
@@ -343,7 +342,7 @@
 		if ($prefs['format'] === 'zip')
 		{
 			// Set the filename if not provided (only needed with Zip files)
-			if ($prefs['filename'] == '')
+			if ($prefs['filename'] === '')
 			{
 				$prefs['filename'] = (count($prefs['tables']) === 1 ? $prefs['tables'] : $this->db->database)
 							.date('Y-m-d_H-i', time()).'.sql';
@@ -369,7 +368,7 @@
 			$CI->zip->add_data($prefs['filename'], $this->_backup($prefs));
 			return $CI->zip->get_zip();
 		}
-		elseif ($prefs['format'] == 'txt') // Was a text file requested?
+		elseif ($prefs['format'] === 'txt') // Was a text file requested?
 		{
 			return $this->_backup($prefs);
 		}
@@ -384,4 +383,4 @@
 }
 
 /* End of file DB_utility.php */
-/* Location: ./system/database/DB_utility.php */
+/* Location: ./system/database/DB_utility.php */
\ No newline at end of file
diff --git a/system/database/drivers/cubrid/cubrid_driver.php b/system/database/drivers/cubrid/cubrid_driver.php
index cde719e..6b67b75 100644
--- a/system/database/drivers/cubrid/cubrid_driver.php
+++ b/system/database/drivers/cubrid/cubrid_driver.php
@@ -1,13 +1,13 @@
-<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
- * 
+ *
  * Licensed under the Open Software License version 3.0
- * 
+ *
  * This source file is subject to the Open Software License (OSL 3.0) that is
  * bundled with this package in the files license.txt / license.rst.  It is
  * also available through the world wide web at this URL:
@@ -21,17 +21,15 @@
  * @copyright	Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/)
  * @license		http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
  * @link		http://codeigniter.com
- * @since		Version 2.0.2
+ * @since		Version 2.1
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * CUBRID Database Adapter Class
  *
  * Note: _DB is an extender class that the app controller
- * creates dynamically based on whether the active record
+ * creates dynamically based on whether the query builder
  * class is being used or not.
  *
  * @package		CodeIgniter
@@ -42,79 +40,102 @@
  */
 class CI_DB_cubrid_driver extends CI_DB {
 
-	// Default CUBRID Broker port. Will be used unless user
-	// explicitly specifies another one.
-	const DEFAULT_PORT = 33000;
-
-	var $dbdriver = 'cubrid';
+	public $dbdriver = 'cubrid';
 
 	// The character used for escaping - no need in CUBRID
-	var	$_escape_char = '';
+	protected $_escape_char = '`';
 
 	// clause and character used for LIKE escape sequences - not used in CUBRID
-	var $_like_escape_str = '';
-	var $_like_escape_chr = '';
+	protected $_like_escape_str = '';
+	protected $_like_escape_chr = '';
 
 	/**
 	 * The syntax to count rows is slightly different across different
 	 * database engines, so this string appears in each driver and is
 	 * used for the count_all() and count_all_results() functions.
 	 */
-	var $_count_string = 'SELECT COUNT(*) AS ';
-	var $_random_keyword = ' RAND()'; // database specific random keyword
+	protected $_count_string = 'SELECT COUNT(*) AS ';
+	protected $_random_keyword = ' RAND()'; // database specific random keyword
+
+	// CUBRID-specific properties
+	public $auto_commit = TRUE;
+
+	public function __construct($params)
+	{
+		parent::__construct($params);
+
+		if (preg_match('/^CUBRID:[^:]+(:[0-9][1-9]{0,4})?:[^:]+:[^:]*:[^:]*:(\?.+)?$/', $this->dsn, $matches))
+		{
+			if (stripos($matches[2], 'autocommit=off') !== FALSE)
+			{
+				$this->auto_commit = FALSE;
+			}
+		}
+		else
+		{
+			// If no port is defined by the user, use the default value
+			empty($this->port) OR $this->port = 33000;
+		}
+	}
 
 	/**
 	 * Non-persistent database connection
 	 *
-	 * @access	private called by the base class
 	 * @return	resource
 	 */
-	function db_connect()
+	public function db_connect()
 	{
-		// If no port is defined by the user, use the default value
-		if ($this->port == '')
-		{
-			$this->port = self::DEFAULT_PORT;
-		}
-
-		$conn = cubrid_connect($this->hostname, $this->port, $this->database, $this->username, $this->password);
-
-		if ($conn)
-		{
-			// Check if a user wants to run queries in dry, i.e. run the
-			// queries but not commit them.
-			if (isset($this->auto_commit) && ! $this->auto_commit)
-			{
-				cubrid_set_autocommit($conn, CUBRID_AUTOCOMMIT_FALSE);
-			}
-			else
-			{
-				cubrid_set_autocommit($conn, CUBRID_AUTOCOMMIT_TRUE);
-				$this->auto_commit = TRUE;
-			}
-		}
-
-		return $conn;
+		return $this->_cubrid_connect();
 	}
 
 	// --------------------------------------------------------------------
 
 	/**
 	 * Persistent database connection
+	 *
 	 * In CUBRID persistent DB connection is supported natively in CUBRID
 	 * engine which can be configured in the CUBRID Broker configuration
 	 * file by setting the CCI_PCONNECT parameter to ON. In that case, all
 	 * connections established between the client application and the
-	 * server will become persistent. This is calling the same
-	 * @cubrid_connect function will establish persisten connection
-	 * considering that the CCI_PCONNECT is ON.
+	 * server will become persistent.
 	 *
-	 * @access	private called by the base class
 	 * @return	resource
 	 */
-	function db_pconnect()
+	public function db_pconnect()
 	{
-		return $this->db_connect();
+		return $this->_cubrid_connect(TRUE);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * CUBRID connection
+	 *
+	 * A CUBRID-specific method to create a connection to the database.
+	 * Except for determining if a persistent connection should be used,
+	 * the rest of the logic is the same for db_connect() and db_pconnect().
+	 *
+	 * @param	bool
+	 * @return	resource
+	 */
+	protected function _cubrid_connect($persistent = FALSE)
+	{
+		if (preg_match('/^CUBRID:[^:]+(:[0-9][1-9]{0,4})?:[^:]+:([^:]*):([^:]*):(\?.+)?$/', $this->dsn, $matches))
+		{
+			$_temp = ($persistent !== TRUE) ? 'cubrid_connect_with_url' : 'cubrid_pconnect_with_url';
+			$conn_id = ($matches[2] === '' && $matches[3] === '' && $this->username !== '' && $this->password !== '')
+					? $_temp($this->dsn, $this->username, $this->password)
+					: $_temp($this->dsn);
+		}
+		else
+		{
+			$_temp = ($persistent !== TRUE) ? 'cubrid_connect' : 'cubrid_pconnect';
+			$conn_id = ($this->username !== '')
+					? $_temp($this->hostname, $this->port, $this->database, $this->username, $this->password)
+					: $_temp($this->hostname, $this->port, $this->database);
+		}
+
+		return $conn_id;
 	}
 
 	// --------------------------------------------------------------------
@@ -125,10 +146,9 @@
 	 * Keep / reestablish the db connection if no queries have been
 	 * sent for a length of time exceeding the server's idle timeout
 	 *
-	 * @access	public
 	 * @return	void
 	 */
-	function reconnect()
+	public function reconnect()
 	{
 		if (cubrid_ping($this->conn_id) === FALSE)
 		{
@@ -139,54 +159,15 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 * Select the database
+	 * Database version number
 	 *
-	 * @access	private called by the base class
-	 * @return	resource
-	 */
-	function db_select()
-	{
-		// In CUBRID there is no need to select a database as the database
-		// is chosen at the connection time.
-		// So, to determine if the database is "selected", all we have to
-		// do is ping the server and return that value.
-		return cubrid_ping($this->conn_id);
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Set client character set
-	 *
-	 * @access	public
-	 * @param	string
-	 * @param	string
-	 * @return	resource
-	 */
-	function db_set_charset($charset, $collation)
-	{
-		// In CUBRID, there is no need to set charset or collation.
-		// This is why returning true will allow the application continue
-		// its normal process.
-		return TRUE;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Version number query string
-	 *
-	 * @access	public
 	 * @return	string
 	 */
-	function _version()
+	public function version()
 	{
-		// To obtain the CUBRID Server version, no need to run the SQL query.
-		// CUBRID PHP API provides a function to determin this value.
-		// This is why we also need to add 'cubrid' value to the list of
-		// $driver_version_exceptions array in DB_driver class in
-		// version() function.
-		return cubrid_get_server_info($this->conn_id);
+		return isset($this->data_cache['version'])
+			? $this->data_cache['version']
+			: $this->data_cache['version'] = cubrid_get_server_info($this->conn_id);
 	}
 
 	// --------------------------------------------------------------------
@@ -194,50 +175,25 @@
 	/**
 	 * Execute the query
 	 *
-	 * @access	private called by the base class
 	 * @param	string	an SQL query
 	 * @return	resource
 	 */
-	function _execute($sql)
+	protected function _execute($sql)
 	{
-		$sql = $this->_prep_query($sql);
 		return @cubrid_query($sql, $this->conn_id);
 	}
 
 	// --------------------------------------------------------------------
 
 	/**
-	 * Prep the query
-	 *
-	 * If needed, each database adapter can prep the query string
-	 *
-	 * @access	private called by execute()
-	 * @param	string	an SQL query
-	 * @return	string
-	 */
-	function _prep_query($sql)
-	{
-		// No need to prepare
-		return $sql;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
 	 * Begin Transaction
 	 *
-	 * @access	public
 	 * @return	bool
 	 */
-	function trans_begin($test_mode = FALSE)
+	public function trans_begin($test_mode = FALSE)
 	{
-		if ( ! $this->trans_enabled)
-		{
-			return TRUE;
-		}
-
 		// When transactions are nested we only begin/commit/rollback the outermost ones
-		if ($this->_trans_depth > 0)
+		if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
 		{
 			return TRUE;
 		}
@@ -245,7 +201,7 @@
 		// Reset the transaction failure flag.
 		// If the $test_mode flag is set to TRUE transactions will be rolled back
 		// even if the queries produce a successful result.
-		$this->_trans_failure = ($test_mode === TRUE) ? TRUE : FALSE;
+		$this->_trans_failure = ($test_mode === TRUE);
 
 		if (cubrid_get_autocommit($this->conn_id))
 		{
@@ -260,18 +216,12 @@
 	/**
 	 * Commit Transaction
 	 *
-	 * @access	public
 	 * @return	bool
 	 */
-	function trans_commit()
+	public function trans_commit()
 	{
-		if ( ! $this->trans_enabled)
-		{
-			return TRUE;
-		}
-
 		// When transactions are nested we only begin/commit/rollback the outermost ones
-		if ($this->_trans_depth > 0)
+		if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
 		{
 			return TRUE;
 		}
@@ -291,18 +241,12 @@
 	/**
 	 * Rollback Transaction
 	 *
-	 * @access	public
 	 * @return	bool
 	 */
-	function trans_rollback()
+	public function trans_rollback()
 	{
-		if ( ! $this->trans_enabled)
-		{
-			return TRUE;
-		}
-
 		// When transactions are nested we only begin/commit/rollback the outermost ones
-		if ($this->_trans_depth > 0)
+		if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
 		{
 			return TRUE;
 		}
@@ -322,12 +266,11 @@
 	/**
 	 * Escape String
 	 *
-	 * @access	public
 	 * @param	string
 	 * @param	bool	whether or not the string will be used in a LIKE condition
 	 * @return	string
 	 */
-	function escape_str($str, $like = FALSE)
+	public function escape_str($str, $like = FALSE)
 	{
 		if (is_array($str))
 		{
@@ -339,7 +282,9 @@
 			return $str;
 		}
 
-		if (function_exists('cubrid_real_escape_string') AND is_resource($this->conn_id))
+		if (function_exists('cubrid_real_escape_string') &&
+			(is_resource($this->conn_id)
+				OR (get_resource_type($this->conn_id) === 'Unknown' && preg_match('/Resource id #/', strval($this->conn_id)))))
 		{
 			$str = cubrid_real_escape_string($str, $this->conn_id);
 		}
@@ -351,7 +296,7 @@
 		// escape LIKE condition wildcards
 		if ($like === TRUE)
 		{
-			$str = str_replace(array('%', '_'), array('\\%', '\\_'), $str);
+			return str_replace(array('%', '_'), array('\\%', '\\_'), $str);
 		}
 
 		return $str;
@@ -362,12 +307,11 @@
 	/**
 	 * Affected Rows
 	 *
-	 * @access	public
-	 * @return	integer
+	 * @return	int
 	 */
-	function affected_rows()
+	public function affected_rows()
 	{
-		return @cubrid_affected_rows($this->conn_id);
+		return @cubrid_affected_rows();
 	}
 
 	// --------------------------------------------------------------------
@@ -375,10 +319,9 @@
 	/**
 	 * Insert ID
 	 *
-	 * @access	public
-	 * @return	integer
+	 * @return	int
 	 */
-	function insert_id()
+	public function insert_id()
 	{
 		return @cubrid_insert_id($this->conn_id);
 	}
@@ -386,52 +329,20 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 * "Count All" query
-	 *
-	 * Generates a platform-specific query string that counts all records in
-	 * the specified table
-	 *
-	 * @access	public
-	 * @param	string
-	 * @return	string
-	 */
-	function count_all($table = '')
-	{
-		if ($table == '')
-		{
-			return 0;
-		}
-		
-		$query = $this->query($this->_count_string . $this->_protect_identifiers('numrows') . " FROM " . $this->_protect_identifiers($table, TRUE, NULL, FALSE));
-
-		if ($query->num_rows() == 0)
-		{
-			return 0;
-		}
-
-		$row = $query->row();
-		$this->_reset_select();
-		return (int) $row->numrows;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
 	 * List table query
 	 *
 	 * Generates a platform-specific query string so that the table names can be fetched
 	 *
-	 * @access	private
-	 * @param	boolean
+	 * @param	bool
 	 * @return	string
 	 */
-	function _list_tables($prefix_limit = FALSE)
+	protected function _list_tables($prefix_limit = FALSE)
 	{
-		$sql = "SHOW TABLES";
+		$sql = 'SHOW TABLES';
 
-		if ($prefix_limit !== FALSE AND $this->dbprefix != '')
+		if ($prefix_limit !== FALSE && $this->dbprefix !== '')
 		{
-			$sql .= " LIKE '".$this->escape_like_str($this->dbprefix)."%'";
+			return $sql." LIKE '".$this->escape_like_str($this->dbprefix)."%'";
 		}
 
 		return $sql;
@@ -444,13 +355,12 @@
 	 *
 	 * Generates a platform-specific query string so that the column names can be fetched
 	 *
-	 * @access	public
 	 * @param	string	the table name
 	 * @return	string
 	 */
-	function _list_columns($table = '')
+	protected function _list_columns($table = '')
 	{
-		return "SHOW COLUMNS FROM ".$this->_protect_identifiers($table, TRUE, NULL, FALSE);
+		return 'SHOW COLUMNS FROM '.$this->protect_identifiers($table, TRUE, NULL, FALSE);
 	}
 
 	// --------------------------------------------------------------------
@@ -460,300 +370,68 @@
 	 *
 	 * Generates a platform-specific query so that the column data can be retrieved
 	 *
-	 * @access	public
 	 * @param	string	the table name
-	 * @return	object
-	 */
-	function _field_data($table)
-	{
-		return "SELECT * FROM ".$table." LIMIT 1";
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * The error message string
-	 *
-	 * @access	private
 	 * @return	string
 	 */
-	function _error_message()
+	protected function _field_data($table)
 	{
-		return cubrid_error($this->conn_id);
+		return 'SELECT * FROM '.$table.' LIMIT 1';
 	}
 
 	// --------------------------------------------------------------------
 
 	/**
-	 * The error message number
+	 * Error
 	 *
-	 * @access	private
-	 * @return	integer
+	 * Returns an array containing code and message of the last
+	 * database error that has occured.
+	 *
+	 * @return	array
 	 */
-	function _error_number()
+	public function error()
 	{
-		return cubrid_errno($this->conn_id);
+		return array('code' => cubrid_errno($this->conn_id), 'message' => cubrid_error($this->conn_id));
 	}
 
 	// --------------------------------------------------------------------
 
 	/**
-	 * Escape the SQL Identifiers
-	 *
-	 * This function escapes column and table names
-	 *
-	 * @access	private
-	 * @param	string
-	 * @return	string
-	 */
-	function _escape_identifiers($item)
-	{
-		if ($this->_escape_char == '')
-		{
-			return $item;
-		}
-
-		foreach ($this->_reserved_identifiers as $id)
-		{
-			if (strpos($item, '.'.$id) !== FALSE)
-			{
-				$str = $this->_escape_char. str_replace('.', $this->_escape_char.'.', $item);
-
-				// remove duplicates if the user already included the escape
-				return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str);
-			}
-		}
-
-		if (strpos($item, '.') !== FALSE)
-		{
-			$str = $this->_escape_char.str_replace('.', $this->_escape_char.'.'.$this->_escape_char, $item).$this->_escape_char;
-		}
-		else
-		{
-			$str = $this->_escape_char.$item.$this->_escape_char;
-		}
-
-		// remove duplicates if the user already included the escape
-		return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str);
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * From Tables
-	 *
-	 * This function implicitly groups FROM tables so there is no confusion
-	 * about operator precedence in harmony with SQL standards
-	 *
-	 * @access	public
-	 * @param	type
-	 * @return	type
-	 */
-	function _from_tables($tables)
-	{
-		if ( ! is_array($tables))
-		{
-			$tables = array($tables);
-		}
-
-		return '('.implode(', ', $tables).')';
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Insert statement
-	 *
-	 * Generates a platform-specific insert string from the supplied data
-	 *
-	 * @access	public
-	 * @param	string	the table name
-	 * @param	array	the insert keys
-	 * @param	array	the insert values
-	 * @return	string
-	 */
-	function _insert($table, $keys, $values)
-	{
-		return "INSERT INTO ".$table." (\"".implode('", "', $keys)."\") VALUES (".implode(', ', $values).")";
-	}
-
-	// --------------------------------------------------------------------
-
-
-	/**
-	 * Replace statement
-	 *
-	 * Generates a platform-specific replace string from the supplied data
-	 *
-	 * @access	public
-	 * @param	string	the table name
-	 * @param	array	the insert keys
-	 * @param	array	the insert values
-	 * @return	string
-	 */
-	function _replace($table, $keys, $values)
-	{
-		return "REPLACE INTO ".$table." (\"".implode('", "', $keys)."\") VALUES (".implode(', ', $values).")";
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Insert_batch statement
-	 *
-	 * Generates a platform-specific insert string from the supplied data
-	 *
-	 * @access	public
-	 * @param	string	the table name
-	 * @param	array	the insert keys
-	 * @param	array	the insert values
-	 * @return	string
-	 */
-	function _insert_batch($table, $keys, $values)
-	{
-		return "INSERT INTO ".$table." (\"".implode('", "', $keys)."\") VALUES ".implode(', ', $values);
-	}
-
-	// --------------------------------------------------------------------
-
-
-	/**
-	 * Update statement
-	 *
-	 * Generates a platform-specific update string from the supplied data
-	 *
-	 * @access	public
-	 * @param	string	the table name
-	 * @param	array	the update data
-	 * @param	array	the where clause
-	 * @param	array	the orderby clause
-	 * @param	array	the limit clause
-	 * @return	string
-	 */
-	function _update($table, $values, $where, $orderby = array(), $limit = FALSE)
-	{
-		foreach ($values as $key => $val)
-		{
-			$valstr[] = sprintf('"%s" = %s', $key, $val);
-		}
-
-		$limit = ( ! $limit) ? '' : ' LIMIT '.$limit;
-
-		$orderby = (count($orderby) >= 1)?' ORDER BY '.implode(", ", $orderby):'';
-
-		$sql = "UPDATE ".$table." SET ".implode(', ', $valstr);
-
-		$sql .= ($where != '' AND count($where) >=1) ? " WHERE ".implode(" ", $where) : '';
-
-		$sql .= $orderby.$limit;
-
-		return $sql;
-	}
-
-	// --------------------------------------------------------------------
-
-
-	/**
 	 * Update_Batch statement
 	 *
 	 * Generates a platform-specific batch update string from the supplied data
 	 *
-	 * @access	public
 	 * @param	string	the table name
 	 * @param	array	the update data
 	 * @param	array	the where clause
 	 * @return	string
 	 */
-	function _update_batch($table, $values, $index, $where = NULL)
+	protected function _update_batch($table, $values, $index, $where = NULL)
 	{
 		$ids = array();
-		$where = ($where != '' AND count($where) >=1) ? implode(" ", $where).' AND ' : '';
-
 		foreach ($values as $key => $val)
 		{
 			$ids[] = $val[$index];
 
 			foreach (array_keys($val) as $field)
 			{
-				if ($field != $index)
+				if ($field !== $index)
 				{
 					$final[$field][] = 'WHEN '.$index.' = '.$val[$index].' THEN '.$val[$field];
 				}
 			}
 		}
 
-		$sql = "UPDATE ".$table." SET ";
 		$cases = '';
-
 		foreach ($final as $k => $v)
 		{
-			$cases .= $k.' = CASE '."\n";
-			foreach ($v as $row)
-			{
-				$cases .= $row."\n";
-			}
-
-			$cases .= 'ELSE '.$k.' END, ';
+			$cases .= $k." = CASE \n"
+				.implode("\n", $v)
+				.'ELSE '.$k.' END, ';
 		}
 
-		$sql .= substr($cases, 0, -2);
-
-		$sql .= ' WHERE '.$where.$index.' IN ('.implode(',', $ids).')';
-
-		return $sql;
-	}
-
-	// --------------------------------------------------------------------
-
-
-	/**
-	 * Truncate statement
-	 *
-	 * Generates a platform-specific truncate string from the supplied data
-	 * If the database does not support the truncate() command
-	 * This function maps to "DELETE FROM table"
-	 *
-	 * @access	public
-	 * @param	string	the table name
-	 * @return	string
-	 */
-	function _truncate($table)
-	{
-		return "TRUNCATE ".$table;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Delete statement
-	 *
-	 * Generates a platform-specific delete string from the supplied data
-	 *
-	 * @access	public
-	 * @param	string	the table name
-	 * @param	array	the where clause
-	 * @param	string	the limit clause
-	 * @return	string
-	 */
-	function _delete($table, $where = array(), $like = array(), $limit = FALSE)
-	{
-		$conditions = '';
-
-		if (count($where) > 0 OR count($like) > 0)
-		{
-			$conditions = "\nWHERE ";
-			$conditions .= implode("\n", $this->ar_where);
-
-			if (count($where) > 0 && count($like) > 0)
-			{
-				$conditions .= " AND ";
-			}
-			$conditions .= implode("\n", $like);
-		}
-
-		$limit = ( ! $limit) ? '' : ' LIMIT '.$limit;
-
-		return "DELETE FROM ".$table.$conditions.$limit;
+		return 'UPDATE '.$table.' SET '.substr($cases, 0, -2)
+			.' WHERE '.(($where !== '' && count($where) > 0) ? implode(' ', $where).' AND ' : '')
+			.$index.' IN ('.implode(',', $ids).')';
 	}
 
 	// --------------------------------------------------------------------
@@ -763,24 +441,14 @@
 	 *
 	 * Generates a platform-specific LIMIT clause
 	 *
-	 * @access	public
 	 * @param	string	the sql query string
-	 * @param	integer	the number of rows to limit the query to
-	 * @param	integer	the offset value
+	 * @param	int	the number of rows to limit the query to
+	 * @param	int	the offset value
 	 * @return	string
 	 */
-	function _limit($sql, $limit, $offset)
+	protected function _limit($sql, $limit, $offset)
 	{
-		if ($offset == 0)
-		{
-			$offset = '';
-		}
-		else
-		{
-			$offset .= ", ";
-		}
-
-		return $sql."LIMIT ".$offset.$limit;
+		return $sql.'LIMIT '.($offset == 0 ? '' : $offset.', ').$limit;
 	}
 
 	// --------------------------------------------------------------------
@@ -788,17 +456,14 @@
 	/**
 	 * Close DB Connection
 	 *
-	 * @access	public
-	 * @param	resource
 	 * @return	void
 	 */
-	function _close($conn_id)
+	protected function _close()
 	{
-		@cubrid_close($conn_id);
+		@cubrid_close($this->conn_id);
 	}
 
 }
 
-
 /* End of file cubrid_driver.php */
 /* Location: ./system/database/drivers/cubrid/cubrid_driver.php */
\ No newline at end of file
diff --git a/system/database/drivers/cubrid/cubrid_forge.php b/system/database/drivers/cubrid/cubrid_forge.php
index 85e7400..d328aa2 100644
--- a/system/database/drivers/cubrid/cubrid_forge.php
+++ b/system/database/drivers/cubrid/cubrid_forge.php
@@ -1,13 +1,13 @@
-<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
- * 
+ *
  * Licensed under the Open Software License version 3.0
- * 
+ *
  * This source file is subject to the Open Software License (OSL 3.0) that is
  * bundled with this package in the files license.txt / license.rst.  It is
  * also available through the world wide web at this URL:
@@ -21,12 +21,10 @@
  * @copyright	Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/)
  * @license		http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
  * @link		http://codeigniter.com
- * @since		Version 1.0
+ * @since		Version 2.1
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * CUBRID Forge Class
  *
@@ -36,86 +34,54 @@
  */
 class CI_DB_cubrid_forge extends CI_DB_forge {
 
-	/**
-	 * Create database
-	 *
-	 * @access	private
-	 * @param	string	the database name
-	 * @return	bool
-	 */
-	function _create_database($name)
-	{
-		// CUBRID does not allow to create a database in SQL. The GUI tools
-		// have to be used for this purpose.
-		return FALSE;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Drop database
-	 *
-	 * @access	private
-	 * @param	string	the database name
-	 * @return	bool
-	 */
-	function _drop_database($name)
-	{
-		// CUBRID does not allow to drop a database in SQL. The GUI tools
-		// have to be used for this purpose.
-		return FALSE;
-	}
-
-	// --------------------------------------------------------------------
+	protected $_create_database	= FALSE;
+	protected $_drop_database	= FALSE;
 
 	/**
 	 * Process Fields
 	 *
-	 * @access	private
 	 * @param	mixed	the fields
 	 * @return	string
 	 */
-	function _process_fields($fields)
+	protected function _process_fields($fields)
 	{
 		$current_field_count = 0;
 		$sql = '';
 
-		foreach ($fields as $field=>$attributes)
+		foreach ($fields as $field => $attributes)
 		{
 			// Numeric field names aren't allowed in databases, so if the key is
 			// numeric, we know it was assigned by PHP and the developer manually
 			// entered the field information, so we'll simply add it to the list
 			if (is_numeric($field))
 			{
-				$sql .= "\n\t$attributes";
+				$sql .= "\n\t".$attributes;
 			}
 			else
 			{
 				$attributes = array_change_key_case($attributes, CASE_UPPER);
 
-				$sql .= "\n\t\"" . $this->db->_protect_identifiers($field) . "\"";
+				$sql .= "\n\t".$this->db->escape_identifiers($field);
 
-				if (array_key_exists('NAME', $attributes))
-				{
-					$sql .= ' '.$this->db->_protect_identifiers($attributes['NAME']).' ';
-				}
+				empty($attributes['NAME']) OR $sql .= ' '.$this->db->escape_identifiers($attributes['NAME']).' ';
 
-				if (array_key_exists('TYPE', $attributes))
+				if ( ! empty($attributes['TYPE']))
 				{
 					$sql .= ' '.$attributes['TYPE'];
 
-					if (array_key_exists('CONSTRAINT', $attributes))
+					if ( ! empty($attributes['CONSTRAINT']))
 					{
-						switch ($attributes['TYPE'])
+						switch (strtolower($attributes['TYPE']))
 						{
 							case 'decimal':
 							case 'float':
 							case 'numeric':
 								$sql .= '('.implode(',', $attributes['CONSTRAINT']).')';
 								break;
-							case 'enum': 	// As of version 8.4.0 CUBRID does not support
-											// enum data type.
-											break;
+							case 'enum':
+								// Will be supported in the future as part a part of
+								// MySQL compatibility features.
+								break;
 							case 'set':
 								$sql .= '("'.implode('","', $attributes['CONSTRAINT']).'")';
 								break;
@@ -125,33 +91,29 @@
 					}
 				}
 
-				if (array_key_exists('UNSIGNED', $attributes) && $attributes['UNSIGNED'] === TRUE)
+			/* As of version 8.4.1 CUBRID does not support UNSIGNED INTEGER data type.
+			 * Will be supported in the next release as a part of MySQL Compatibility.
+			 *
+				if (isset($attributes['UNSIGNED']) && $attributes['UNSIGNED'] === TRUE)
 				{
-					//$sql .= ' UNSIGNED';
-					// As of version 8.4.0 CUBRID does not support UNSIGNED INTEGER data type.
-					// Will be supported in the next release as a part of MySQL Compatibility.
+					$sql .= ' UNSIGNED';
+				}
+			 */
+
+				if (isset($attributes['DEFAULT']))
+				{
+					$sql .= " DEFAULT '".$attributes['DEFAULT']."'";
 				}
 
-				if (array_key_exists('DEFAULT', $attributes))
-				{
-					$sql .= ' DEFAULT \''.$attributes['DEFAULT'].'\'';
-				}
+				$sql .= ( ! empty($attributes['NULL']) && $attributes['NULL'] === TRUE)
+					? ' NULL' : ' NOT NULL';
 
-				if (array_key_exists('NULL', $attributes) && $attributes['NULL'] === TRUE)
-				{
-					$sql .= ' NULL';
-				}
-				else
-				{
-					$sql .= ' NOT NULL';
-				}
-
-				if (array_key_exists('AUTO_INCREMENT', $attributes) && $attributes['AUTO_INCREMENT'] === TRUE)
+				if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE)
 				{
 					$sql .= ' AUTO_INCREMENT';
 				}
 
-				if (array_key_exists('UNIQUE', $attributes) && $attributes['UNIQUE'] === TRUE)
+				if ( ! empty($attributes['UNIQUE']) && $attributes['UNIQUE'] === TRUE)
 				{
 					$sql .= ' UNIQUE';
 				}
@@ -172,36 +134,31 @@
 	/**
 	 * Create Table
 	 *
-	 * @access	private
 	 * @param	string	the table name
 	 * @param	mixed	the fields
 	 * @param	mixed	primary key(s)
 	 * @param	mixed	key(s)
-	 * @param	boolean	should 'IF NOT EXISTS' be added to the SQL
+	 * @param	bool	should 'IF NOT EXISTS' be added to the SQL
 	 * @return	bool
 	 */
-	function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists)
+	protected function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists)
 	{
 		$sql = 'CREATE TABLE ';
 
+		/* As of version 8.4.1 CUBRID does not support this SQL syntax.
 		if ($if_not_exists === TRUE)
 		{
-			//$sql .= 'IF NOT EXISTS ';
-			// As of version 8.4.0 CUBRID does not support this SQL syntax.
+			$sql .= 'IF NOT EXISTS ';
 		}
+		*/
 
-		$sql .= $this->db->_escape_identifiers($table)." (";
-
-		$sql .= $this->_process_fields($fields);
+		$sql .= $this->db->escape_identifiers($table).' ('.$this->_process_fields($fields);
 
 		// If there is a PK defined
 		if (count($primary_keys) > 0)
 		{
-			$key_name = "pk_" . $table . "_" .
-				$this->db->_protect_identifiers(implode('_', $primary_keys));
-			
-			$primary_keys = $this->db->_protect_identifiers($primary_keys);
-			$sql .= ",\n\tCONSTRAINT " . $key_name . " PRIMARY KEY(" . implode(', ', $primary_keys) . ")";
+			$key_name = $this->db->escape_identifiers('pk_'.$table.'_'.implode('_', $primary_keys));
+			$sql .= ",\n\tCONSTRAINT ".$key_name.' PRIMARY KEY('.implode(', ', $this->db->escape_identifiers($primary_keys)).')';
 		}
 
 		if (is_array($keys) && count($keys) > 0)
@@ -210,35 +167,20 @@
 			{
 				if (is_array($key))
 				{
-					$key_name = $this->db->_protect_identifiers(implode('_', $key));
-					$key = $this->db->_protect_identifiers($key);
+					$key_name = $this->db->escape_identifiers('idx_'.$table.implode('_', $key));
+					$key = $this->db->escape_identifiers($key);
 				}
 				else
 				{
-					$key_name = $this->db->_protect_identifiers($key);
+					$key_name = $this->db->escape_identifiers('idx_'.$table.$key);
 					$key = array($key_name);
 				}
-				
-				$sql .= ",\n\tKEY \"{$key_name}\" (" . implode(', ', $key) . ")";
+
+				$sql .= ",\n\tKEY ".$key_name.' ('.implode(', ', $key).')';
 			}
 		}
 
-		$sql .= "\n);";
-
-		return $sql;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Drop Table
-	 *
-	 * @access	private
-	 * @return	string
-	 */
-	function _drop_table($table)
-	{
-		return "DROP TABLE IF EXISTS ".$this->db->_escape_identifiers($table);
+		return $sql."\n);";
 	}
 
 	// --------------------------------------------------------------------
@@ -249,49 +191,24 @@
 	 * Generates a platform-specific query so that a table can be altered
 	 * Called by add_column(), drop_column(), and column_alter(),
 	 *
-	 * @access	private
 	 * @param	string	the ALTER type (ADD, DROP, CHANGE)
 	 * @param	string	the column name
 	 * @param	array	fields
 	 * @param	string	the field after which we should add the new field
-	 * @return	object
-	 */
-	function _alter_table($alter_type, $table, $fields, $after_field = '')
-	{
-		$sql = 'ALTER TABLE '.$this->db->_protect_identifiers($table)." $alter_type ";
-
-		// DROP has everything it needs now.
-		if ($alter_type == 'DROP')
-		{
-			return $sql.$this->db->_protect_identifiers($fields);
-		}
-
-		$sql .= $this->_process_fields($fields);
-
-		if ($after_field != '')
-		{
-			$sql .= ' AFTER ' . $this->db->_protect_identifiers($after_field);
-		}
-
-		return $sql;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Rename a table
-	 *
-	 * Generates a platform-specific query so that a table can be renamed
-	 *
-	 * @access	private
-	 * @param	string	the old table name
-	 * @param	string	the new table name
 	 * @return	string
 	 */
-	function _rename_table($table_name, $new_table_name)
+	protected function _alter_table($alter_type, $table, $fields, $after_field = '')
 	{
-		$sql = 'RENAME TABLE '.$this->db->_protect_identifiers($table_name)." AS ".$this->db->_protect_identifiers($new_table_name);
-		return $sql;
+		$sql = 'ALTER TABLE '.$this->db->escape_identifiers($table).' '.$alter_type.' ';
+
+		// DROP has everything it needs now.
+		if ($alter_type === 'DROP')
+		{
+			return $sql.$this->db->escape_identifiers($fields);
+		}
+
+		return $sql.$this->_process_fields($fields)
+			.($after_field !== '' ? ' AFTER '.$this->db->escape_identifiers($after_field) : '');
 	}
 
 }
diff --git a/system/database/drivers/cubrid/cubrid_result.php b/system/database/drivers/cubrid/cubrid_result.php
index 4c0fede..3eb9f7e 100644
--- a/system/database/drivers/cubrid/cubrid_result.php
+++ b/system/database/drivers/cubrid/cubrid_result.php
@@ -1,13 +1,13 @@
-<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
- * 
+ *
  * Licensed under the Open Software License version 3.0
- * 
+ *
  * This source file is subject to the Open Software License (OSL 3.0) that is
  * bundled with this package in the files license.txt / license.rst.  It is
  * also available through the world wide web at this URL:
@@ -21,12 +21,10 @@
  * @copyright	Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/)
  * @license		http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
  * @link		http://codeigniter.com
- * @since		Version 2.0.2
+ * @since		Version 2.1
  * @filesource
  */
 
-// --------------------------------------------------------------------
-
 /**
  * CUBRID Result Class
  *
@@ -41,10 +39,9 @@
 	/**
 	 * Number of rows in the result set
 	 *
-	 * @access	public
-	 * @return	integer
+	 * @return	int
 	 */
-	function num_rows()
+	public function num_rows()
 	{
 		return @cubrid_num_rows($this->result_id);
 	}
@@ -54,10 +51,9 @@
 	/**
 	 * Number of fields in the result set
 	 *
-	 * @access	public
-	 * @return	integer
+	 * @return	int
 	 */
-	function num_fields()
+	public function num_fields()
 	{
 		return @cubrid_num_fields($this->result_id);
 	}
@@ -69,10 +65,9 @@
 	 *
 	 * Generates an array of column names
 	 *
-	 * @access	public
 	 * @return	array
 	 */
-	function list_fields()
+	public function list_fields()
 	{
 		return cubrid_column_names($this->result_id);
 	}
@@ -84,59 +79,25 @@
 	 *
 	 * Generates an array of objects containing field meta-data
 	 *
-	 * @access	public
 	 * @return	array
 	 */
-	function field_data()
+	public function field_data()
 	{
 		$retval = array();
-
-		$tablePrimaryKeys = array();
+		$i = 0;
 
 		while ($field = cubrid_fetch_field($this->result_id))
 		{
-			$F				= new stdClass();
-			$F->name		= $field->name;
-			$F->type		= $field->type;
-			$F->default		= $field->def;
-			$F->max_length	= $field->max_length;
-
-			// At this moment primary_key property is not returned when
-			// cubrid_fetch_field is called. The following code will
-			// provide a patch for it. primary_key property will be added
-			// in the next release.
-
-			// TODO: later version of CUBRID will provide primary_key
-			// property.
-			// When PK is defined in CUBRID, an index is automatically
-			// created in the db_index system table in the form of
-			// pk_tblname_fieldname. So the following will count how many
-			// columns are there which satisfy this format.
-			// The query will search for exact single columns, thus
-			// compound PK is not supported.
-			$res = cubrid_query($this->conn_id,
-				"SELECT COUNT(*) FROM db_index WHERE class_name = '" . $field->table .
-				"' AND is_primary_key = 'YES' AND index_name = 'pk_" .
-				$field->table . "_" . $field->name . "'"
-			);
-
-			if ($res)
-			{
-				$row = cubrid_fetch_array($res, CUBRID_NUM);
-				$F->primary_key = ($row[0] > 0 ? 1 : null);
-			}
-			else
-			{
-				$F->primary_key = null;
-			}
-
-			if (is_resource($res))
-			{
-				cubrid_close_request($res);
-				$this->result_id = FALSE;
-			}
-
-			$retval[] = $F;
+			$retval[$i]			= new stdClass();
+			$retval[$i]->name		= $field->name;
+			// CUBRID returns type as e.g. varchar(100),
+			// so we need to remove all digits and brackets.
+			$retval[$i]->type		= preg_replace('/[\d()]/', '', $field->type);
+			$retval[$i]->default		= $field->def;
+			// Use CUBRID's native API to obtain column's max_length,
+			// otherwise $field->max_length has incorrect info
+			$retval[$i]->max_length		= cubrid_field_len($this->result_id, $i);
+			$retval[$i++]->primary_key	= $field->primary_key;
 		}
 
 		return $retval;
@@ -147,13 +108,12 @@
 	/**
 	 * Free the result
 	 *
-	 * @return	null
+	 * @return	void
 	 */
-	function free_result()
+	public function free_result()
 	{
-		if(is_resource($this->result_id) ||
-			get_resource_type($this->result_id) == "Unknown" &&
-			preg_match('/Resource id #/', strval($this->result_id)))
+		if (is_resource($this->result_id) OR
+			(get_resource_type($this->result_id) === 'Unknown' && preg_match('/Resource id #/', strval($this->result_id))))
 		{
 			cubrid_close_request($this->result_id);
 			$this->result_id = FALSE;
@@ -169,10 +129,9 @@
 	 * this internally before fetching results to make sure the
 	 * result set starts at zero
 	 *
-	 * @access	private
-	 * @return	array
+	 * @return	bool
 	 */
-	function _data_seek($n = 0)
+	protected function _data_seek($n = 0)
 	{
 		return cubrid_data_seek($this->result_id, $n);
 	}
@@ -184,10 +143,9 @@
 	 *
 	 * Returns the result set as an array
 	 *
-	 * @access	private
 	 * @return	array
 	 */
-	function _fetch_assoc()
+	protected function _fetch_assoc()
 	{
 		return cubrid_fetch_assoc($this->result_id);
 	}
@@ -199,16 +157,14 @@
 	 *
 	 * Returns the result set as an object
 	 *
-	 * @access	private
 	 * @return	object
 	 */
-	function _fetch_object()
+	protected function _fetch_object()
 	{
 		return cubrid_fetch_object($this->result_id);
 	}
 
 }
 
-
 /* End of file cubrid_result.php */
 /* Location: ./system/database/drivers/cubrid/cubrid_result.php */
\ No newline at end of file
diff --git a/system/database/drivers/cubrid/cubrid_utility.php b/system/database/drivers/cubrid/cubrid_utility.php
index 750c0d8..ea8feb4 100644
--- a/system/database/drivers/cubrid/cubrid_utility.php
+++ b/system/database/drivers/cubrid/cubrid_utility.php
@@ -1,13 +1,13 @@
-<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
- * 
+ *
  * Licensed under the Open Software License version 3.0
- * 
+ *
  * This source file is subject to the Open Software License (OSL 3.0) that is
  * bundled with this package in the files license.txt / license.rst.  It is
  * also available through the world wide web at this URL:
@@ -21,12 +21,10 @@
  * @copyright	Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/)
  * @license		http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
  * @link		http://codeigniter.com
- * @since		Version 1.0
+ * @since		Version 2.1
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * CUBRID Utility Class
  *
@@ -39,75 +37,27 @@
 	/**
 	 * List databases
 	 *
-	 * @access	private
 	 * @return	array
 	 */
-	function _list_databases()
+	public function list_databases()
 	{
-		// CUBRID does not allow to see the list of all databases on the
-		// server. It is the way its architecture is designed. Every
-		// database is independent and isolated.
-		// For this reason we can return only the name of the currect
-		// connected database.
-		if ($this->conn_id)
+		if (isset($this->db->data_cache['db_names']))
 		{
-			return "SELECT '" . $this->database . "'";
+			return $this->db->data_cache['db_names'];
 		}
-		else
-		{
-			return FALSE;
-		}
+
+		return $this->db->data_cache['db_names'] = cubrid_list_dbs($this->db->conn_id);
 	}
 
 	// --------------------------------------------------------------------
 
 	/**
-	 * Optimize table query
-	 *
-	 * Generates a platform-specific query so that a table can be optimized
-	 *
-	 * @access	private
-	 * @param	string	the table name
-	 * @return	object
-	 * @link 	http://www.cubrid.org/manual/840/en/Optimize%20Database
-	 */
-	function _optimize_table($table)
-	{
-		// No SQL based support in CUBRID as of version 8.4.0. Database or
-		// table optimization can be performed using CUBRID Manager
-		// database administration tool. See the link above for more info.
-		return FALSE;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Repair table query
-	 *
-	 * Generates a platform-specific query so that a table can be repaired
-	 *
-	 * @access	private
-	 * @param	string	the table name
-	 * @return	object
-	 * @link 	http://www.cubrid.org/manual/840/en/Checking%20Database%20Consistency
-	 */
-	function _repair_table($table)
-	{
-		// Not supported in CUBRID as of version 8.4.0. Database or
-		// table consistency can be checked using CUBRID Manager
-		// database administration tool. See the link above for more info.
-		return FALSE;
-	}
-
-	// --------------------------------------------------------------------
-	/**
 	 * CUBRID Export
 	 *
-	 * @access	private
 	 * @param	array	Preferences
 	 * @return	mixed
 	 */
-	function _backup($params = array())
+	protected function _backup($params = array())
 	{
 		// No SQL based support in CUBRID as of version 8.4.0. Database or
 		// table backup can be performed using CUBRID Manager
diff --git a/application/errors/index.html b/system/database/drivers/interbase/index.html
similarity index 100%
copy from application/errors/index.html
copy to system/database/drivers/interbase/index.html
diff --git a/system/database/drivers/interbase/interbase_driver.php b/system/database/drivers/interbase/interbase_driver.php
new file mode 100644
index 0000000..5a03607
--- /dev/null
+++ b/system/database/drivers/interbase/interbase_driver.php
@@ -0,0 +1,450 @@
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.2.4 or newer
+ *
+ * NOTICE OF LICENSE
+ *
+ * Licensed under the Open Software License version 3.0
+ *
+ * This source file is subject to the Open Software License (OSL 3.0) that is
+ * bundled with this package in the files license.txt / license.rst.  It is
+ * also available through the world wide web at this URL:
+ * http://opensource.org/licenses/OSL-3.0
+ * If you did not receive a copy of the license and are unable to obtain it
+ * through the world wide web, please send an email to
+ * licensing@ellislab.com so we can send you a copy immediately.
+ *
+ * @package		CodeIgniter
+ * @author		EllisLab Dev Team
+ * @copyright	Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/)
+ * @license		http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
+ * @link		http://codeigniter.com
+ * @since		Version 3.0
+ * @filesource
+ */
+
+/**
+ * Firebird/Interbase Database Adapter Class
+ *
+ * Note: _DB is an extender class that the app controller
+ * creates dynamically based on whether the query builder
+ * class is being used or not.
+ *
+ * @package		CodeIgniter
+ * @subpackage	Drivers
+ * @category	Database
+ * @author		EllisLab Dev Team
+ * @link		http://codeigniter.com/user_guide/database/
+ */
+class CI_DB_interbase_driver extends CI_DB {
+
+	public $dbdriver = 'interbase';
+
+	// The character used to escape with
+	protected $_escape_char = '"';
+
+	// clause and character used for LIKE escape sequences
+	protected $_like_escape_str = " ESCAPE '%s' ";
+	protected $_like_escape_chr = '!';
+
+	/**
+	 * The syntax to count rows is slightly different across different
+	 * database engines, so this string appears in each driver and is
+	 * used for the count_all() and count_all_results() functions.
+	 */
+	protected $_count_string	= 'SELECT COUNT(*) AS ';
+	protected $_random_keyword	= ' Random()'; // database specific random keyword
+
+	// Keeps track of the resource for the current transaction
+	protected $trans;
+
+	/**
+	 * Non-persistent database connection
+	 *
+	 * @return	resource
+	 */
+	public function db_connect()
+	{
+		return @ibase_connect($this->hostname.':'.$this->database, $this->username, $this->password, $this->char_set);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Persistent database connection
+	 *
+	 * @return	resource
+	 */
+	public function db_pconnect()
+	{
+		return @ibase_pconnect($this->hostname.':'.$this->database, $this->username, $this->password, $this->char_set);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Database version number
+	 *
+	 * @return	string
+	 */
+	public function version()
+	{
+		if (isset($this->data_cache['version']))
+		{
+			return $this->data_cache['version'];
+		}
+
+		if (($service = ibase_service_attach($this->hostname, $this->username, $this->password)))
+		{
+			$this->data_cache['version'] = ibase_server_info($service, IBASE_SVC_SERVER_VERSION);
+
+			// Don't keep the service open
+			ibase_service_detach($service);
+			return $this->data_cache['version'];
+		}
+
+		return FALSE;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Execute the query
+	 *
+	 * @param	string	an SQL query
+	 * @return	resource
+	 */
+	protected function _execute($sql)
+	{
+		return @ibase_query($this->conn_id, $sql);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Begin Transaction
+	 *
+	 * @return	bool
+	 */
+	public function trans_begin($test_mode = FALSE)
+	{
+		// When transactions are nested we only begin/commit/rollback the outermost ones
+		if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
+		{
+			return TRUE;
+		}
+
+		// Reset the transaction failure flag.
+		// If the $test_mode flag is set to TRUE transactions will be rolled back
+		// even if the queries produce a successful result.
+		$this->_trans_failure = ($test_mode === TRUE);
+
+		$this->trans = @ibase_trans($this->conn_id);
+
+		return TRUE;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Commit Transaction
+	 *
+	 * @return	bool
+	 */
+	public function trans_commit()
+	{
+		// When transactions are nested we only begin/commit/rollback the outermost ones
+		if ( ! $this->trans_enabled OR $this->_trans->depth > 0)
+		{
+			return TRUE;
+		}
+
+		return @ibase_commit($this->trans);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Rollback Transaction
+	 *
+	 * @return	bool
+	 */
+	public function trans_rollback()
+	{
+		// When transactions are nested we only begin/commit/rollback the outermost ones
+		if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
+		{
+			return TRUE;
+		}
+
+		return @ibase_rollback($this->trans);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Escape String
+	 *
+	 * @param	string
+	 * @param	bool	whether or not the string will be used in a LIKE condition
+	 * @return	string
+	 */
+	public function escape_str($str, $like = FALSE)
+	{
+		if (is_array($str))
+		{
+			foreach ($str as $key => $val)
+			{
+				$str[$key] = $this->escape_str($val, $like);
+			}
+
+			return $str;
+		}
+
+		// escape LIKE condition wildcards
+		if ($like === TRUE)
+		{
+			return str_replace(array($this->_like_escape_chr, '%', '_'),
+						array($this->_like_escape_chr.$this->_like_escape_chr, $this->_like_escape_chr.'%', $this->_like_escape_chr.'_'),
+						$str);
+		}
+
+		return $str;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Affected Rows
+	 *
+	 * @return	int
+	 */
+	public function affected_rows()
+	{
+		return @ibase_affected_rows($this->conn_id);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Insert ID
+	 *
+	 * @param	string	$generator_name
+	 * @param	int	$inc_by
+	 * @return	int
+	 */
+	public function insert_id($generator_name, $inc_by=0)
+	{
+		//If a generator hasn't been used before it will return 0
+		return ibase_gen_id('"'.$generator_name.'"', $inc_by);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * List table query
+	 *
+	 * Generates a platform-specific query string so that the table names can be fetched
+	 *
+	 * @param	bool
+	 * @return	string
+	 */
+	protected function _list_tables($prefix_limit = FALSE)
+	{
+		$sql = 'SELECT "RDB$RELATION_NAME" FROM "RDB$RELATIONS" WHERE "RDB$RELATION_NAME" NOT LIKE \'RDB$%\' AND "RDB$RELATION_NAME" NOT LIKE \'MON$%\'';
+
+		if ($prefix_limit !== FALSE && $this->dbprefix !== '')
+		{
+			return $sql.' AND "RDB$RELATION_NAME" LIKE \''.$this->escape_like_str($this->dbprefix)."%' ".sprintf($this->_like_escape_str, $this->_like_escape_chr);
+		}
+
+		return $sql;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Show column query
+	 *
+	 * Generates a platform-specific query string so that the column names can be fetched
+	 *
+	 * @param	string	the table name
+	 * @return	string
+	 */
+	protected function _list_columns($table = '')
+	{
+		return 'SELECT "RDB$FIELD_NAME" FROM "RDB$RELATION_FIELDS" WHERE "RDB$RELATION_NAME" = \''.$this->escape_str($table)."'";
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Field data query
+	 *
+	 * Generates a platform-specific query so that the column data can be retrieved
+	 *
+	 * @param	string	the table name
+	 * @return	string
+	 */
+	protected function _field_data($table)
+	{
+		// Need to find a more efficient way to do this
+		// but Interbase/Firebird seems to lack the
+		// limit clause
+		return 'SELECT * FROM '.$table;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Error
+	 *
+	 * Returns an array containing code and message of the last
+	 * database error that has occured.
+	 *
+	 * @return	array
+	 */
+	public function error()
+	{
+		return array('code' => ibase_errcode(), 'message' => ibase_errmsg());
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * From Tables
+	 *
+	 * This public function implicitly groups FROM tables so there is no confusion
+	 * about operator precedence in harmony with SQL standards
+	 *
+	 * @param	array
+	 * @return	string
+	 */
+	protected function _from_tables($tables)
+	{
+		return is_array($tables) ? implode(', ', $tables) : $tables;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Update statement
+	 *
+	 * Generates a platform-specific update string from the supplied data
+	 *
+	 * @param	string	the table name
+	 * @param	array	the update data
+	 * @param	array	the where clause
+	 * @param	array	the orderby clause
+	 * @param	array	the limit clause (ignored)
+	 * @param	array	the like clause
+	 * @return	string
+	 */
+	protected function _update($table, $values, $where, $orderby = array(), $limit = FALSE, $like = array())
+	{
+		foreach ($values as $key => $val)
+		{
+			$valstr[] = $key.' = '.$val;
+		}
+
+		$where = empty($where) ? '' : ' WHERE '.implode(' ', $where);
+
+		if ( ! empty($like))
+		{
+			$where .= ($where === '' ? ' WHERE ' : ' AND ').implode(' ', $like);
+		}
+
+		return 'UPDATE '.$table.' SET '.implode(', ', $valstr)
+			.$where
+			.(count($orderby) > 0 ? ' ORDER BY '.implode(', ', $orderby) : '');
+	}
+
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Truncate statement
+	 *
+	 * Generates a platform-specific truncate string from the supplied data
+	 *
+	 * If the database does not support the truncate() command,
+	 * then this method maps to 'DELETE FROM table'
+	 *
+	 * @param	string	the table name
+	 * @return	string
+	 */
+	protected function _truncate($table)
+	{
+		return 'DELETE FROM '.$table;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Delete statement
+	 *
+	 * Generates a platform-specific delete string from the supplied data
+	 *
+	 * @param	string	the table name
+	 * @param	array	the where clause
+	 * @param	array	the like clause
+	 * @param	string	the limit clause (ignored)
+	 * @return	string
+	 */
+	protected function _delete($table, $where = array(), $like = array(), $limit = FALSE)
+	{
+		$conditions = array();
+
+		empty($where) OR $conditions[] = implode(' ', $where);
+		empty($like) OR $conditions[] = implode(' ', $like);
+
+		return 'DELETE FROM '.$table.(count($conditions) > 0 ? ' WHERE '.implode(' AND ', $conditions) : '');
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Limit string
+	 *
+	 * Generates a platform-specific LIMIT clause
+	 *
+	 * @param	string	the sql query string
+	 * @param	int	the number of rows to limit the query to
+	 * @param	int	the offset value
+	 * @return	string
+	 */
+	protected function _limit($sql, $limit, $offset)
+	{
+		// Limit clause depends on if Interbase or Firebird
+		if (stripos($this->version(), 'firebird') !== FALSE)
+		{
+			$select = 'FIRST '. (int) $limit
+				.($offset > 0 ? ' SKIP '. (int) $offset : '');
+		}
+		else
+		{
+			$select = 'ROWS '
+				.($offset > 0 ? (int) $offset.' TO '.($limit + $offset) : (int) $limit);
+		}
+
+		return preg_replace('`SELECT`i', 'SELECT '.$select, $sql);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Close DB Connection
+	 *
+	 * @return	void
+	 */
+	protected function _close()
+	{
+		@ibase_close($this->conn_id);
+	}
+
+}
+
+/* End of file interbase_driver.php */
+/* Location: ./system/database/drivers/interbase/interbase_driver.php */
\ No newline at end of file
diff --git a/system/database/drivers/interbase/interbase_forge.php b/system/database/drivers/interbase/interbase_forge.php
new file mode 100644
index 0000000..d1b006e
--- /dev/null
+++ b/system/database/drivers/interbase/interbase_forge.php
@@ -0,0 +1,194 @@
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.2.4 or newer
+ *
+ * NOTICE OF LICENSE
+ *
+ * Licensed under the Open Software License version 3.0
+ *
+ * This source file is subject to the Open Software License (OSL 3.0) that is
+ * bundled with this package in the files license.txt / license.rst.  It is
+ * also available through the world wide web at this URL:
+ * http://opensource.org/licenses/OSL-3.0
+ * If you did not receive a copy of the license and are unable to obtain it
+ * through the world wide web, please send an email to
+ * licensing@ellislab.com so we can send you a copy immediately.
+ *
+ * @package		CodeIgniter
+ * @author		EllisLab Dev Team
+ * @copyright	Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/)
+ * @license		http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
+ * @link		http://codeigniter.com
+ * @since		Version 3.0
+ * @filesource
+ */
+
+/**
+ * Interbase/Firebird Forge Class
+ *
+ * @category	Database
+ * @author		EllisLab Dev Team
+ * @link		http://codeigniter.com/user_guide/database/
+ */
+class CI_DB_interbase_forge extends CI_DB_forge {
+
+	protected $_drop_table	= 'DROP TABLE %s';
+
+	/**
+	 * Create database
+	 *
+	 * @param	string	the database name
+	 * @return	string
+	 */
+	public function create_database($db_name)
+	{
+		// Firebird databases are flat files, so a path is required
+
+		// Hostname is needed for remote access
+		empty($this->db->hostname) OR $db_name = $this->hostname.':'.$db_name;
+
+		return parent::create_database('"'.$db_name.'"');
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Drop database
+	 *
+	 * @param	string	the database name
+	 *		- not used in this driver, the current db is dropped
+	 * @return	bool
+	 */
+	public function drop_database($db_name = '')
+	{
+		if ( ! ibase_drop_db($this->conn_id))
+		{
+			return ($this->db->db_debug) ? $this->db->display_error('db_unable_to_drop') : FALSE;
+		}
+		elseif ( ! empty($this->db->data_cache['db_names']))
+		{
+			$key = array_search(strtolower($this->db->database), array_map('strtolower', $this->db->data_cache['db_names']), TRUE);
+			if ($key !== FALSE)
+			{
+				unset($this->db->data_cache['db_names'][$key]);
+			}
+		}
+
+		return TRUE;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Create Table
+	 *
+	 * @param	string	the table name
+	 * @param	array	the fields
+	 * @param	mixed	primary key(s)
+	 * @param	mixed	key(s)
+	 * @param	bool	should 'IF NOT EXISTS' be added to the SQL
+	 * @return	string
+	 */
+	protected function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists)
+	{
+		$sql = 'CREATE TABLE ';
+
+		$sql .= $this->db->escape_identifiers($table).'(';
+		$current_field_count = 0;
+
+		foreach ($fields as $field => $attributes)
+		{
+			// Numeric field names aren't allowed in databases, so if the key is
+			// numeric, we know it was assigned by PHP and the developer manually
+			// entered the field information, so we'll simply add it to the list
+			if (is_numeric($field))
+			{
+				$sql .= "\n\t".$attributes;
+			}
+			else
+			{
+				$attributes = array_change_key_case($attributes, CASE_UPPER);
+
+				$sql .= "\n\t".$this->db->escape_identifiers($field).' '.$attributes['TYPE'];
+
+				empty($attributes['CONSTRAINT']) OR $sql .= '('.$attributes['CONSTRAINT'].')';
+
+				if ( ! empty($attributes['UNSIGNED']) && $attributes['UNSIGNED'] === TRUE)
+				{
+					$sql .= ' UNSIGNED';
+				}
+
+				if (isset($attributes['DEFAULT']))
+				{
+					$sql .= " DEFAULT '".$attributes['DEFAULT']."'";
+				}
+
+				$sql .= ( ! empty($attributes['NULL']) && $attributes['NULL'] === TRUE)
+					? ' NULL' : ' NOT NULL';
+
+				if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE)
+				{
+					$sql .= ' AUTO_INCREMENT';
+				}
+			}
+
+			// don't add a comma on the end of the last field
+			if (++$current_field_count < count($fields))
+			{
+				$sql .= ',';
+			}
+		}
+
+		if (count($primary_keys) > 0)
+		{
+			$primary_keys = $this->db->escape_identifiers($primary_keys);
+			$sql .= ",\n\tPRIMARY KEY (".implode(', ', $primary_keys).')';
+		}
+
+		if (is_array($keys) && count($keys) > 0)
+		{
+			foreach ($keys as $key)
+			{
+				$key = is_array($key)
+					? $this->db->escape_identifiers($key)
+					: array($this->db->escape_identifiers($key));
+
+				$sql .= ",\n\tUNIQUE (".implode(', ', $key).')';
+			}
+		}
+
+		return $sql."\n)";
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Alter table query
+	 *
+	 * Generates a platform-specific query so that a table can be altered
+	 * Called by add_column(), drop_column(), and column_alter(),
+	 *
+	 * @param	string	the ALTER type (ADD, DROP, CHANGE)
+	 * @param	string	the column name
+	 * @param	string	the table name
+	 * @param	string	the column definition
+	 * @param	string	the default value
+	 * @param	bool	should 'NOT NULL' be added
+	 * @param	string	the field after which we should add the new field
+	 * @return	string
+	 */
+	protected function _alter_table($alter_type, $table, $column_name, $column_definition = '', $default_value = '', $null = '', $after_field = '')
+	{
+		return 'ALTER TABLE '.$this->db->escape_identifiers($table).' '.$alter_type.' '.$this->db->escape_identifiers($column_name)
+			.' '.$column_definition
+			.($default_value !== '' ? ' DEFAULT "'.$default_value.'"' : '')
+			.($null === NULL ? ' NULL' : ' NOT NULL')
+			.($after_field !== '' ? ' AFTER '.$this->db->escape_identifiers($after_field) : '');
+	}
+
+}
+
+/* End of file interbase_forge.php */
+/* Location: ./system/database/drivers/interbase/interbase_forge.php */
\ No newline at end of file
diff --git a/system/database/drivers/interbase/interbase_result.php b/system/database/drivers/interbase/interbase_result.php
new file mode 100644
index 0000000..5ddb6fa
--- /dev/null
+++ b/system/database/drivers/interbase/interbase_result.php
@@ -0,0 +1,260 @@
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.2.4 or newer
+ *
+ * NOTICE OF LICENSE
+ *
+ * Licensed under the Open Software License version 3.0
+ *
+ * This source file is subject to the Open Software License (OSL 3.0) that is
+ * bundled with this package in the files license.txt / license.rst.  It is
+ * also available through the world wide web at this URL:
+ * http://opensource.org/licenses/OSL-3.0
+ * If you did not receive a copy of the license and are unable to obtain it
+ * through the world wide web, please send an email to
+ * licensing@ellislab.com so we can send you a copy immediately.
+ *
+ * @package		CodeIgniter
+ * @author		EllisLab Dev Team
+ * @copyright	Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/)
+ * @license		http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
+ * @link		http://codeigniter.com
+ * @since		Version 3.0
+ * @filesource
+ */
+
+/**
+ * Interbase/Firebird Result Class
+ *
+ * This class extends the parent result class: CI_DB_result
+ *
+ * @category	Database
+ * @author		EllisLab Dev Team
+ * @link		http://codeigniter.com/user_guide/database/
+ */
+class CI_DB_interbase_result extends CI_DB_result {
+
+	public $num_rows;
+
+	/**
+	 * Number of rows in the result set
+	 *
+	 * @return	int
+	 */
+	public function num_rows()
+	{
+		if (is_int($this->num_rows))
+		{
+			return $this->num_rows;
+		}
+
+		// Get the results so that you can get an accurate rowcount
+		$this->result();
+
+		return $this->num_rows;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Number of fields in the result set
+	 *
+	 * @return	int
+	 */
+	public function num_fields()
+	{
+		return @ibase_num_fields($this->result_id);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Fetch Field Names
+	 *
+	 * Generates an array of column names
+	 *
+	 * @return	array
+	 */
+	public function list_fields()
+	{
+		$field_names = array();
+		for ($i = 0, $num_fields = $this->num_fields(); $i < $num_fields; $i++)
+		{
+			$info = ibase_field_info($this->result_id, $i);
+			$field_names[] = $info['name'];
+		}
+
+		return $field_names;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Field data
+	 *
+	 * Generates an array of objects containing field meta-data
+	 *
+	 * @return	array
+	 */
+	public function field_data()
+	{
+		$retval = array();
+		for ($i = 0, $c = $this->num_fields(); $i < $c; $i++)
+		{
+			$info = ibase_field_info($this->result_id, $i);
+
+			$retval[$i]			= new stdClass();
+			$retval[$i]->name		= $info['name'];
+			$retval[$i]->type		= $info['type'];
+			$retval[$i]->max_length		= $info['length'];
+			$retval[$i]->primary_key	= 0;
+			$retval[$i]->default		= '';
+		}
+
+		return $retval;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Free the result
+	 *
+	 * @return	void
+	 */
+	public function free_result()
+	{
+		@ibase_free_result($this->result_id);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Result - associative array
+	 *
+	 * Returns the result set as an array
+	 *
+	 * @return	array
+	 */
+	protected function _fetch_assoc()
+	{
+		if (($row = @ibase_fetch_assoc($this->result_id, IBASE_FETCH_BLOBS)) !== FALSE)
+		{
+			//Increment row count
+			$this->num_rows++;
+		}
+
+		return $row;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Result - object
+	 *
+	 * Returns the result set as an object
+	 *
+	 * @return	object
+	 */
+	protected function _fetch_object()
+	{
+		if (($row = @ibase_fetch_object($this->result_id, IBASE_FETCH_BLOBS)) !== FALSE)
+		{
+			//Increment row count
+			$this->num_rows++;
+		}
+
+		return $row;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Query result.  "object" version.
+	 *
+	 * @return	object
+	 */
+	public function result_object()
+	{
+		if (count($this->result_object) === $this->num_rows)
+		{
+			return $this->result_object;
+		}
+
+		// Convert result array to object so that
+		// We don't have to get the result again
+		if (($c = count($this->result_array)) > 0)
+		{
+			for ($i = 0; $i < $c; $i++)
+			{
+				$this->result_object[$i] = (object) $this->result_array[$i];
+			}
+
+			return $this->result_object;
+		}
+
+		// In the event that query caching is on the result_id variable
+		// will return FALSE since there isn't a valid SQL resource so
+		// we'll simply return an empty array.
+		if ($this->result_id === FALSE)
+		{
+			return array();
+		}
+
+		$this->num_rows = 0;
+		while ($row = $this->_fetch_object())
+		{
+			$this->result_object[] = $row;
+		}
+
+		return $this->result_object;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Query result.  "array" version.
+	 *
+	 * @return	array
+	 */
+	public function result_array()
+	{
+		if (count($this->result_array) === $this->num_rows)
+		{
+			return $this->result_array;
+		}
+
+		// Since the object and array are really similar, just case
+		// the result object to an array  if need be
+		if (($c = count($this->result_object)) > 0)
+		{
+			for ($i = 0; $i < $c; $i++)
+			{
+				$this->result_array[$i] = (array) $this->result_object[$i];
+			}
+
+			return $this->result_array;
+		}
+
+		// In the event that query caching is on the result_id variable
+		// will return FALSE since there isn't a valid SQL resource so
+		// we'll simply return an empty array.
+		if ($this->result_id === FALSE)
+		{
+			return array();
+		}
+
+		$this->num_rows = 0;
+		while ($row = $this->_fetch_assoc())
+		{
+			$this->result_array[] = $row;
+		}
+
+		return $this->result_array;
+	}
+
+}
+
+/* End of file interbase_result.php */
+/* Location: ./system/database/drivers/interbase/interbase_result.php */
\ No newline at end of file
diff --git a/system/database/drivers/interbase/interbase_utility.php b/system/database/drivers/interbase/interbase_utility.php
new file mode 100644
index 0000000..1642118
--- /dev/null
+++ b/system/database/drivers/interbase/interbase_utility.php
@@ -0,0 +1,62 @@
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.2.4 or newer
+ *
+ * NOTICE OF LICENSE
+ *
+ * Licensed under the Open Software License version 3.0
+ *
+ * This source file is subject to the Open Software License (OSL 3.0) that is
+ * bundled with this package in the files license.txt / license.rst.  It is
+ * also available through the world wide web at this URL:
+ * http://opensource.org/licenses/OSL-3.0
+ * If you did not receive a copy of the license and are unable to obtain it
+ * through the world wide web, please send an email to
+ * licensing@ellislab.com so we can send you a copy immediately.
+ *
+ * @package		CodeIgniter
+ * @author		EllisLab Dev Team
+ * @copyright	Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/)
+ * @license		http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
+ * @link		http://codeigniter.com
+ * @since		Version 3.0
+ * @filesource
+ */
+
+/**
+ * Interbase/Firebird Utility Class
+ *
+ * @category	Database
+ * @author		EllisLab Dev Team
+ * @link		http://codeigniter.com/user_guide/database/
+ */
+class CI_DB_interbase_utility extends CI_DB_utility {
+
+	protected $_list_databases	= FALSE;
+
+	/**
+	 * Interbase/Firebird Export
+	 *
+	 * @param	string	$filename
+	 * @return	mixed
+	 */
+	protected function _backup($filename)
+	{
+		if ($service = ibase_service_attach($this->db->hostname, $this->db->username, $this->db->password))
+		{
+			$res = ibase_backup($service, $this->db->database, $filename.'.fbk');
+
+			// Close the service connection
+			ibase_service_detach($service);
+			return $res;
+		}
+
+		return FALSE;
+	}
+
+}
+
+/* End of file interbase_utility.php */
+/* Location: ./system/database/drivers/interbase/interbase_utility.php */
\ No newline at end of file
diff --git a/system/database/drivers/mssql/mssql_driver.php b/system/database/drivers/mssql/mssql_driver.php
index 2a10989..47dc558 100644
--- a/system/database/drivers/mssql/mssql_driver.php
+++ b/system/database/drivers/mssql/mssql_driver.php
@@ -1,13 +1,13 @@
-<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
- * 
+ *
  * Licensed under the Open Software License version 3.0
- * 
+ *
  * This source file is subject to the Open Software License (OSL 3.0) that is
  * bundled with this package in the files license.txt / license.rst.  It is
  * also available through the world wide web at this URL:
@@ -25,13 +25,11 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * MS SQL Database Adapter Class
  *
  * Note: _DB is an extender class that the app controller
- * creates dynamically based on whether the active record
+ * creates dynamically based on whether the query builder
  * class is being used or not.
  *
  * @package		CodeIgniter
@@ -42,37 +40,54 @@
  */
 class CI_DB_mssql_driver extends CI_DB {
 
-	var $dbdriver = 'mssql';
+	public $dbdriver = 'mssql';
 
 	// The character used for escaping
-	var $_escape_char = '';
+	protected $_escape_char = '"';
 
 	// clause and character used for LIKE escape sequences
-	var $_like_escape_str = " ESCAPE '%s' ";
-	var $_like_escape_chr = '!';
+	protected $_like_escape_str = " ESCAPE '%s' ";
+	protected $_like_escape_chr = '!';
 
 	/**
 	 * The syntax to count rows is slightly different across different
 	 * database engines, so this string appears in each driver and is
-	 * used for the count_all() and count_all_results() functions.
+	 * used for the count_all() and count_all_results() methods.
 	 */
-	var $_count_string = "SELECT COUNT(*) AS ";
-	var $_random_keyword = ' ASC'; // not currently supported
+	protected $_count_string = 'SELECT COUNT(*) AS ';
+	protected $_random_keyword = ' NEWID()';
+
+	// MSSQL-specific properties
+	protected $_quoted_identifier = TRUE;
+
+	/*
+	 * Constructor
+	 *
+	 * Appends the port number to the hostname, if needed.
+	 *
+	 * @param	array
+	 * @return	void
+	 */
+	public function __construct($params)
+	{
+		parent::__construct($params);
+
+		if ( ! empty($this->port))
+		{
+			$this->hostname .= (DIRECTORY_SEPARATOR === '\\' ? ',' : ':').$this->port;
+		}
+	}
+
+	// --------------------------------------------------------------------
 
 	/**
 	 * Non-persistent database connection
 	 *
-	 * @access	private called by the base class
 	 * @return	resource
 	 */
-	function db_connect()
+	public function db_connect()
 	{
-		if ($this->port != '')
-		{
-			$this->hostname .= ','.$this->port;
-		}
-
-		return @mssql_connect($this->hostname, $this->username, $this->password);
+		return $this->_mssql_connect();
 	}
 
 	// --------------------------------------------------------------------
@@ -80,33 +95,39 @@
 	/**
 	 * Persistent database connection
 	 *
-	 * @access	private called by the base class
 	 * @return	resource
 	 */
-	function db_pconnect()
+	public function db_pconnect()
 	{
-		if ($this->port != '')
-		{
-			$this->hostname .= ','.$this->port;
-		}
-
-		return @mssql_pconnect($this->hostname, $this->username, $this->password);
+		return $this->_mssql_connect(TRUE);
 	}
 
 	// --------------------------------------------------------------------
 
-	/**
-	 * Reconnect
+	/*
+	 * MSSQL Connect
 	 *
-	 * Keep / reestablish the db connection if no queries have been
-	 * sent for a length of time exceeding the server's idle timeout
-	 *
-	 * @access	public
-	 * @return	void
+	 * @param	bool
+	 * @return	resource
 	 */
-	function reconnect()
+	protected function _mssql_connect($persistent = FALSE)
 	{
-		// not implemented in MSSQL
+		$conn_id = ($persistent)
+				? @mssql_pconnect($this->hostname, $this->username, $this->password)
+				: @mssql_connect($this->hostname, $this->username, $this->password);
+
+		if ( ! $conn_id)
+		{
+			return FALSE;
+		}
+
+		// Determine how identifiers are escaped
+		$query = $this->query('SELECT CASE WHEN (@@OPTIONS | 256) = @@OPTIONS THEN 1 ELSE 0 END AS qi');
+		$query = $query->row_array();
+		$this->_quoted_identifier = empty($query) ? FALSE : (bool) $query->qi;
+		$this->_escape_char = ($this->_quoted_identifier) ? '"' : array('[', ']');
+
+		return $conn_id;
 	}
 
 	// --------------------------------------------------------------------
@@ -114,30 +135,25 @@
 	/**
 	 * Select the database
 	 *
-	 * @access	private called by the base class
-	 * @return	resource
+	 * @param	string	database name
+	 * @return	bool
 	 */
-	function db_select()
+	public function db_select($database = '')
 	{
+		if ($database === '')
+		{
+			$database = $this->database;
+		}
+
 		// Note: The brackets are required in the event that the DB name
 		// contains reserved characters
-		return @mssql_select_db('['.$this->database.']', $this->conn_id);
-	}
+		if (@mssql_select_db($this->escape_identifiers($database), $this->conn_id))
+		{
+			$this->database = $database;
+			return TRUE;
+		}
 
-	// --------------------------------------------------------------------
-
-	/**
-	 * Set client character set
-	 *
-	 * @access	public
-	 * @param	string
-	 * @param	string
-	 * @return	resource
-	 */
-	function db_set_charset($charset, $collation)
-	{
-		// @todo - add support if needed
-		return TRUE;
+		return FALSE;
 	}
 
 	// --------------------------------------------------------------------
@@ -145,49 +161,25 @@
 	/**
 	 * Execute the query
 	 *
-	 * @access	private called by the base class
 	 * @param	string	an SQL query
-	 * @return	resource
+	 * @return	mixed	resource if rows are returned, bool otherwise
 	 */
-	function _execute($sql)
+	protected function _execute($sql)
 	{
-		$sql = $this->_prep_query($sql);
 		return @mssql_query($sql, $this->conn_id);
 	}
 
 	// --------------------------------------------------------------------
 
 	/**
-	 * Prep the query
-	 *
-	 * If needed, each database adapter can prep the query string
-	 *
-	 * @access	private called by execute()
-	 * @param	string	an SQL query
-	 * @return	string
-	 */
-	function _prep_query($sql)
-	{
-		return $sql;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
 	 * Begin Transaction
 	 *
-	 * @access	public
 	 * @return	bool
 	 */
-	function trans_begin($test_mode = FALSE)
+	public function trans_begin($test_mode = FALSE)
 	{
-		if ( ! $this->trans_enabled)
-		{
-			return TRUE;
-		}
-
 		// When transactions are nested we only begin/commit/rollback the outermost ones
-		if ($this->_trans_depth > 0)
+		if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
 		{
 			return TRUE;
 		}
@@ -195,10 +187,9 @@
 		// Reset the transaction failure flag.
 		// If the $test_mode flag is set to TRUE transactions will be rolled back
 		// even if the queries produce a successful result.
-		$this->_trans_failure = ($test_mode === TRUE) ? TRUE : FALSE;
+		$this->_trans_failure = ($test_mode === TRUE);
 
-		$this->simple_query('BEGIN TRAN');
-		return TRUE;
+		return $this->simple_query('BEGIN TRAN');
 	}
 
 	// --------------------------------------------------------------------
@@ -206,24 +197,17 @@
 	/**
 	 * Commit Transaction
 	 *
-	 * @access	public
 	 * @return	bool
 	 */
-	function trans_commit()
+	public function trans_commit()
 	{
-		if ( ! $this->trans_enabled)
-		{
-			return TRUE;
-		}
-
 		// When transactions are nested we only begin/commit/rollback the outermost ones
-		if ($this->_trans_depth > 0)
+		if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
 		{
 			return TRUE;
 		}
 
-		$this->simple_query('COMMIT TRAN');
-		return TRUE;
+		return $this->simple_query('COMMIT TRAN');
 	}
 
 	// --------------------------------------------------------------------
@@ -231,24 +215,17 @@
 	/**
 	 * Rollback Transaction
 	 *
-	 * @access	public
 	 * @return	bool
 	 */
-	function trans_rollback()
+	public function trans_rollback()
 	{
-		if ( ! $this->trans_enabled)
-		{
-			return TRUE;
-		}
-
 		// When transactions are nested we only begin/commit/rollback the outermost ones
-		if ($this->_trans_depth > 0)
+		if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
 		{
 			return TRUE;
 		}
 
-		$this->simple_query('ROLLBACK TRAN');
-		return TRUE;
+		return $this->simple_query('ROLLBACK TRAN');
 	}
 
 	// --------------------------------------------------------------------
@@ -256,12 +233,11 @@
 	/**
 	 * Escape String
 	 *
-	 * @access	public
 	 * @param	string
 	 * @param	bool	whether or not the string will be used in a LIKE condition
 	 * @return	string
 	 */
-	function escape_str($str, $like = FALSE)
+	public function escape_str($str, $like = FALSE)
 	{
 		if (is_array($str))
 		{
@@ -279,7 +255,7 @@
 		// escape LIKE condition wildcards
 		if ($like === TRUE)
 		{
-			$str = str_replace(
+			return str_replace(
 				array($this->_like_escape_chr, '%', '_'),
 				array($this->_like_escape_chr.$this->_like_escape_chr, $this->_like_escape_chr.'%', $this->_like_escape_chr.'_'),
 				$str
@@ -294,10 +270,9 @@
 	/**
 	 * Affected Rows
 	 *
-	 * @access	public
-	 * @return	integer
+	 * @return	int
 	 */
-	function affected_rows()
+	public function affected_rows()
 	{
 		return @mssql_rows_affected($this->conn_id);
 	}
@@ -305,35 +280,35 @@
 	// --------------------------------------------------------------------
 
 	/**
-	* Insert ID
-	*
-	* Returns the last id created in the Identity column.
-	*
-	* @access public
-	* @return integer
-	*/
-	function insert_id()
+	 * Insert ID
+	 *
+	 * Returns the last id created in the Identity column.
+	 *
+	 * @return	string
+	 */
+	public function insert_id()
 	{
-		$ver = self::_parse_major_version($this->version());
-		$sql = ($ver >= 8 ? "SELECT SCOPE_IDENTITY() AS last_id" : "SELECT @@IDENTITY AS last_id");
-		$query = $this->query($sql);
-		$row = $query->row();
-		return $row->last_id;
+		$query = (self::_parse_major_version($this->version()) > 7)
+			? 'SELECT SCOPE_IDENTITY() AS last_id'
+			: 'SELECT @@IDENTITY AS last_id';
+
+		$query = $this->query($query);
+		$query = $query->row();
+		return $query->last_id;
 	}
 
 	// --------------------------------------------------------------------
 
 	/**
-	* Parse major version
-	*
-	* Grabs the major version number from the
-	* database server version string passed in.
-	*
-	* @access private
-	* @param string $version
-	* @return int16 major version number
-	*/
-	function _parse_major_version($version)
+	 * Parse major version
+	 *
+	 * Grabs the major version number from the
+	 * database server version string passed in.
+	 *
+	 * @param	string	$version
+	 * @return	int	major version number
+	 */
+	protected function _parse_major_version($version)
 	{
 		preg_match('/([0-9]+)\.([0-9]+)\.([0-9]+)/', $version, $ver_info);
 		return $ver_info[1]; // return the major version b/c that's all we're interested in.
@@ -342,45 +317,13 @@
 	// --------------------------------------------------------------------
 
 	/**
-	* Version number query string
-	*
-	* @access public
-	* @return string
-	*/
-	function _version()
-	{
-		return "SELECT @@VERSION AS ver";
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * "Count All" query
+	 * Version number query string
 	 *
-	 * Generates a platform-specific query string that counts all records in
-	 * the specified database
-	 *
-	 * @access	public
-	 * @param	string
 	 * @return	string
 	 */
-	function count_all($table = '')
+	protected function _version()
 	{
-		if ($table == '')
-		{
-			return 0;
-		}
-
-		$query = $this->query($this->_count_string . $this->_protect_identifiers('numrows') . " FROM " . $this->_protect_identifiers($table, TRUE, NULL, FALSE));
-
-		if ($query->num_rows() == 0)
-		{
-			return 0;
-		}
-
-		$row = $query->row();
-		$this->_reset_select();
-		return (int) $row->numrows;
+		return 'SELECT @@VERSION AS ver';
 	}
 
 	// --------------------------------------------------------------------
@@ -390,16 +333,15 @@
 	 *
 	 * Generates a platform-specific query string so that the table names can be fetched
 	 *
-	 * @access	private
-	 * @param	boolean
+	 * @param	bool
 	 * @return	string
 	 */
-	function _list_tables($prefix_limit = FALSE)
+	protected function _list_tables($prefix_limit = FALSE)
 	{
 		$sql = "SELECT name FROM sysobjects WHERE type = 'U' ORDER BY name";
 
 		// for future compatibility
-		if ($prefix_limit !== FALSE AND $this->dbprefix != '')
+		if ($prefix_limit !== FALSE AND $this->dbprefix !== '')
 		{
 			//$sql .= " LIKE '".$this->escape_like_str($this->dbprefix)."%' ".sprintf($this->_like_escape_str, $this->_like_escape_chr);
 			return FALSE; // not currently supported
@@ -415,11 +357,10 @@
 	 *
 	 * Generates a platform-specific query string so that the column names can be fetched
 	 *
-	 * @access	private
 	 * @param	string	the table name
 	 * @return	string
 	 */
-	function _list_columns($table = '')
+	protected function _list_columns($table = '')
 	{
 		return "SELECT * FROM INFORMATION_SCHEMA.Columns WHERE TABLE_NAME = '".$table."'";
 	}
@@ -431,82 +372,29 @@
 	 *
 	 * Generates a platform-specific query so that the column data can be retrieved
 	 *
-	 * @access	public
 	 * @param	string	the table name
-	 * @return	object
-	 */
-	function _field_data($table)
-	{
-		return "SELECT TOP 1 * FROM ".$table;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * The error message string
-	 *
-	 * @access	private
 	 * @return	string
 	 */
-	function _error_message()
+	protected function _field_data($table)
 	{
-		return mssql_get_last_message();
+		return 'SELECT TOP 1 * FROM '.$table;
 	}
 
 	// --------------------------------------------------------------------
 
 	/**
-	 * The error message number
+	 * Error
 	 *
-	 * @access	private
-	 * @return	integer
+	 * Returns an array containing code and message of the last
+	 * database error that has occured.
+	 *
+	 * @return	array
 	 */
-	function _error_number()
+	public function error()
 	{
-		// Are error numbers supported?
-		return '';
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Escape the SQL Identifiers
-	 *
-	 * This function escapes column and table names
-	 *
-	 * @access	private
-	 * @param	string
-	 * @return	string
-	 */
-	function _escape_identifiers($item)
-	{
-		if ($this->_escape_char == '')
-		{
-			return $item;
-		}
-
-		foreach ($this->_reserved_identifiers as $id)
-		{
-			if (strpos($item, '.'.$id) !== FALSE)
-			{
-				$str = $this->_escape_char. str_replace('.', $this->_escape_char.'.', $item);
-
-				// remove duplicates if the user already included the escape
-				return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str);
-			}
-		}
-
-		if (strpos($item, '.') !== FALSE)
-		{
-			$str = $this->_escape_char.str_replace('.', $this->_escape_char.'.'.$this->_escape_char, $item).$this->_escape_char;
-		}
-		else
-		{
-			$str = $this->_escape_char.$item.$this->_escape_char;
-		}
-
-		// remove duplicates if the user already included the escape
-		return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str);
+		$query = $this->query('SELECT @@ERROR AS code');
+		$query = $query->row();
+		return array('code' => $query->code, 'message' => mssql_get_last_message());
 	}
 
 	// --------------------------------------------------------------------
@@ -517,36 +405,12 @@
 	 * This function implicitly groups FROM tables so there is no confusion
 	 * about operator precedence in harmony with SQL standards
 	 *
-	 * @access	public
-	 * @param	type
-	 * @return	type
-	 */
-	function _from_tables($tables)
-	{
-		if ( ! is_array($tables))
-		{
-			$tables = array($tables);
-		}
-
-		return implode(', ', $tables);
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Insert statement
-	 *
-	 * Generates a platform-specific insert string from the supplied data
-	 *
-	 * @access	public
-	 * @param	string	the table name
-	 * @param	array	the insert keys
-	 * @param	array	the insert values
+	 * @param	array
 	 * @return	string
 	 */
-	function _insert($table, $keys, $values)
+	protected function _from_tables($tables)
 	{
-		return "INSERT INTO ".$table." (".implode(', ', $keys).") VALUES (".implode(', ', $values).")";
+		return is_array($tables) ? implode(', ', $tables) : $tables;
 	}
 
 	// --------------------------------------------------------------------
@@ -556,51 +420,47 @@
 	 *
 	 * Generates a platform-specific update string from the supplied data
 	 *
-	 * @access	public
 	 * @param	string	the table name
 	 * @param	array	the update data
 	 * @param	array	the where clause
-	 * @param	array	the orderby clause
-	 * @param	array	the limit clause
+	 * @param	array	the orderby clause (ignored)
+	 * @param	array	the limit clause (ignored)
+	 * @param	array	the like clause
 	 * @return	string
 	 */
-	function _update($table, $values, $where, $orderby = array(), $limit = FALSE)
+	protected function _update($table, $values, $where, $orderby = array(), $limit = FALSE, $like = array())
 	{
-		foreach ($values as $key => $val)
+		foreach($values as $key => $val)
 		{
-			$valstr[] = $key." = ".$val;
+			$valstr[] = $key.' = '.$val;
 		}
 
-		$limit = ( ! $limit) ? '' : ' LIMIT '.$limit;
+		$where = empty($where) ? '' : ' WHERE '.implode(' ', $where);
 
-		$orderby = (count($orderby) >= 1)?' ORDER BY '.implode(", ", $orderby):'';
+		if ( ! empty($like))
+		{
+			$where .= ($where === '' ? ' WHERE ' : ' AND ').implode(' ', $like);
+		}
 
-		$sql = "UPDATE ".$table." SET ".implode(', ', $valstr);
-
-		$sql .= ($where != '' AND count($where) >=1) ? " WHERE ".implode(" ", $where) : '';
-
-		$sql .= $orderby.$limit;
-
-		return $sql;
+		return 'UPDATE '.$table.' SET '.implode(', ', $valstr).' WHERE '.$where;
 	}
 
-
 	// --------------------------------------------------------------------
 
 	/**
 	 * Truncate statement
 	 *
 	 * Generates a platform-specific truncate string from the supplied data
-	 * If the database does not support the truncate() command
-	 * This function maps to "DELETE FROM table"
 	 *
-	 * @access	public
+	 * If the database does not support the truncate() command,
+	 * then this method maps to 'DELETE FROM table'
+	 *
 	 * @param	string	the table name
 	 * @return	string
 	 */
-	function _truncate($table)
+	protected function _truncate($table)
 	{
-		return "TRUNCATE ".$table;
+		return 'TRUNCATE TABLE '.$table;
 	}
 
 	// --------------------------------------------------------------------
@@ -610,31 +470,24 @@
 	 *
 	 * Generates a platform-specific delete string from the supplied data
 	 *
-	 * @access	public
 	 * @param	string	the table name
 	 * @param	array	the where clause
+	 * @param	array	the like clause
 	 * @param	string	the limit clause
 	 * @return	string
 	 */
-	function _delete($table, $where = array(), $like = array(), $limit = FALSE)
+	protected function _delete($table, $where = array(), $like = array(), $limit = FALSE)
 	{
-		$conditions = '';
+		$conditions = array();
 
-		if (count($where) > 0 OR count($like) > 0)
-		{
-			$conditions = "\nWHERE ";
-			$conditions .= implode("\n", $this->ar_where);
+		empty($where) OR $conditions[] = implode(' ', $where);
+		empty($like) OR $conditions[] = implode(' ', $like);
 
-			if (count($where) > 0 && count($like) > 0)
-			{
-				$conditions .= " AND ";
-			}
-			$conditions .= implode("\n", $like);
-		}
+		$conditions = (count($conditions) > 0) ? ' WHERE '.implode(' AND ', $conditions) : '';
 
-		$limit = ( ! $limit) ? '' : ' LIMIT '.$limit;
-
-		return "DELETE FROM ".$table.$conditions.$limit;
+		return ($limit)
+			? 'WITH ci_delete AS (SELECT TOP '.$limit.' * FROM '.$table.$conditions.') DELETE FROM ci_delete'
+			: 'DELETE FROM '.$table.$conditions;
 	}
 
 	// --------------------------------------------------------------------
@@ -644,17 +497,37 @@
 	 *
 	 * Generates a platform-specific LIMIT clause
 	 *
-	 * @access	public
 	 * @param	string	the sql query string
-	 * @param	integer	the number of rows to limit the query to
-	 * @param	integer	the offset value
+	 * @param	int	the number of rows to limit the query to
+	 * @param	int	the offset value
 	 * @return	string
 	 */
-	function _limit($sql, $limit, $offset)
+	protected function _limit($sql, $limit, $offset)
 	{
-		$i = $limit + $offset;
+		// As of SQL Server 2012 (11.0.*) OFFSET is supported
+		if (version_compare($this->version(), '11', '>='))
+		{
+			return $sql.' OFFSET '.(int) $offset.' ROWS FETCH NEXT '.(int) $limit.' ROWS ONLY';
+		}
 
-		return preg_replace('/(^\SELECT (DISTINCT)?)/i','\\1 TOP '.$i.' ', $sql);
+		$limit = $offset + $limit;
+
+		// As of SQL Server 2005 (9.0.*) ROW_NUMBER() is supported,
+		// however an ORDER BY clause is required for it to work
+		if (version_compare($this->version(), '9', '>=') && $offset && ! empty($this->qb_orderby))
+		{
+			$orderby = 'ORDER BY '.implode(', ', $this->qb_orderby);
+
+			// We have to strip the ORDER BY clause
+			$sql = trim(substr($sql, 0, strrpos($sql, 'ORDER BY '.$orderby)));
+
+			return 'SELECT '.(count($this->qb_select) === 0 ? '*' : implode(', ', $this->qb_select))." FROM (\n"
+				.preg_replace('/^(SELECT( DISTINCT)?)/i', '\\1 ROW_NUMBER() OVER('.$orderby.') AS '.$this->escape_identifiers('CI_rownum').', ', $sql)
+				."\n) ".$this->escape_identifiers('CI_subquery')
+				."\nWHERE ".$this->escape_identifiers('CI_rownum').' BETWEEN '.((int) $offset + 1).' AND '.$limit;
+		}
+
+		return preg_replace('/(^\SELECT (DISTINCT)?)/i','\\1 TOP '.$limit.' ', $sql);
 	}
 
 	// --------------------------------------------------------------------
@@ -662,18 +535,14 @@
 	/**
 	 * Close DB Connection
 	 *
-	 * @access	public
-	 * @param	resource
 	 * @return	void
 	 */
-	function _close($conn_id)
+	protected function _close()
 	{
-		@mssql_close($conn_id);
+		@mssql_close($this->conn_id);
 	}
 
 }
 
-
-
 /* End of file mssql_driver.php */
 /* Location: ./system/database/drivers/mssql/mssql_driver.php */
\ No newline at end of file
diff --git a/system/database/drivers/mssql/mssql_forge.php b/system/database/drivers/mssql/mssql_forge.php
index dd8aa34..3a3528f 100644
--- a/system/database/drivers/mssql/mssql_forge.php
+++ b/system/database/drivers/mssql/mssql_forge.php
@@ -1,13 +1,13 @@
-<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
- * 
+ *
  * Licensed under the Open Software License version 3.0
- * 
+ *
  * This source file is subject to the Open Software License (OSL 3.0) that is
  * bundled with this package in the files license.txt / license.rst.  It is
  * also available through the world wide web at this URL:
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * MS SQL Forge Class
  *
@@ -36,112 +34,61 @@
  */
 class CI_DB_mssql_forge extends CI_DB_forge {
 
-	/**
-	 * Create database
-	 *
-	 * @access	private
-	 * @param	string	the database name
-	 * @return	bool
-	 */
-	function _create_database($name)
-	{
-		return "CREATE DATABASE ".$name;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Drop database
-	 *
-	 * @access	private
-	 * @param	string	the database name
-	 * @return	bool
-	 */
-	function _drop_database($name)
-	{
-		return "DROP DATABASE ".$name;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Drop Table
-	 *
-	 * @access	private
-	 * @return	bool
-	 */
-	function _drop_table($table)
-	{
-		return "DROP TABLE ".$this->db->_escape_identifiers($table);
-	}
-
-	// --------------------------------------------------------------------
+	protected $_drop_table	= 'DROP TABLE %s';
 
 	/**
 	 * Create Table
 	 *
-	 * @access	private
 	 * @param	string	the table name
 	 * @param	array	the fields
 	 * @param	mixed	primary key(s)
 	 * @param	mixed	key(s)
-	 * @param	boolean	should 'IF NOT EXISTS' be added to the SQL
-	 * @return	bool
+	 * @param	bool	should 'IF NOT EXISTS' be added to the SQL
+	 * @return	string
 	 */
-	function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists)
+	protected function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists)
 	{
-		$sql = 'CREATE TABLE ';
+		$sql = ($if_not_exists === TRUE)
+			? "IF NOT EXISTS (SELECT * FROM sysobjects WHERE ID = object_id(N'".$table."') AND OBJECTPROPERTY(id, N'IsUserTable') = 1)\n"
+			: '';
 
-		if ($if_not_exists === TRUE)
-		{
-			$sql .= 'IF NOT EXISTS ';
-		}
+		$sql .= 'CREATE TABLE '.$this->db->escape_identifiers($table).' (';
 
-		$sql .= $this->db->_escape_identifiers($table)." (";
 		$current_field_count = 0;
-
-		foreach ($fields as $field=>$attributes)
+		foreach ($fields as $field => $attributes)
 		{
 			// Numeric field names aren't allowed in databases, so if the key is
 			// numeric, we know it was assigned by PHP and the developer manually
 			// entered the field information, so we'll simply add it to the list
 			if (is_numeric($field))
 			{
-				$sql .= "\n\t$attributes";
+				$sql .= "\n\t".$attributes;
 			}
 			else
 			{
 				$attributes = array_change_key_case($attributes, CASE_UPPER);
 
-				$sql .= "\n\t".$this->db->_protect_identifiers($field);
+				$sql .= "\n\t".$this->db->escape_identifiers($field).' '.$attributes['TYPE'];
 
-				$sql .=  ' '.$attributes['TYPE'];
-
-				if (array_key_exists('CONSTRAINT', $attributes))
+				if (stripos($attributes['TYPE'], 'INT') === FALSE && ! empty($attributes['CONSTRAINT']))
 				{
 					$sql .= '('.$attributes['CONSTRAINT'].')';
 				}
 
-				if (array_key_exists('UNSIGNED', $attributes) && $attributes['UNSIGNED'] === TRUE)
+				if ( ! empty($attributes['UNSIGNED']) && $attributes['UNSIGNED'] === TRUE)
 				{
 					$sql .= ' UNSIGNED';
 				}
 
-				if (array_key_exists('DEFAULT', $attributes))
+				if (isset($attributes['DEFAULT']))
 				{
-					$sql .= ' DEFAULT \''.$attributes['DEFAULT'].'\'';
+					$sql .= " DEFAULT '".$attributes['DEFAULT']."'";
 				}
 
-				if (array_key_exists('NULL', $attributes) && $attributes['NULL'] === TRUE)
-				{
-					$sql .= ' NULL';
-				}
-				else
-				{
-					$sql .= ' NOT NULL';
-				}
+				$sql .= ( ! empty($attributes['NULL']) && $attributes['NULL'] === TRUE)
+					? ' NULL' : ' NOT NULL';
 
-				if (array_key_exists('AUTO_INCREMENT', $attributes) && $attributes['AUTO_INCREMENT'] === TRUE)
+				if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE)
 				{
 					$sql .= ' AUTO_INCREMENT';
 				}
@@ -156,30 +103,22 @@
 
 		if (count($primary_keys) > 0)
 		{
-			$primary_keys = $this->db->_protect_identifiers($primary_keys);
-			$sql .= ",\n\tPRIMARY KEY (" . implode(', ', $primary_keys) . ")";
+			$sql .= ",\n\tPRIMARY KEY (".implode(', ', $this->db->escape_identifiers($primary_keys)).')';
 		}
 
 		if (is_array($keys) && count($keys) > 0)
 		{
 			foreach ($keys as $key)
 			{
-				if (is_array($key))
-				{
-					$key = $this->db->_protect_identifiers($key);
-				}
-				else
-				{
-					$key = array($this->db->_protect_identifiers($key));
-				}
+				$key = is_array($key)
+					? $this->db->escape_identifiers($key)
+					: array($this->db->escape_identifiers($key));
 
-				$sql .= ",\n\tFOREIGN KEY (" . implode(', ', $key) . ")";
+				$sql .= ",\n\tFOREIGN KEY (".implode(', ', $key).')';
 			}
 		}
 
-		$sql .= "\n)";
-
-		return $sql;
+		return $sql."\n)";
 	}
 
 	// --------------------------------------------------------------------
@@ -190,68 +129,29 @@
 	 * Generates a platform-specific query so that a table can be altered
 	 * Called by add_column(), drop_column(), and column_alter(),
 	 *
-	 * @access	private
 	 * @param	string	the ALTER type (ADD, DROP, CHANGE)
 	 * @param	string	the column name
 	 * @param	string	the table name
 	 * @param	string	the column definition
 	 * @param	string	the default value
-	 * @param	boolean	should 'NOT NULL' be added
+	 * @param	bool	should 'NOT NULL' be added
 	 * @param	string	the field after which we should add the new field
-	 * @return	object
+	 * @return	string
 	 */
-	function _alter_table($alter_type, $table, $column_name, $column_definition = '', $default_value = '', $null = '', $after_field = '')
+	protected function _alter_table($alter_type, $table, $column_name, $column_definition = '', $default_value = '', $null = '', $after_field = '')
 	{
-		$sql = 'ALTER TABLE '.$this->db->_protect_identifiers($table)." $alter_type ".$this->db->_protect_identifiers($column_name);
+		$sql = 'ALTER TABLE '.$this->db->escape_identifiers($table).' '.$alter_type.' '.$this->db->escape_identifiers($column_name);
 
 		// DROP has everything it needs now.
-		if ($alter_type == 'DROP')
+		if ($alter_type === 'DROP')
 		{
 			return $sql;
 		}
 
-		$sql .= " $column_definition";
-
-		if ($default_value != '')
-		{
-			$sql .= " DEFAULT \"$default_value\"";
-		}
-
-		if ($null === NULL)
-		{
-			$sql .= ' NULL';
-		}
-		else
-		{
-			$sql .= ' NOT NULL';
-		}
-
-		if ($after_field != '')
-		{
-			$sql .= ' AFTER ' . $this->db->_protect_identifiers($after_field);
-		}
-
-		return $sql;
-
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Rename a table
-	 *
-	 * Generates a platform-specific query so that a table can be renamed
-	 *
-	 * @access	private
-	 * @param	string	the old table name
-	 * @param	string	the new table name
-	 * @return	string
-	 */
-	function _rename_table($table_name, $new_table_name)
-	{
-		// I think this syntax will work, but can find little documentation on renaming tables in MSSQL
-		$sql = 'ALTER TABLE '.$this->db->_protect_identifiers($table_name)." RENAME TO ".$this->db->_protect_identifiers($new_table_name);
-		return $sql;
+		return $sql.' '.$column_definition
+			.($default_value != '' ? ' DEFAULT "'.$default_value.'"' : '')
+			.($null === NULL ? ' NULL' : ' NOT NULL')
+			.($after_field != '' ? ' AFTER '.$this->db->escape_identifiers($after_field) : '');
 	}
 
 }
diff --git a/system/database/drivers/mssql/mssql_result.php b/system/database/drivers/mssql/mssql_result.php
index bba2e62..5929306 100644
--- a/system/database/drivers/mssql/mssql_result.php
+++ b/system/database/drivers/mssql/mssql_result.php
@@ -1,13 +1,13 @@
-<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
- * 
+ *
  * Licensed under the Open Software License version 3.0
- * 
+ *
  * This source file is subject to the Open Software License (OSL 3.0) that is
  * bundled with this package in the files license.txt / license.rst.  It is
  * also available through the world wide web at this URL:
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * MS SQL Result Class
  *
@@ -41,10 +39,9 @@
 	/**
 	 * Number of rows in the result set
 	 *
-	 * @access	public
-	 * @return	integer
+	 * @return	int
 	 */
-	function num_rows()
+	public function num_rows()
 	{
 		return @mssql_num_rows($this->result_id);
 	}
@@ -54,10 +51,9 @@
 	/**
 	 * Number of fields in the result set
 	 *
-	 * @access	public
-	 * @return	integer
+	 * @return	int
 	 */
-	function num_fields()
+	public function num_fields()
 	{
 		return @mssql_num_fields($this->result_id);
 	}
@@ -69,10 +65,9 @@
 	 *
 	 * Generates an array of column names
 	 *
-	 * @access	public
 	 * @return	array
 	 */
-	function list_fields()
+	public function list_fields()
 	{
 		$field_names = array();
 		while ($field = mssql_fetch_field($this->result_id))
@@ -90,20 +85,19 @@
 	 *
 	 * Generates an array of objects containing field meta-data
 	 *
-	 * @access	public
 	 * @return	array
 	 */
-	function field_data()
+	public function field_data()
 	{
 		$retval = array();
 		while ($field = mssql_fetch_field($this->result_id))
 		{
-			$F				= new stdClass();
-			$F->name		= $field->name;
-			$F->type		= $field->type;
+			$F		= new stdClass();
+			$F->name	= $field->name;
+			$F->type	= $field->type;
 			$F->max_length	= $field->max_length;
 			$F->primary_key = 0;
-			$F->default		= '';
+			$F->default	= '';
 
 			$retval[] = $F;
 		}
@@ -116,9 +110,9 @@
 	/**
 	 * Free the result
 	 *
-	 * @return	null
+	 * @return	void
 	 */
-	function free_result()
+	public function free_result()
 	{
 		if (is_resource($this->result_id))
 		{
@@ -132,14 +126,13 @@
 	/**
 	 * Data Seek
 	 *
-	 * Moves the internal pointer to the desired offset.  We call
+	 * Moves the internal pointer to the desired offset. We call
 	 * this internally before fetching results to make sure the
 	 * result set starts at zero
 	 *
-	 * @access	private
-	 * @return	array
+	 * @return	bool
 	 */
-	function _data_seek($n = 0)
+	protected function _data_seek($n = 0)
 	{
 		return mssql_data_seek($this->result_id, $n);
 	}
@@ -151,10 +144,9 @@
 	 *
 	 * Returns the result set as an array
 	 *
-	 * @access	private
 	 * @return	array
 	 */
-	function _fetch_assoc()
+	protected function _fetch_assoc()
 	{
 		return mssql_fetch_assoc($this->result_id);
 	}
@@ -166,16 +158,14 @@
 	 *
 	 * Returns the result set as an object
 	 *
-	 * @access	private
 	 * @return	object
 	 */
-	function _fetch_object()
+	protected function _fetch_object()
 	{
 		return mssql_fetch_object($this->result_id);
 	}
 
 }
 
-
 /* End of file mssql_result.php */
 /* Location: ./system/database/drivers/mssql/mssql_result.php */
\ No newline at end of file
diff --git a/system/database/drivers/mssql/mssql_utility.php b/system/database/drivers/mssql/mssql_utility.php
index be6ed5b..69fcec5 100644
--- a/system/database/drivers/mssql/mssql_utility.php
+++ b/system/database/drivers/mssql/mssql_utility.php
@@ -1,13 +1,13 @@
-<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
- * 
+ *
  * Licensed under the Open Software License version 3.0
- * 
+ *
  * This source file is subject to the Open Software License (OSL 3.0) that is
  * bundled with this package in the files license.txt / license.rst.  It is
  * also available through the world wide web at this URL:
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * MS SQL Utility Class
  *
@@ -36,59 +34,16 @@
  */
 class CI_DB_mssql_utility extends CI_DB_utility {
 
-	/**
-	 * List databases
-	 *
-	 * @access	private
-	 * @return	bool
-	 */
-	function _list_databases()
-	{
-		return "EXEC sp_helpdb"; // Can also be: EXEC sp_databases
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Optimize table query
-	 *
-	 * Generates a platform-specific query so that a table can be optimized
-	 *
-	 * @access	private
-	 * @param	string	the table name
-	 * @return	object
-	 */
-	function _optimize_table($table)
-	{
-		return FALSE; // Is this supported in MS SQL?
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Repair table query
-	 *
-	 * Generates a platform-specific query so that a table can be repaired
-	 *
-	 * @access	private
-	 * @param	string	the table name
-	 * @return	object
-	 */
-	function _repair_table($table)
-	{
-		return FALSE; // Is this supported in MS SQL?
-	}
-
-	// --------------------------------------------------------------------
+	protected $_list_databases	= 'EXEC sp_helpdb'; // Can also be: EXEC sp_databases
+	protected $_optimize_table	= 'ALTER INDEX all ON %s REORGANIZE';
 
 	/**
 	 * MSSQL Export
 	 *
-	 * @access	private
 	 * @param	array	Preferences
-	 * @return	mixed
+	 * @return	bool
 	 */
-	function _backup($params = array())
+	protected function _backup($params = array())
 	{
 		// Currently unsupported
 		return $this->db->display_error('db_unsuported_feature');
diff --git a/system/database/drivers/mysql/mysql_driver.php b/system/database/drivers/mysql/mysql_driver.php
index 067710f..8938d22 100644
--- a/system/database/drivers/mysql/mysql_driver.php
+++ b/system/database/drivers/mysql/mysql_driver.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -29,7 +29,7 @@
  * MySQL Database Adapter Class
  *
  * Note: _DB is an extender class that the app controller
- * creates dynamically based on whether the active record
+ * creates dynamically based on whether the query builder
  * class is being used or not.
  *
  * @package		CodeIgniter
@@ -47,7 +47,7 @@
 
 	// clause and character used for LIKE escape sequences - not used in MySQL
 	protected $_like_escape_str = '';
-	protected $_like_escape_chr = '';
+	protected $_like_escape_chr = '\\';
 
 	/**
 	 * The syntax to count rows is slightly different across different
@@ -68,7 +68,7 @@
 	{
 		parent::__construct($params);
 
-		if ($this->port != '')
+		if ( ! empty($this->port))
 		{
 			$this->hostname .= ':'.$this->port;
 		}
@@ -119,11 +119,23 @@
 	/**
 	 * Select the database
 	 *
+	 * @param	string	database name
 	 * @return	bool
 	 */
-	public function db_select()
+	public function db_select($database = '')
 	{
-		return @mysql_select_db($this->database, $this->conn_id);
+		if ($database === '')
+		{
+			$database = $this->database;
+		}
+
+		if (@mysql_select_db($database, $this->conn_id))
+		{
+			$this->database = $database;
+			return TRUE;
+		}
+
+		return FALSE;
 	}
 
 	// --------------------------------------------------------------------
@@ -132,26 +144,25 @@
 	 * Set client character set
 	 *
 	 * @param	string
-	 * @param	string
 	 * @return	bool
 	 */
-	public function db_set_charset($charset, $collation)
+	protected function _db_set_charset($charset)
 	{
-		return function_exists('mysql_set_charset')
-			? @mysql_set_charset($charset, $this->conn_id)
-			: @mysql_query("SET NAMES '".$this->escape_str($charset)."' COLLATE '".$this->escape_str($collation)."'", $this->conn_id);
+		return @mysql_set_charset($charset, $this->conn_id);
 	}
 
 	// --------------------------------------------------------------------
 
 	/**
-	 * Version number query string
+	 * Database version number
 	 *
 	 * @return	string
 	 */
-	protected function _version()
+	public function version()
 	{
-		return 'SELECT version() AS ver';
+		return isset($this->data_cache['version'])
+			? $this->data_cache['version']
+			: $this->data_cache['version'] = @mysql_get_server_info($this->conn_id);
 	}
 
 	// --------------------------------------------------------------------
@@ -275,23 +286,14 @@
 	   		return $str;
 	   	}
 
-		if (function_exists('mysql_real_escape_string') && is_resource($this->conn_id))
-		{
-			$str = mysql_real_escape_string($str, $this->conn_id);
-		}
-		elseif (function_exists('mysql_escape_string'))
-		{
-			$str = mysql_escape_string($str);
-		}
-		else
-		{
-			$str = addslashes($str);
-		}
+		$str = is_resource($this->conn_id) ? mysql_real_escape_string($str, $this->conn_id) : addslashes($str);
 
 		// escape LIKE condition wildcards
 		if ($like === TRUE)
 		{
-			return str_replace(array('%', '_'), array('\\%', '\\_'), $str);
+			return str_replace(array($this->_like_escape_chr, '%', '_'),
+						array($this->_like_escape_chr.$this->_like_escape_chr, $this->_like_escape_chr.'%', $this->_like_escape_chr.'_'),
+						$str);
 		}
 
 		return $str;
@@ -324,35 +326,6 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 * "Count All" query
-	 *
-	 * Generates a platform-specific query string that counts all records in
-	 * the specified database
-	 *
-	 * @param	string
-	 * @return	string
-	 */
-	public function count_all($table = '')
-	{
-		if ($table == '')
-		{
-			return 0;
-		}
-
-		$query = $this->query($this->_count_string.$this->protect_identifiers('numrows').' FROM '.$this->protect_identifiers($table, TRUE, NULL, FALSE));
-		if ($query->num_rows() == 0)
-		{
-			return 0;
-		}
-
-		$query = $query->row();
-		$this->_reset_select();
-		return (int) $query->numrows;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
 	 * List table query
 	 *
 	 * Generates a platform-specific query string so that the table names can be fetched
@@ -364,7 +337,7 @@
 	{
 		$sql = 'SHOW TABLES FROM '.$this->_escape_char.$this->database.$this->_escape_char;
 
-		if ($prefix_limit !== FALSE && $this->dbprefix != '')
+		if ($prefix_limit !== FALSE && $this->dbprefix !== '')
 		{
 			return $sql." LIKE '".$this->escape_like_str($this->dbprefix)."%'";
 		}
@@ -390,189 +363,55 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 * Field data query
-	 *
-	 * Generates a platform-specific query so that the column data can be retrieved
+	 * Returns an object with field data
 	 *
 	 * @param	string	the table name
-	 * @return	string
+	 * @return	object
 	 */
-	public function _field_data($table)
+	public function field_data($table = '')
 	{
-		return 'DESCRIBE '.$table;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * The error message string
-	 *
-	 * @return	string
-	 */
-	protected function _error_message()
-	{
-		return mysql_error($this->conn_id);
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * The error message number
-	 *
-	 * @return	int
-	 */
-	protected function _error_number()
-	{
-		return mysql_errno($this->conn_id);
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Escape the SQL Identifiers
-	 *
-	 * This function escapes column and table names
-	 *
-	 * @param	string
-	 * @return	string
-	 */
-	public function _escape_identifiers($item)
-	{
-		if ($this->_escape_char == '')
+		if ($table === '')
 		{
-			return $item;
+			return ($this->db_debug) ? $this->display_error('db_field_param_missing') : FALSE;
 		}
 
-		foreach ($this->_reserved_identifiers as $id)
-		{
-			if (strpos($item, '.'.$id) !== FALSE)
-			{
-				$item = str_replace('.', $this->_escape_char.'.', $item);
+		$query = $this->query('DESCRIBE '.$this->protect_identifiers($table, TRUE, NULL, FALSE));
+		$query = $query->result_object();
 
-				// remove duplicates if the user already included the escape
-				return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $this->_escape_char.$item);
-			}
+		$retval = array();
+		for ($i = 0, $c = count($query); $i < $c; $i++)
+		{
+			preg_match('/([a-z]+)(\(\d+\))?/', $query[$i]->Type, $matches);
+
+			$retval[$i]			= new stdClass();
+			$retval[$i]->name		= $query[$i]->Field;
+			$retval[$i]->type		= empty($matches[1]) ? NULL : $matches[1];
+			$retval[$i]->default		= $query[$i]->Default;
+			$retval[$i]->max_length		= empty($matches[2]) ? NULL : preg_replace('/[^\d]/', '', $matches[2]);
+			$retval[$i]->primary_key	= (int) ($query[$i]->Key === 'PRI');
 		}
 
-		if (strpos($item, '.') !== FALSE)
-		{
-			$item = str_replace('.', $this->_escape_char.'.'.$this->_escape_char, $item);
-		}
-
-		// remove duplicates if the user already included the escape
-		return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $this->_escape_char.$item.$this->_escape_char);
+		return $retval;
 	}
 
 	// --------------------------------------------------------------------
 
 	/**
-	 * From Tables
+	 * Error
 	 *
-	 * This function implicitly groups FROM tables so there is no confusion
-	 * about operator precedence in harmony with SQL standards
+	 * Returns an array containing code and message of the last
+	 * database error that has occured.
 	 *
-	 * @param	string	table name
-	 * @return	string
+	 * @return	array
 	 */
-	protected function _from_tables($tables)
+	public function error()
 	{
-		if ( ! is_array($tables))
-		{
-			$tables = array($tables);
-		}
-
-		return '('.implode(', ', $tables).')';
+		return array('code' => mysql_errno($this->conn_id), 'message' => mysql_error($this->conn_id));
 	}
 
 	// --------------------------------------------------------------------
 
 	/**
-	 * Insert statement
-	 *
-	 * Generates a platform-specific insert string from the supplied data
-	 *
-	 * @param	string	the table name
-	 * @param	array	the insert keys
-	 * @param	array	the insert values
-	 * @return	string
-	 */
-	protected function _insert($table, $keys, $values)
-	{
-		return 'INSERT INTO '.$table.' ('.implode(', ', $keys).') VALUES ('.implode(', ', $values).')';
-	}
-
-	// --------------------------------------------------------------------
-
-
-	/**
-	 * Replace statement
-	 *
-	 * Generates a platform-specific replace string from the supplied data
-	 *
-	 * @param	string	the table name
-	 * @param	array	the insert keys
-	 * @param	array	the insert values
-	 * @return	string
-	 */
-	protected function _replace($table, $keys, $values)
-	{
-		return 'REPLACE INTO '.$table.' ('.implode(', ', $keys).') VALUES ('.implode(', ', $values).')';
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Insert_batch statement
-	 *
-	 * Generates a platform-specific insert string from the supplied data
-	 *
-	 * @param	string	the table name
-	 * @param	array	the insert keys
-	 * @param	array	the insert values
-	 * @return	string
-	 */
-	protected function _insert_batch($table, $keys, $values)
-	{
-		return 'INSERT INTO '.$table.' ('.implode(', ', $keys).') VALUES '.implode(', ', $values);
-	}
-
-	// --------------------------------------------------------------------
-
-
-	/**
-	 * Update statement
-	 *
-	 * Generates a platform-specific update string from the supplied data
-	 *
-	 * @param	string	the table name
-	 * @param	array	the update data
-	 * @param	array	the where clause
-	 * @param	array	the orderby clause
-	 * @param	array	the limit clause
-	 * @return	string
-	 */
-	protected function _update($table, $values, $where, $orderby = array(), $limit = FALSE, $like = array())
-	{
-		foreach ($values as $key => $val)
-		{
-			$valstr[] = $key.' = '.$val;
-		}
-
-		$where = ($where != '' && count($where) > 0) ? ' WHERE '.implode(' ', $where) : '';
-		if (count($like) > 0)
-		{
-			$where .= ($where == '' ? ' WHERE ' : ' AND ').implode(' ', $like);
-		}
-
-		return 'UPDATE '.$table.' SET '.implode(', ', $valstr).$where
-			.(count($orderby) > 0 ? ' ORDER BY '.implode(', ', $orderby) : '')
-			.( ! $limit ? '' : ' LIMIT '.$limit);
-	}
-
-	// --------------------------------------------------------------------
-
-
-	/**
 	 * Update_Batch statement
 	 *
 	 * Generates a platform-specific batch update string from the supplied data
@@ -591,7 +430,7 @@
 
 			foreach (array_keys($val) as $field)
 			{
-				if ($field != $index)
+				if ($field !== $index)
 				{
 					$final[$field][] =  'WHEN '.$index.' = '.$val[$index].' THEN '.$val[$field];
 				}
@@ -607,60 +446,13 @@
 		}
 
 		return 'UPDATE '.$table.' SET '.substr($cases, 0, -2)
-			.' WHERE '.(($where != '' && count($where) > 0) ? implode(' ', $where).' AND ' : '')
+			.' WHERE '.(($where !== '' && count($where) > 0) ? implode(' ', $where).' AND ' : '')
 			.$index.' IN('.implode(',', $ids).')';
 	}
 
 	// --------------------------------------------------------------------
 
 	/**
-	 * Truncate statement
-	 *
-	 * Generates a platform-specific truncate string from the supplied data
-	 * If the database does not support the truncate() command
-	 * This function maps to "DELETE FROM table"
-	 *
-	 * @param	string	the table name
-	 * @return	string
-	 */
-	protected function _truncate($table)
-	{
-		return 'TRUNCATE '.$table;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Delete statement
-	 *
-	 * Generates a platform-specific delete string from the supplied data
-	 *
-	 * @param	string	the table name
-	 * @param	array	the where clause
-	 * @param	string	the limit clause
-	 * @return	string
-	 */
-	protected function _delete($table, $where = array(), $like = array(), $limit = FALSE)
-	{
-		$conditions = '';
-
-		if (count($where) > 0 OR count($like) > 0)
-		{
-			$conditions = "\nWHERE ".implode("\n", $this->ar_where);
-
-			if (count($where) > 0 && count($like) > 0)
-			{
-				$conditions .= ' AND ';
-			}
-			$conditions .= implode("\n", $like);
-		}
-
-		return 'DELETE FROM '.$table.$conditions.( ! $limit ? '' : ' LIMIT '.$limit);
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
 	 * Limit string
 	 *
 	 * Generates a platform-specific LIMIT clause
@@ -680,15 +472,14 @@
 	/**
 	 * Close DB Connection
 	 *
-	 * @param	resource
 	 * @return	void
 	 */
-	protected function _close($conn_id)
+	protected function _close()
 	{
-		@mysql_close($conn_id);
+		@mysql_close($this->conn_id);
 	}
 
 }
 
 /* End of file mysql_driver.php */
-/* Location: ./system/database/drivers/mysql/mysql_driver.php */
+/* Location: ./system/database/drivers/mysql/mysql_driver.php */
\ No newline at end of file
diff --git a/system/database/drivers/mysql/mysql_forge.php b/system/database/drivers/mysql/mysql_forge.php
index d310713..d22454d 100644
--- a/system/database/drivers/mysql/mysql_forge.php
+++ b/system/database/drivers/mysql/mysql_forge.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -34,31 +34,7 @@
  */
 class CI_DB_mysql_forge extends CI_DB_forge {
 
-	/**
-	 * Create database
-	 *
-	 * @param	string	the database name
-	 * @return	string
-	 */
-	public function _create_database($name)
-	{
-		return 'CREATE DATABASE '.$name;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Drop database
-	 *
-	 * @param	string	the database name
-	 * @return	string
-	 */
-	public function _drop_database($name)
-	{
-		return 'DROP DATABASE '.$name;
-	}
-
-	// --------------------------------------------------------------------
+	protected $_create_database	= 'CREATE DATABASE %s CHARACTER SET %s COLLATE %s';
 
 	/**
 	 * Process Fields
@@ -66,7 +42,7 @@
 	 * @param	mixed	the fields
 	 * @return	string
 	 */
-	private function _process_fields($fields)
+	protected function _process_fields($fields)
 	{
 		$current_field_count = 0;
 		$sql = '';
@@ -84,8 +60,9 @@
 			{
 				$attributes = array_change_key_case($attributes, CASE_UPPER);
 
-				$sql .= "\n\t".$this->db->protect_identifiers($field)
-					.( ! empty($attributes['NAME']) ? ' '.$this->db->protect_identifiers($attributes['NAME']).' ' : '');
+				$sql .= "\n\t".$this->db->escape_identifiers($field);
+
+				empty($attributes['NAME']) OR ' '.$this->db->escape_identifiers($attributes['NAME']).' ';
 
 				if ( ! empty($attributes['TYPE']))
 				{
@@ -110,10 +87,23 @@
 					}
 				}
 
-				$sql .= (( ! empty($attributes['UNSIGNED']) && $attributes['UNSIGNED'] === TRUE) ? ' UNSIGNED' : '')
-					.(isset($attributes['DEFAULT']) ? " DEFAULT '".$attributes['DEFAULT']."'" : '')
-					.(( ! empty($attributes['NULL']) && $attributes['NULL'] === TRUE) ? ' NULL' : ' NOT NULL')
-					.(( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE) ? ' AUTO_INCREMENT' : '');
+				if ( ! empty($attributes['UNSIGNED']) && $attributes['UNSIGNED'] === TRUE)
+				{
+					$sql .= ' UNSIGNED';
+				}
+
+				if (isset($attributes['DEFAULT']))
+				{
+					$sql .= " DEFAULT '".$attributes['DEFAULT']."'";
+				}
+
+				$sql .= ( ! empty($attributes['NULL']) && $attributes['NULL'] === TRUE)
+					? ' NULL' : ' NOT NULL';
+
+				if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE)
+				{
+					$sql .= ' AUTO_INCREMENT';
+				}
 			}
 
 			// don't add a comma on the end of the last field
@@ -138,7 +128,7 @@
 	 * @param	bool	should 'IF NOT EXISTS' be added to the SQL
 	 * @return	bool
 	 */
-	public function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists)
+	protected function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists)
 	{
 		$sql = 'CREATE TABLE ';
 
@@ -147,12 +137,12 @@
 			$sql .= 'IF NOT EXISTS ';
 		}
 
-		$sql .= $this->db->_escape_identifiers($table).' ('.$this->_process_fields($fields);
+		$sql .= $this->db->escape_identifiers($table).' ('.$this->_process_fields($fields);
 
 		if (count($primary_keys) > 0)
 		{
-			$key_name = $this->db->_protect_identifiers(implode('_', $primary_keys));
-			$sql .= ",\n\tPRIMARY KEY ".$key_name.' ('.implode(', ', $this->db->protect_identifiers($primary_keys)).')';
+			$key_name = $this->db->escape_identifiers(implode('_', $primary_keys));
+			$sql .= ",\n\tPRIMARY KEY ".$key_name.' ('.implode(', ', $this->db->escape_identifiers($primary_keys)).')';
 		}
 
 		if (is_array($keys) && count($keys) > 0)
@@ -161,12 +151,12 @@
 			{
 				if (is_array($key))
 				{
-					$key_name = $this->db->_protect_identifiers(implode('_', $key));
-					$key = $this->db->_protect_identifiers($key);
+					$key_name = $this->db->escape_identifiers(implode('_', $key));
+					$key = $this->db->escape_identifiers($key);
 				}
 				else
 				{
-					$key_name = $this->db->_protect_identifiers($key);
+					$key_name = $this->db->escape_identifiers($key);
 					$key = array($key_name);
 				}
 
@@ -180,19 +170,6 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 * Drop Table
-	 *
-	 * @param	string	table name
-	 * @return	string
-	 */
-	public function _drop_table($table)
-	{
-		return 'DROP TABLE IF EXISTS '.$this->db->_escape_identifiers($table);
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
 	 * Alter table query
 	 *
 	 * Generates a platform-specific query so that a table can be altered
@@ -204,37 +181,21 @@
 	 * @param	string	the field after which we should add the new field
 	 * @return	string
 	 */
-	public function _alter_table($alter_type, $table, $fields, $after_field = '')
+	protected function _alter_table($alter_type, $table, $fields, $after_field = '')
 	{
-		$sql = 'ALTER TABLE '.$this->db->protect_identifiers($table).' '.$alter_type.' ';
+		$sql = 'ALTER TABLE '.$this->db->escape_identifiers($table).' '.$alter_type.' ';
 
 		// DROP has everything it needs now.
 		if ($alter_type === 'DROP')
 		{
-			return $sql.$this->db->protect_identifiers($fields);
+			return $sql.$this->db->escape_identifiers($fields);
 		}
 
 		return $sql.$this->_process_fields($fields)
-			.($after_field != '' ? ' AFTER '.$this->db->protect_identifiers($after_field) : '');
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Rename a table
-	 *
-	 * Generates a platform-specific query so that a table can be renamed
-	 *
-	 * @param	string	the old table name
-	 * @param	string	the new table name
-	 * @return	string
-	 */
-	public function _rename_table($table_name, $new_table_name)
-	{
-		return 'ALTER TABLE '.$this->db->protect_identifiers($table_name).' RENAME TO '.$this->db->protect_identifiers($new_table_name);
+			.($after_field !== '' ? ' AFTER '.$this->db->escape_identifiers($after_field) : '');
 	}
 
 }
 
 /* End of file mysql_forge.php */
-/* Location: ./system/database/drivers/mysql/mysql_forge.php */
+/* Location: ./system/database/drivers/mysql/mysql_forge.php */
\ No newline at end of file
diff --git a/system/database/drivers/mysql/mysql_result.php b/system/database/drivers/mysql/mysql_result.php
index 8f04a93..14d6d07 100644
--- a/system/database/drivers/mysql/mysql_result.php
+++ b/system/database/drivers/mysql/mysql_result.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -90,18 +90,14 @@
 	public function field_data()
 	{
 		$retval = array();
-		while ($field = mysql_fetch_object($this->result_id))
+		for ($i = 0, $c = $this->num_fields(); $i < $c; $i++)
 		{
-			preg_match('/([a-zA-Z]+)(\(\d+\))?/', $field->Type, $matches);
-
-			$F		= new stdClass();
-			$F->name	= $field->Field;
-			$F->type	= ( ! empty($matches[1])) ? $matches[1] : NULL;
-			$F->default	= $field->Default;
-			$F->max_length	= ( ! empty($matches[2])) ? preg_replace('/[^\d]/', '', $matches[2]) : NULL;
-			$F->primary_key = (int) ($field->Key === 'PRI');
-
-			$retval[] = $F;
+			$retval[$i]			= new stdClass();
+			$retval[$i]->name		= mysql_field_name($this->result_id, $i);
+			$retval[$i]->type		= mysql_field_type($this->result_id, $i);
+			$retval[$i]->max_length		= mysql_field_len($this->result_id, $i);
+			$retval[$i]->primary_key	= (strpos(mysql_field_flags($this->result_id, $i), 'primary_key') === FALSE) ? 0 : 1;
+			$retval[$i]->default		= '';
 		}
 
 		return $retval;
@@ -132,7 +128,7 @@
 	 * this internally before fetching results to make sure the
 	 * result set starts at zero
 	 *
-	 * @return	array
+	 * @return	bool
 	 */
 	protected function _data_seek($n = 0)
 	{
@@ -170,4 +166,4 @@
 }
 
 /* End of file mysql_result.php */
-/* Location: ./system/database/drivers/mysql/mysql_result.php */
+/* Location: ./system/database/drivers/mysql/mysql_result.php */
\ No newline at end of file
diff --git a/system/database/drivers/mysql/mysql_utility.php b/system/database/drivers/mysql/mysql_utility.php
index 0e7c18e..f0bbc66 100644
--- a/system/database/drivers/mysql/mysql_utility.php
+++ b/system/database/drivers/mysql/mysql_utility.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -34,54 +34,17 @@
  */
 class CI_DB_mysql_utility extends CI_DB_utility {
 
-	/**
-	 * List databases
-	 *
-	 * @return	string
-	 */
-	public function _list_databases()
-	{
-		return 'SHOW DATABASES';
-	}
+	protected $_list_databases	= 'SHOW DATABASES';
+	protected $_optimize_table	= 'OPTIMIZE TABLE %s';
+	protected $_repair_table	= 'REPAIR TABLE %s';
 
-	// --------------------------------------------------------------------
-
-	/**
-	 * Optimize table query
-	 *
-	 * Generates a platform-specific query so that a table can be optimized
-	 *
-	 * @param	string	the table name
-	 * @return	string
-	 */
-	public function _optimize_table($table)
-	{
-		return 'OPTIMIZE TABLE '.$this->db->_escape_identifiers($table);
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Repair table query
-	 *
-	 * Generates a platform-specific query so that a table can be repaired
-	 *
-	 * @param	string	the table name
-	 * @return	string
-	 */
-	public function _repair_table($table)
-	{
-		return 'REPAIR TABLE '.$this->db->_escape_identifiers($table);
-	}
-
-	// --------------------------------------------------------------------
 	/**
 	 * MySQL Export
 	 *
 	 * @param	array	Preferences
 	 * @return	mixed
 	 */
-	public function _backup($params = array())
+	protected function _backup($params = array())
 	{
 		if (count($params) === 0)
 		{
@@ -102,7 +65,7 @@
 			}
 
 			// Get the table schema
-			$query = $this->db->query('SHOW CREATE TABLE `'.$this->db->database.'`.`'.$table.'`');
+			$query = $this->db->query('SHOW CREATE TABLE '.$this->db->escape_identifiers($this->db->database.'.'.$table));
 
 			// No result means the table name was invalid
 			if ($query === FALSE)
@@ -113,9 +76,9 @@
 			// Write out the table schema
 			$output .= '#'.$newline.'# TABLE STRUCTURE FOR: '.$table.$newline.'#'.$newline.$newline;
 
-			if ($add_drop == TRUE)
+			if ($add_drop === TRUE)
 			{
-				$output .= 'DROP TABLE IF EXISTS '.$table.';'.$newline.$newline;
+				$output .= 'DROP TABLE IF EXISTS '.$this->db->protect_identifiers($table).';'.$newline.$newline;
 			}
 
 			$i = 0;
@@ -129,15 +92,15 @@
 			}
 
 			// If inserts are not needed we're done...
-			if ($add_insert == FALSE)
+			if ($add_insert === FALSE)
 			{
 				continue;
 			}
 
 			// Grab all the data from the current table
-			$query = $this->db->query('SELECT * FROM '.$table);
+			$query = $this->db->query('SELECT * FROM '.$this->db->protect_identifiers($table));
 
-			if ($query->num_rows() == 0)
+			if ($query->num_rows() === 0)
 			{
 				continue;
 			}
@@ -157,7 +120,7 @@
 							TRUE);
 
 				// Create a string of field names
-				$field_str .= '`'.$field->name.'`, ';
+				$field_str .= $this->db->escape_identifiers($field->name).', ';
 				$i++;
 			}
 
@@ -180,7 +143,7 @@
 					else
 					{
 						// Escape the data if it's not an integer
-						$val_str .= ($is_int[$i] == FALSE) ? $this->db->escape($v) : $v;
+						$val_str .= ($is_int[$i] === FALSE) ? $this->db->escape($v) : $v;
 					}
 
 					// Append a comma
@@ -192,15 +155,16 @@
 				$val_str = preg_replace('/, $/' , '', $val_str);
 
 				// Build the INSERT string
-				$output .= 'INSERT INTO '.$table.' ('.$field_str.') VALUES ('.$val_str.');'.$newline;
+				$output .= 'INSERT INTO '.$this->db->protect_identifiers($table).' ('.$field_str.') VALUES ('.$val_str.');'.$newline;
 			}
 
-			return $output.$newline.$newline;
+			$output .= $newline.$newline;
 		}
 
 		return $output;
 	}
+
 }
 
 /* End of file mysql_utility.php */
-/* Location: ./system/database/drivers/mysql/mysql_utility.php */
+/* Location: ./system/database/drivers/mysql/mysql_utility.php */
\ No newline at end of file
diff --git a/system/database/drivers/mysqli/mysqli_driver.php b/system/database/drivers/mysqli/mysqli_driver.php
index a79b2a4..d3fb77a 100644
--- a/system/database/drivers/mysqli/mysqli_driver.php
+++ b/system/database/drivers/mysqli/mysqli_driver.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -29,7 +29,7 @@
  * MySQLi Database Adapter Class
  *
  * Note: _DB is an extender class that the app controller
- * creates dynamically based on whether the active record
+ * creates dynamically based on whether the query builder
  * class is being used or not.
  *
  * @package		CodeIgniter
@@ -47,7 +47,7 @@
 
 	// clause and character used for LIKE escape sequences - not used in MySQL
 	protected $_like_escape_str = '';
-	protected $_like_escape_chr = '';
+	protected $_like_escape_chr = '\\';
 
 	/**
 	 * The syntax to count rows is slightly different across different
@@ -71,9 +71,9 @@
 	 */
 	public function db_connect()
 	{
-		return ($this->port != '')
-			? @mysqli_connect($this->hostname, $this->username, $this->password, $this->database, $this->port)
-			: @mysqli_connect($this->hostname, $this->username, $this->password, $this->database);
+		return empty($this->port)
+			? @new mysqli($this->hostname, $this->username, $this->password, $this->database)
+			: @new mysqli($this->hostname, $this->username, $this->password, $this->database, $this->port);
 	}
 
 	// --------------------------------------------------------------------
@@ -91,9 +91,9 @@
 			return $this->db_connect();
 		}
 
-		return ($this->port != '')
-			? @mysqli_connect('p:'.$this->hostname, $this->username, $this->password, $this->database, $this->port)
-			: @mysqli_connect('p:'.$this->hostname, $this->username, $this->password, $this->database);
+		return empty($this->port)
+			? @new mysqli('p:'.$this->hostname, $this->username, $this->password, $this->database)
+			: @new mysqli('p:'.$this->hostname, $this->username, $this->password, $this->database, $this->port);
 	}
 
 	// --------------------------------------------------------------------
@@ -108,7 +108,7 @@
 	 */
 	public function reconnect()
 	{
-		if (mysqli_ping($this->conn_id) === FALSE)
+		if ($this->conn_id !== FALSE && $this->conn_id->ping() === FALSE)
 		{
 			$this->conn_id = FALSE;
 		}
@@ -119,11 +119,23 @@
 	/**
 	 * Select the database
 	 *
+	 * @param	string	database name
 	 * @return	bool
 	 */
-	public function db_select()
+	public function db_select($database = '')
 	{
-		return @mysqli_select_db($this->conn_id, $this->database);
+		if ($database === '')
+		{
+			$database = $this->database;
+		}
+
+		if (@$this->conn_id->select_db($database))
+		{
+			$this->database = $database;
+			return TRUE;
+		}
+
+		return FALSE;
 	}
 
 	// --------------------------------------------------------------------
@@ -132,26 +144,25 @@
 	 * Set client character set
 	 *
 	 * @param	string
-	 * @param	string
 	 * @return	bool
 	 */
-	protected function _db_set_charset($charset, $collation)
+	protected function _db_set_charset($charset)
 	{
-		return function_exists('mysqli_set_charset')
-			? @mysqli_set_charset($this->conn_id, $charset)
-			: @mysqli_query($this->conn_id, "SET NAMES '".$this->escape_str($charset)."' COLLATE '".$this->escape_str($collation)."'");
+		return @$this->conn_id->set_charset($charset);
 	}
 
 	// --------------------------------------------------------------------
 
 	/**
-	 * Version number query string
+	 * Database version number
 	 *
 	 * @return	string
 	 */
-	protected function _version()
+	public function version()
 	{
-		return @mysqli_get_server_info($this->conn_id);
+		return isset($this->data_cache['version'])
+			? $this->data_cache['version']
+			: $this->data_cache['version'] = $this->conn_id->server_info;
 	}
 
 	// --------------------------------------------------------------------
@@ -164,7 +175,7 @@
 	 */
 	protected function _execute($sql)
 	{
-		return @mysqli_query($this->conn_id, $this->_prep_query($sql));
+		return @$this->conn_id->query($this->_prep_query($sql));
 	}
 
 	// --------------------------------------------------------------------
@@ -275,23 +286,14 @@
 			return $str;
 		}
 
-		if (function_exists('mysqli_real_escape_string') && is_object($this->conn_id))
-		{
-			$str = mysqli_real_escape_string($this->conn_id, $str);
-		}
-		elseif (function_exists('mysql_escape_string'))
-		{
-			$str = mysql_escape_string($str);
-		}
-		else
-		{
-			$str = addslashes($str);
-		}
+		$str = is_object($this->conn_id) ? $this->conn_id->real_escape_string($str) : addslashes($str);
 
 		// escape LIKE condition wildcards
 		if ($like === TRUE)
 		{
-			return str_replace(array('%', '_'), array('\\%', '\\_'), $str);
+			return str_replace(array($this->_like_escape_chr, '%', '_'),
+						array($this->_like_escape_chr.$this->_like_escape_chr, $this->_like_escape_chr.'%', $this->_like_escape_chr.'_'),
+						$str);
 		}
 
 		return $str;
@@ -306,7 +308,7 @@
 	 */
 	public function affected_rows()
 	{
-		return @mysqli_affected_rows($this->conn_id);
+		return $this->conn_id->affected_rows;
 	}
 
 	// --------------------------------------------------------------------
@@ -318,36 +320,7 @@
 	 */
 	public function insert_id()
 	{
-		return @mysqli_insert_id($this->conn_id);
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * "Count All" query
-	 *
-	 * Generates a platform-specific query string that counts all records in
-	 * the specified database
-	 *
-	 * @param	string
-	 * @return	string
-	 */
-	public function count_all($table = '')
-	{
-		if ($table == '')
-		{
-			return 0;
-		}
-
-		$query = $this->query($this->_count_string.$this->_protect_identifiers('numrows').' FROM '.$this->_protect_identifiers($table, TRUE, NULL, FALSE));
-		if ($query->num_rows() == 0)
-		{
-			return 0;
-		}
-
-		$query = $query->row();
-		$this->_reset_select();
-		return (int) $query->numrows;
+		return $this->conn_id->insert_id;
 	}
 
 	// --------------------------------------------------------------------
@@ -357,7 +330,6 @@
 	 *
 	 * Generates a platform-specific query string so that the table names can be fetched
 	 *
-	 * @access	private
 	 * @param	bool
 	 * @return	string
 	 */
@@ -365,7 +337,7 @@
 	{
 		$sql = 'SHOW TABLES FROM '.$this->_escape_char.$this->database.$this->_escape_char;
 
-		if ($prefix_limit !== FALSE && $this->dbprefix != '')
+		if ($prefix_limit !== FALSE && $this->dbprefix !== '')
 		{
 			return $sql." LIKE '".$this->escape_like_str($this->dbprefix)."%'";
 		}
@@ -385,183 +357,56 @@
 	 */
 	protected function _list_columns($table = '')
 	{
-		return 'SHOW COLUMNS FROM '.$this->_protect_identifiers($table, TRUE, NULL, FALSE);
+		return 'SHOW COLUMNS FROM '.$this->protect_identifiers($table, TRUE, NULL, FALSE);
 	}
 
 	// --------------------------------------------------------------------
 
 	/**
-	 * Field data query
-	 *
-	 * Generates a platform-specific query so that the column data can be retrieved
+	 * Returns an object with field data
 	 *
 	 * @param	string	the table name
-	 * @return	string
+	 * @return	object
 	 */
-	protected function _field_data($table)
+	public function field_data($table = '')
 	{
-		return 'DESCRIBE '.$table;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * The error message string
-	 *
-	 * @return	string
-	 */
-	protected function _error_message()
-	{
-		return mysqli_error($this->conn_id);
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * The error message number
-	 *
-	 * @return	int
-	 */
-	protected function _error_number()
-	{
-		return mysqli_errno($this->conn_id);
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Escape the SQL Identifiers
-	 *
-	 * This function escapes column and table names
-	 *
-	 * @param	string
-	 * @return	string
-	 */
-	public function _escape_identifiers($item)
-	{
-		if ($this->_escape_char == '')
+		if ($table === '')
 		{
-			return $item;
+			return ($this->db_debug) ? $this->display_error('db_field_param_missing') : FALSE;
 		}
 
-		foreach ($this->_reserved_identifiers as $id)
-		{
-			if (strpos($item, '.'.$id) !== FALSE)
-			{
-				$item = str_replace('.', $this->_escape_char.'.', $item);
+		$query = $this->query('DESCRIBE '.$this->protect_identifiers($table, TRUE, NULL, FALSE));
+		$query = $query->result_object();
 
-				// remove duplicates if the user already included the escape
-				return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $this->_escape_char.$item);
-			}
+		$retval = array();
+		for ($i = 0, $c = count($query); $i < $c; $i++)
+		{
+			preg_match('/([a-z]+)(\(\d+\))?/', $query[$i]->Type, $matches);
+
+			$retval[$i]			= new stdClass();
+			$retval[$i]->name		= $query[$i]->Field;
+			$retval[$i]->type		= empty($matches[1]) ? NULL : $matches[1];
+			$retval[$i]->default		= $query[$i]->Default;
+			$retval[$i]->max_length		= empty($matches[2]) ? NULL : preg_replace('/[^\d]/', '', $matches[2]);
+			$retval[$i]->primary_key	= (int) ($query[$i]->Key === 'PRI');
 		}
 
-		if (strpos($item, '.') !== FALSE)
-		{
-			$item = str_replace('.', $this->_escape_char.'.'.$this->_escape_char, $item);
-		}
-
-		// remove duplicates if the user already included the escape
-		return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $this->_escape_char.$item.$this->_escape_char);
+		return $retval;
 	}
 
 	// --------------------------------------------------------------------
 
 	/**
-	 * From Tables
+	 * Error
 	 *
-	 * This function implicitly groups FROM tables so there is no confusion
-	 * about operator precedence in harmony with SQL standards
+	 * Returns an array containing code and message of the last
+	 * database error that has occured.
 	 *
-	 * @param	string
-	 * @return	string
+	 * @return	array
 	 */
-	protected function _from_tables($tables)
+	public function error()
 	{
-		if ( ! is_array($tables))
-		{
-			$tables = array($tables);
-		}
-
-		return '('.implode(', ', $tables).')';
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Insert statement
-	 *
-	 * Generates a platform-specific insert string from the supplied data
-	 *
-	 * @param	string	the table name
-	 * @param	array	the insert keys
-	 * @param	array	the insert values
-	 * @return	string
-	 */
-	protected function _insert($table, $keys, $values)
-	{
-		return 'INSERT INTO '.$table.' ('.implode(', ', $keys).') VALUES ('.implode(', ', $values).')';
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Insert_batch statement
-	 *
-	 * Generates a platform-specific insert string from the supplied data
-	 *
-	 * @param	string	the table name
-	 * @param	array	the insert keys
-	 * @param	array	the insert values
-	 * @return	string
-	 */
-	protected function _insert_batch($table, $keys, $values)
-	{
-		return 'INSERT INTO '.$table.' ('.implode(', ', $keys).') VALUES '.implode(', ', $values);
-	}
-
-	// --------------------------------------------------------------------
-
-
-	/**
-	 * Replace statement
-	 *
-	 * Generates a platform-specific replace string from the supplied data
-	 *
-	 * @param	string	the table name
-	 * @param	array	the insert keys
-	 * @param	array	the insert values
-	 * @return	string
-	 */
-	protected function _replace($table, $keys, $values)
-	{
-		return 'REPLACE INTO '.$table.' ('.implode(', ', $keys).') VALUES ('.implode(', ', $values).')';
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Update statement
-	 *
-	 * Generates a platform-specific update string from the supplied data
-	 *
-	 * @param	string	the table name
-	 * @param	array	the update data
-	 * @param	array	the where clause
-	 * @param	array	the orderby clause
-	 * @param	array	the limit clause
-	 * @return	string
-	 */
-	protected function _update($table, $values, $where, $orderby = array(), $limit = FALSE)
-	{
-		foreach ($values as $key => $val)
-		{
-			$valstr[] = $key.' = '.$val;
-		}
-
-		return 'UPDATE '.$table.' SET '.implode(', ', $valstr)
-			.(($where != '' && count($where) > 0) ? ' WHERE '.implode(' ', $where) : '')
-			.(count($orderby) > 0 ? ' ORDER BY '.implode(', ', $orderby) : '')
-			.( ! $limit ? '' : ' LIMIT '.$limit);
+		return array('code' => $this->conn_id->errno, 'message' => $this->conn_id->error);
 	}
 
 	// --------------------------------------------------------------------
@@ -585,7 +430,7 @@
 
 			foreach (array_keys($val) as $field)
 			{
-				if ($field != $index)
+				if ($field !== $index)
 				{
 					$final[$field][] =  'WHEN '.$index.' = '.$val[$index].' THEN '.$val[$field];
 				}
@@ -600,62 +445,16 @@
 				.'ELSE '.$k.' END, ';
 		}
 
-		$where = ($where != '' && count($where) > 0) ? implode(' ', $where).' AND ' : '';
+		$where = ($where !== '' && count($where) > 0) ? implode(' ', $where).' AND ' : '';
 
 		return 'UPDATE '.$table.' SET '.substr($cases, 0, -2)
-			.' WHERE '.(($where != '' && count($where) > 0) ? implode(' ', $where).' AND ' : '')
+			.' WHERE '.(($where !== '' && count($where) > 0) ? implode(' ', $where).' AND ' : '')
 			.$index.' IN('.implode(',', $ids).')';
 	}
 
 	// --------------------------------------------------------------------
 
 	/**
-	 * Truncate statement
-	 *
-	 * Generates a platform-specific truncate string from the supplied data
-	 * If the database does not support the truncate() command
-	 * This function maps to "DELETE FROM table"
-	 *
-	 * @param	string	the table name
-	 * @return	string
-	 */
-	protected function _truncate($table)
-	{
-		return 'TRUNCATE '.$table;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Delete statement
-	 *
-	 * Generates a platform-specific delete string from the supplied data
-	 *
-	 * @param	string	the table name
-	 * @param	array	the where clause
-	 * @param	string	the limit clause
-	 * @return	string
-	 */
-	protected function _delete($table, $where = array(), $like = array(), $limit = FALSE)
-	{
-		$conditions = '';
-		if (count($where) > 0 OR count($like) > 0)
-		{
-			$conditions = "\nWHERE ".implode("\n", $this->ar_where);
-
-			if (count($where) > 0 && count($like) > 0)
-			{
-				$conditions .= ' AND ';
-			}
-			$conditions .= implode("\n", $like);
-		}
-
-		return 'DELETE FROM '.$table.$conditions.( ! $limit ? '' : ' LIMIT '.$limit);
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
 	 * Limit string
 	 *
 	 * Generates a platform-specific LIMIT clause
@@ -676,15 +475,14 @@
 	/**
 	 * Close DB Connection
 	 *
-	 * @param	object
 	 * @return	void
 	 */
-	protected function _close($conn_id)
+	protected function _close()
 	{
-		@mysqli_close($conn_id);
+		$this->conn_id->close();
 	}
 
 }
 
 /* End of file mysqli_driver.php */
-/* Location: ./system/database/drivers/mysqli/mysqli_driver.php */
+/* Location: ./system/database/drivers/mysqli/mysqli_driver.php */
\ No newline at end of file
diff --git a/system/database/drivers/mysqli/mysqli_forge.php b/system/database/drivers/mysqli/mysqli_forge.php
index 7de0361..b74c775 100644
--- a/system/database/drivers/mysqli/mysqli_forge.php
+++ b/system/database/drivers/mysqli/mysqli_forge.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -34,31 +34,7 @@
  */
 class CI_DB_mysqli_forge extends CI_DB_forge {
 
-	/**
-	 * Create database
-	 *
-	 * @param	string	the database name
-	 * @return	string
-	 */
-	public function _create_database($name)
-	{
-		return 'CREATE DATABASE '.$name;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Drop database
-	 *
-	 * @param	string	the database name
-	 * @return	string
-	 */
-	public function _drop_database($name)
-	{
-		return 'DROP DATABASE '.$name;
-	}
-
-	// --------------------------------------------------------------------
+	protected $_create_database	= 'CREATE DATABASE %s CHARACTER SET %s COLLATE %s';
 
 	/**
 	 * Process Fields
@@ -66,7 +42,7 @@
 	 * @param	mixed	the fields
 	 * @return	string
 	 */
-	public function _process_fields($fields)
+	protected function _process_fields($fields)
 	{
 		$current_field_count = 0;
 		$sql = '';
@@ -84,14 +60,50 @@
 			{
 				$attributes = array_change_key_case($attributes, CASE_UPPER);
 
-				$sql .= "\n\t".$this->db->protect_identifiers($field)
-					.( ! empty($attributes['NAME']) ? ' '.$this->db->protect_identifiers($attributes['NAME']).' ' : '')
-					.( ! empty($attributes['TYPE']) ? ' '.$attributes['TYPE'] : '')
-					.( ! empty($attributes['CONSTRAINT']) ? '('.$attributes['CONSTRAINT'].')' : '')
-					.(( ! empty($attributes['UNSIGNED']) && $attributes['UNSIGNED'] === TRUE) ? ' UNSIGNED' : '')
-					.(isset($attributes['DEFAULT']) ? " DEFAULT '".$attributes['DEFAULT']."'" : '')
-					.(( ! empty($attributes['NULL']) && $attributes['NULL'] === TRUE) ? ' NULL' : ' NOT NULL')
-					.(( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE) ? ' AUTO_INCREMENT' : '');
+				$sql .= "\n\t".$this->db->escape_identifiers($field);
+
+				empty($attributes['NAME']) OR $sql .= ' '.$this->db->escape_identifiers($attributes['NAME']).' ';
+
+				if ( ! empty($attributes['TYPE']))
+				{
+					$sql .= ' '.$attributes['TYPE'];
+
+					if ( ! empty($attributes['CONSTRAINT']))
+					{
+						switch (strtolower($attributes['TYPE']))
+						{
+							case 'decimal':
+							case 'float':
+							case 'numeric':
+								$sql .= '('.implode(',', $attributes['CONSTRAINT']).')';
+								break;
+							case 'enum':
+							case 'set':
+								$sql .= '("'.implode('","', $attributes['CONSTRAINT']).'")';
+								break;
+							default:
+								$sql .= '('.$attributes['CONSTRAINT'].')';
+						}
+					}
+				}
+
+				if ( ! empty($attributes['UNSIGNED']) && $attributes['UNSIGNED'] === TRUE)
+				{
+					$sql .= ' UNSIGNED';
+				}
+
+				if (isset($attributes['DEFAULT']))
+				{
+					$sql .= " DEFAULT '".$attributes['DEFAULT']."'";
+				}
+
+				$sql .= ( ! empty($attributes['NULL']) && $attributes['NULL'] === TRUE)
+					? ' NULL' : ' NOT NULL';
+
+				if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE)
+				{
+					$sql .= ' AUTO_INCREMENT';
+				}
 			}
 
 			// don't add a comma on the end of the last field
@@ -116,7 +128,7 @@
 	 * @param	bool	should 'IF NOT EXISTS' be added to the SQL
 	 * @return	bool
 	 */
-	public function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists)
+	protected function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists)
 	{
 		$sql = 'CREATE TABLE ';
 
@@ -125,12 +137,12 @@
 			$sql .= 'IF NOT EXISTS ';
 		}
 
-		$sql .= $this->db->_escape_identifiers($table).' ('.$this->_process_fields($fields);
+		$sql .= $this->db->escape_identifiers($table).' ('.$this->_process_fields($fields);
 
 		if (count($primary_keys) > 0)
 		{
-			$key_name = $this->db->protect_identifiers(implode('_', $primary_keys));
-			$sql .= ",\n\tPRIMARY KEY ".$key_name.' ('.implode(', ', $this->db->protect_identifiers($primary_keys)).')';
+			$key_name = $this->db->escape_identifiers(implode('_', $primary_keys));
+			$sql .= ",\n\tPRIMARY KEY ".$key_name.' ('.implode(', ', $this->db->escape_identifiers($primary_keys)).')';
 		}
 
 		if (is_array($keys) && count($keys) > 0)
@@ -139,12 +151,12 @@
 			{
 				if (is_array($key))
 				{
-					$key_name = $this->db->protect_identifiers(implode('_', $key));
-					$key = $this->db->protect_identifiers($key);
+					$key_name = $this->db->escape_identifiers(implode('_', $key));
+					$key = $this->db->escape_identifiers($key);
 				}
 				else
 				{
-					$key_name = $this->db->protect_identifiers($key);
+					$key_name = $this->db->escape_identifiers($key);
 					$key = array($key_name);
 				}
 
@@ -158,18 +170,6 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 * Drop Table
-	 *
-	 * @return	string
-	 */
-	public function _drop_table($table)
-	{
-		return 'DROP TABLE IF EXISTS '.$this->db->_escape_identifiers($table);
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
 	 * Alter table query
 	 *
 	 * Generates a platform-specific query so that a table can be altered
@@ -181,37 +181,21 @@
 	 * @param	string	the field after which we should add the new field
 	 * @return	string
 	 */
-	public function _alter_table($alter_type, $table, $fields, $after_field = '')
+	protected function _alter_table($alter_type, $table, $fields, $after_field = '')
 	{
-		$sql = 'ALTER TABLE '.$this->db->_protect_identifiers($table).' '.$alter_type.' ';
+		$sql = 'ALTER TABLE '.$this->db->escape_identifiers($table).' '.$alter_type.' ';
 
 		// DROP has everything it needs now.
 		if ($alter_type === 'DROP')
 		{
-			return $sql.$this->db->protect_identifiers($fields);
+			return $sql.$this->db->escape_identifiers($fields);
 		}
 
 		return $sql.$this->_process_fields($fields)
-			.($after_field != '' ? ' AFTER '.$this->db->protect_identifiers($after_field) : '');
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Rename a table
-	 *
-	 * Generates a platform-specific query so that a table can be renamed
-	 *
-	 * @param	string	the old table name
-	 * @param	string	the new table name
-	 * @return	string
-	 */
-	public function _rename_table($table_name, $new_table_name)
-	{
-		return 'ALTER TABLE '.$this->db->protect_identifiers($table_name).' RENAME TO '.$this->db->protect_identifiers($new_table_name);
+			.($after_field !== '' ? ' AFTER '.$this->db->escape_identifiers($after_field) : '');
 	}
 
 }
 
 /* End of file mysqli_forge.php */
-/* Location: ./system/database/drivers/mysqli/mysqli_forge.php */
+/* Location: ./system/database/drivers/mysqli/mysqli_forge.php */
\ No newline at end of file
diff --git a/system/database/drivers/mysqli/mysqli_result.php b/system/database/drivers/mysqli/mysqli_result.php
index 0a50ccc..9b4d494 100644
--- a/system/database/drivers/mysqli/mysqli_result.php
+++ b/system/database/drivers/mysqli/mysqli_result.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -43,7 +43,7 @@
 	 */
 	public function num_rows()
 	{
-		return @mysqli_num_rows($this->result_id);
+		return $this->result_id->num_rows;
 	}
 
 	// --------------------------------------------------------------------
@@ -55,7 +55,7 @@
 	 */
 	public function num_fields()
 	{
-		return @mysqli_num_fields($this->result_id);
+		return $this->result_id->field_count;
 	}
 
 	// --------------------------------------------------------------------
@@ -70,7 +70,7 @@
 	public function list_fields()
 	{
 		$field_names = array();
-		while ($field = mysqli_fetch_field($this->result_id))
+		while ($field = $this->result_id->fetch_field())
 		{
 			$field_names[] = $field->name;
 		}
@@ -90,18 +90,15 @@
 	public function field_data()
 	{
 		$retval = array();
-		while ($field = mysqli_fetch_object($this->result_id))
+		$field_data = $this->result_id->fetch_fields();
+		for ($i = 0, $c = count($field_data); $i < $c; $i++)
 		{
-			preg_match('/([a-zA-Z]+)(\(\d+\))?/', $field->Type, $matches);
-
-			$F		= new stdClass();
-			$F->name	= $field->Field;
-			$F->type	= ( ! empty($matches[1])) ? $matches[1] : NULL;
-			$F->default	= $field->Default;
-			$F->max_length	= ( ! empty($matches[2])) ? preg_replace('/[^\d]/', '', $matches[2]) : NULL;
-			$F->primary_key = (int) ($field->Key === 'PRI');
-
-			$retval[] = $F;
+			$retval[$i]			= new stdClass();
+			$retval[$i]->name		= $field_data[$i]->name;
+			$retval[$i]->type		= $field_data[$i]->type;
+			$retval[$i]->max_length		= $field_data[$i]->max_length;
+			$retval[$i]->primary_key	= (int) ($field_data[$i]->flags & 2);
+			$retval[$i]->default		= '';
 		}
 
 		return $retval;
@@ -118,7 +115,7 @@
 	{
 		if (is_object($this->result_id))
 		{
-			mysqli_free_result($this->result_id);
+			$this->result_id->free();
 			$this->result_id = FALSE;
 		}
 	}
@@ -128,15 +125,15 @@
 	/**
 	 * Data Seek
 	 *
-	 * Moves the internal pointer to the desired offset.  We call
+	 * Moves the internal pointer to the desired offset. We call
 	 * this internally before fetching results to make sure the
 	 * result set starts at zero
 	 *
-	 * @return	array
+	 * @return	bool
 	 */
 	protected function _data_seek($n = 0)
 	{
-		return mysqli_data_seek($this->result_id, $n);
+		return $this->result_id->data_seek($n);
 	}
 
 	// --------------------------------------------------------------------
@@ -150,7 +147,7 @@
 	 */
 	protected function _fetch_assoc()
 	{
-		return mysqli_fetch_assoc($this->result_id);
+		return $this->result_id->fetch_assoc();
 	}
 
 	// --------------------------------------------------------------------
@@ -164,10 +161,10 @@
 	 */
 	protected function _fetch_object()
 	{
-		return mysqli_fetch_object($this->result_id);
+		return $this->result_id->fetch_object();
 	}
 
 }
 
 /* End of file mysqli_result.php */
-/* Location: ./system/database/drivers/mysqli/mysqli_result.php */
+/* Location: ./system/database/drivers/mysqli/mysqli_result.php */
\ No newline at end of file
diff --git a/system/database/drivers/mysqli/mysqli_utility.php b/system/database/drivers/mysqli/mysqli_utility.php
index 3fdc5c7..5d2bdbc 100644
--- a/system/database/drivers/mysqli/mysqli_utility.php
+++ b/system/database/drivers/mysqli/mysqli_utility.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -34,47 +34,9 @@
  */
 class CI_DB_mysqli_utility extends CI_DB_utility {
 
-	/**
-	 * List databases
-	 *
-	 * @return	string
-	 */
-	public function _list_databases()
-	{
-		return 'SHOW DATABASES';
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Optimize table query
-	 *
-	 * Generates a platform-specific query so that a table can be optimized
-	 *
-	 * @param	string	the table name
-	 * @return	string
-	 */
-	public function _optimize_table($table)
-	{
-		return 'OPTIMIZE TABLE '.$this->db->_escape_identifiers($table);
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Repair table query
-	 *
-	 * Generates a platform-specific query so that a table can be repaired
-	 *
-	 * @param	string	the table name
-	 * @return	string
-	 */
-	public function _repair_table($table)
-	{
-		return 'REPAIR TABLE '.$this->db->_escape_identifiers($table);
-	}
-
-	// --------------------------------------------------------------------
+	protected $_list_databases	= 'SHOW DATABASES';
+	protected $_optimize_table	= 'OPTIMIZE TABLE %s';
+	protected $_repair_table	= 'REPAIR TABLE %s';
 
 	/**
 	 * MySQLi Export
@@ -82,12 +44,127 @@
 	 * @param	array	Preferences
 	 * @return	mixed
 	 */
-	public function _backup($params = array())
+	protected function _backup($params = array())
 	{
-		// Currently unsupported
-		return $this->db->display_error('db_unsuported_feature');
+		if (count($params) === 0)
+		{
+			return FALSE;
+		}
+
+		// Extract the prefs for simplicity
+		extract($params);
+
+		// Build the output
+		$output = '';
+		foreach ( (array) $tables as $table)
+		{
+			// Is the table in the "ignore" list?
+			if (in_array($table, (array) $ignore, TRUE))
+			{
+				continue;
+			}
+
+			// Get the table schema
+			$query = $this->db->query('SHOW CREATE TABLE '.$this->db->escape_identifiers($this->db->database.'.'.$table));
+
+			// No result means the table name was invalid
+			if ($query === FALSE)
+			{
+				continue;
+			}
+
+			// Write out the table schema
+			$output .= '#'.$newline.'# TABLE STRUCTURE FOR: '.$table.$newline.'#'.$newline.$newline;
+
+			if ($add_drop === TRUE)
+			{
+				$output .= 'DROP TABLE IF EXISTS '.$this->db->protect_identifiers($table).';'.$newline.$newline;
+			}
+
+			$i = 0;
+			$result = $query->result_array();
+			foreach ($result[0] as $val)
+			{
+				if ($i++ % 2)
+				{
+					$output .= $val.';'.$newline.$newline;
+				}
+			}
+
+			// If inserts are not needed we're done...
+			if ($add_insert === FALSE)
+			{
+				continue;
+			}
+
+			// Grab all the data from the current table
+			$query = $this->db->query('SELECT * FROM '.$this->db->protect_identifiers($table));
+
+			if ($query->num_rows() === 0)
+			{
+				continue;
+			}
+
+			// Fetch the field names and determine if the field is an
+			// integer type. We use this info to decide whether to
+			// surround the data with quotes or not
+
+			$i = 0;
+			$field_str = '';
+			$is_int = array();
+			while ($field = $query->result_id->fetch_field())
+			{
+				// Most versions of MySQL store timestamp as a string
+				$is_int[$i] = in_array(strtolower($field->type),
+							array('tinyint', 'smallint', 'mediumint', 'int', 'bigint'), //, 'timestamp'),
+							TRUE);
+
+				// Create a string of field names
+				$field_str .= $this->db->escape_identifiers($field->name).', ';
+				$i++;
+			}
+
+			// Trim off the end comma
+			$field_str = preg_replace('/, $/' , '', $field_str);
+
+			// Build the insert string
+			foreach ($query->result_array() as $row)
+			{
+				$val_str = '';
+
+				$i = 0;
+				foreach ($row as $v)
+				{
+					// Is the value NULL?
+					if ($v === NULL)
+					{
+						$val_str .= 'NULL';
+					}
+					else
+					{
+						// Escape the data if it's not an integer
+						$val_str .= ($is_int[$i] === FALSE) ? $this->db->escape($v) : $v;
+					}
+
+					// Append a comma
+					$val_str .= ', ';
+					$i++;
+				}
+
+				// Remove the comma at the end of the string
+				$val_str = preg_replace('/, $/' , '', $val_str);
+
+				// Build the INSERT string
+				$output .= 'INSERT INTO '.$this->db->protect_identifiers($table).' ('.$field_str.') VALUES ('.$val_str.');'.$newline;
+			}
+
+			$output .= $newline.$newline;
+		}
+
+		return $output;
 	}
+
 }
 
 /* End of file mysqli_utility.php */
-/* Location: ./system/database/drivers/mysqli/mysqli_utility.php */
+/* Location: ./system/database/drivers/mysqli/mysqli_utility.php */
\ No newline at end of file
diff --git a/system/database/drivers/oci8/oci8_driver.php b/system/database/drivers/oci8/oci8_driver.php
index c662190..e780916 100644
--- a/system/database/drivers/oci8/oci8_driver.php
+++ b/system/database/drivers/oci8/oci8_driver.php
@@ -1,13 +1,13 @@
-<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
- * 
+ *
  * Licensed under the Open Software License version 3.0
- * 
+ *
  * This source file is subject to the Open Software License (OSL 3.0) that is
  * bundled with this package in the files license.txt / license.rst.  It is
  * also available through the world wide web at this URL:
@@ -25,13 +25,11 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * oci8 Database Adapter Class
  *
  * Note: _DB is an extender class that the app controller
- * creates dynamically based on whether the active record
+ * creates dynamically based on whether the query builder
  * class is being used or not.
  *
  * @package		CodeIgniter
@@ -48,48 +46,126 @@
  * permit access to oracle databases
  *
  * @author	  Kelly McArdle
- *
  */
-
 class CI_DB_oci8_driver extends CI_DB {
 
-	var $dbdriver = 'oci8';
+	public $dbdriver = 'oci8';
 
 	// The character used for excaping
-	var $_escape_char = '"';
+	protected $_escape_char = '"';
 
 	// clause and character used for LIKE escape sequences
-	var $_like_escape_str = " escape '%s' ";
-	var $_like_escape_chr = '!';
+	protected $_like_escape_str = " ESCAPE '%s' ";
+	protected $_like_escape_chr = '!';
 
 	/**
 	 * The syntax to count rows is slightly different across different
 	 * database engines, so this string appears in each driver and is
 	 * used for the count_all() and count_all_results() functions.
 	 */
-	var $_count_string = "SELECT COUNT(1) AS ";
-	var $_random_keyword = ' ASC'; // not currently supported
+	protected $_count_string = 'SELECT COUNT(1) AS ';
+	protected $_random_keyword = ' ASC'; // not currently supported
 
 	// Set "auto commit" by default
-	var $_commit = OCI_COMMIT_ON_SUCCESS;
+	public $commit_mode = OCI_COMMIT_ON_SUCCESS;
 
 	// need to track statement id and cursor id
-	var $stmt_id;
-	var $curs_id;
+	public $stmt_id;
+	public $curs_id;
 
 	// if we use a limit, we will add a field that will
 	// throw off num_fields later
-	var $limit_used;
+	public $limit_used;
+
+	public function __construct($params)
+	{
+		parent::__construct($params);
+
+		$valid_dsns = array(
+					'tns'	=> '/^\(DESCRIPTION=(\(.+\)){2,}\)$/', // TNS
+					// Easy Connect string (Oracle 10g+)
+					'ec'	=> '/^(\/\/)?[a-z0-9.:_-]+(:[1-9][0-9]{0,4})?(\/[a-z0-9$_]+)?(:[^\/])?(\/[a-z0-9$_]+)?$/i',
+					'in'	=> '/^[a-z0-9$_]+$/i' // Instance name (defined in tnsnames.ora)
+				);
+
+		/* Space characters don't have any effect when actually
+		 * connecting, but can be a hassle while validating the DSN.
+		 */
+		$this->dsn = str_replace(array("\n", "\r", "\t", ' '), '', $this->dsn);
+
+		if ($this->dsn !== '')
+		{
+			foreach ($valid_dsns as $regexp)
+			{
+				if (preg_match($regexp, $this->dsn))
+				{
+					return;
+				}
+			}
+		}
+
+		// Legacy support for TNS in the hostname configuration field
+		$this->hostname = str_replace(array("\n", "\r", "\t", ' '), '', $this->hostname);
+		if (preg_match($valid_dsns['tns'], $this->hostname))
+		{
+			$this->dsn = $this->hostname;
+			return;
+		}
+		elseif ($this->hostname !== '' && strpos($this->hostname, '/') === FALSE && strpos($this->hostname, ':') === FALSE
+			&& (( ! empty($this->port) && ctype_digit($this->port)) OR $this->database !== ''))
+		{
+			/* If the hostname field isn't empty, doesn't contain
+			 * ':' and/or '/' and if port and/or database aren't
+			 * empty, then the hostname field is most likely indeed
+			 * just a hostname. Therefore we'll try and build an
+			 * Easy Connect string from these 3 settings, assuming
+			 * that the database field is a service name.
+			 */
+			$this->dsn = $this->hostname
+					.(( ! empty($this->port) && ctype_digit($this->port)) ? ':'.$this->port : '')
+					.($this->database !== '' ? '/'.ltrim($this->database, '/') : '');
+
+			if (preg_match($valid_dsns['ec'], $this->dsn))
+			{
+				return;
+			}
+		}
+
+		/* At this point, we can only try and validate the hostname and
+		 * database fields separately as DSNs.
+		 */
+		if (preg_match($valid_dsns['ec'], $this->hostname) OR preg_match($valid_dsns['in'], $this->hostname))
+		{
+			$this->dsn = $this->hostname;
+			return;
+		}
+
+		$this->database = str_replace(array("\n", "\r", "\t", ' '), '', $this->database);
+		foreach ($valid_dsns as $regexp)
+		{
+			if (preg_match($regexp, $this->database))
+			{
+				return;
+			}
+		}
+
+		/* Well - OK, an empty string should work as well.
+		 * PHP will try to use environment variables to
+		 * determine which Oracle instance to connect to.
+		 */
+		$this->dsn = '';
+	}
 
 	/**
 	 * Non-persistent database connection
 	 *
-	 * @access  private called by the base class
-	 * @return  resource
+	 * @return	resource
 	 */
 	public function db_connect()
 	{
-		return @oci_connect($this->username, $this->password, $this->hostname, $this->char_set);
+		return ( ! empty($this->char_set))
+			? @oci_connect($this->username, $this->password, $this->dsn, $this->char_set)
+			: @oci_connect($this->username, $this->password, $this->dsn);
 	}
 
 	// --------------------------------------------------------------------
@@ -97,72 +173,27 @@
 	/**
 	 * Persistent database connection
 	 *
-	 * @access  private called by the base class
-	 * @return  resource
+	 * @return	resource
 	 */
 	public function db_pconnect()
 	{
-		return @oci_pconnect($this->username, $this->password, $this->hostname, $this->char_set);
+		return ( ! empty($this->char_set))
+			? @oci_pconnect($this->username, $this->password, $this->dsn, $this->char_set)
+			: @oci_pconnect($this->username, $this->password, $this->dsn);
 	}
 
 	// --------------------------------------------------------------------
 
 	/**
-	 * Reconnect
+	 * Database version number
 	 *
-	 * Keep / reestablish the db connection if no queries have been
-	 * sent for a length of time exceeding the server's idle timeout
-	 *
-	 * @access	public
-	 * @return	void
+	 * @return	string
 	 */
-	public function reconnect()
+	public function version()
 	{
-		// not implemented in oracle
-		return;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Select the database
-	 *
-	 * @access  private called by the base class
-	 * @return  resource
-	 */
-	public function db_select()
-	{
-		// Not in Oracle - schemas are actually usernames
-		return TRUE;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Set client character set
-	 *
-	 * @access	public
-	 * @param	string
-	 * @param	string
-	 * @return	resource
-	 */
-	public function db_set_charset($charset, $collation)
-	{
-		// this is done upon connect
-		return TRUE;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Version number query string
-	 *
-	 * @access  protected
-	 * @return  string
-	 */
-	protected function _version()
-	{
-		return oci_server_version($this->conn_id);
+		return isset($this->data_cache['version'])
+			? $this->data_cache['version']
+			: $this->data_cache['version'] = oci_server_version($this->conn_id);
 	}
 
 	// --------------------------------------------------------------------
@@ -170,63 +201,44 @@
 	/**
 	 * Execute the query
 	 *
-	 * @access  protected  called by the base class
-	 * @param   string  an SQL query
-	 * @return  resource
+	 * @param	string	an SQL query
+	 * @return	resource
 	 */
 	protected function _execute($sql)
 	{
-		// oracle must parse the query before it is run. All of the actions with
-		// the query are based on the statement id returned by ociparse
+		/* Oracle must parse the query before it is run. All of the actions with
+		 * the query are based on the statement id returned by oci_parse().
+		 */
 		$this->stmt_id = FALSE;
 		$this->_set_stmt_id($sql);
 		oci_set_prefetch($this->stmt_id, 1000);
-		return @oci_execute($this->stmt_id, $this->_commit);
+		return @oci_execute($this->stmt_id, $this->commit_mode);
 	}
 
 	/**
 	 * Generate a statement ID
 	 *
-	 * @access  private
-	 * @param   string  an SQL query
-	 * @return  none
+	 * @param	string	an SQL query
+	 * @return	void
 	 */
-	private function _set_stmt_id($sql)
+	protected function _set_stmt_id($sql)
 	{
 		if ( ! is_resource($this->stmt_id))
 		{
-			$this->stmt_id = oci_parse($this->conn_id, $this->_prep_query($sql));
+			$this->stmt_id = oci_parse($this->conn_id, $sql);
 		}
 	}
 
 	// --------------------------------------------------------------------
 
 	/**
-	 * Prep the query
+	 * Get cursor. Returns a cursor from the database
 	 *
-	 * If needed, each database adapter can prep the query string
-	 *
-	 * @access  private called by execute()
-	 * @param   string  an SQL query
-	 * @return  string
-	 */
-	private function _prep_query($sql)
-	{
-		return $sql;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * getCursor.  Returns a cursor from the datbase
-	 *
-	 * @access  public
-	 * @return  cursor id
+	 * @return	cursor id
 	 */
 	public function get_cursor()
 	{
-		$this->curs_id = oci_new_cursor($this->conn_id);
-		return $this->curs_id;
+		return $this->curs_id = oci_new_cursor($this->conn_id);
 	}
 
 	// --------------------------------------------------------------------
@@ -234,24 +246,23 @@
 	/**
 	 * Stored Procedure.  Executes a stored procedure
 	 *
-	 * @access  public
-	 * @param   package	 package stored procedure is in
-	 * @param   procedure   stored procedure to execute
-	 * @param   params	  array of parameters
-	 * @return  array
+	 * @param	string	package name in which the stored procedure is in
+	 * @param	string	stored procedure name to execute
+	 * @param	array	parameters
+	 * @return	mixed
 	 *
 	 * params array keys
 	 *
 	 * KEY	  OPTIONAL	NOTES
-	 * name		no		the name of the parameter should be in :<param_name> format
-	 * value	no		the value of the parameter.  If this is an OUT or IN OUT parameter,
-	 *					this should be a reference to a variable
-	 * type		yes		the type of the parameter
-	 * length	yes		the max size of the parameter
+	 * name		no	the name of the parameter should be in :<param_name> format
+	 * value	no	the value of the parameter.  If this is an OUT or IN OUT parameter,
+	 *				this should be a reference to a variable
+	 * type		yes	the type of the parameter
+	 * length	yes	the max size of the parameter
 	 */
 	public function stored_procedure($package, $procedure, $params)
 	{
-		if ($package == '' OR $procedure == '' OR ! is_array($params))
+		if ($package === '' OR $procedure === '' OR ! is_array($params))
 		{
 			if ($this->db_debug)
 			{
@@ -262,24 +273,24 @@
 		}
 
 		// build the query string
-		$sql = "begin $package.$procedure(";
+		$sql = 'BEGIN '.$package.'.'.$procedure.'(';
 
 		$have_cursor = FALSE;
 		foreach ($params as $param)
 		{
-			$sql .= $param['name'] . ",";
+			$sql .= $param['name'].',';
 
-			if (array_key_exists('type', $param) && ($param['type'] === OCI_B_CURSOR))
+			if (isset($param['type']) && $param['type'] === OCI_B_CURSOR)
 			{
 				$have_cursor = TRUE;
 			}
 		}
-		$sql = trim($sql, ",") . "); end;";
+		$sql = trim($sql, ',') . '); END;';
 
 		$this->stmt_id = FALSE;
 		$this->_set_stmt_id($sql);
 		$this->_bind_params($params);
-		$this->query($sql, FALSE, $have_cursor);
+		return $this->query($sql, FALSE, $have_cursor);
 	}
 
 	// --------------------------------------------------------------------
@@ -287,10 +298,9 @@
 	/**
 	 * Bind parameters
 	 *
-	 * @access  private
-	 * @return  none
+	 * @return	void
 	 */
-	private function _bind_params($params)
+	protected function _bind_params($params)
 	{
 		if ( ! is_array($params) OR ! is_resource($this->stmt_id))
 		{
@@ -316,7 +326,6 @@
 	/**
 	 * Begin Transaction
 	 *
-	 * @access	public
 	 * @return	bool
 	 */
 	public function trans_begin($test_mode = FALSE)
@@ -337,7 +346,7 @@
 		// even if the queries produce a successful result.
 		$this->_trans_failure = ($test_mode === TRUE) ? TRUE : FALSE;
 
-		$this->_commit = OCI_DEFAULT;
+		$this->commit_mode = (is_php('5.3.2')) ? OCI_NO_AUTO_COMMIT : OCI_DEFAULT;
 		return TRUE;
 	}
 
@@ -346,7 +355,6 @@
 	/**
 	 * Commit Transaction
 	 *
-	 * @access	public
 	 * @return	bool
 	 */
 	public function trans_commit()
@@ -362,9 +370,8 @@
 			return TRUE;
 		}
 
-		$ret = oci_commit($this->conn_id);
-		$this->_commit = OCI_COMMIT_ON_SUCCESS;
-		return $ret;
+		$this->commit_mode = OCI_COMMIT_ON_SUCCESS;
+		return oci_commit($this->conn_id);
 	}
 
 	// --------------------------------------------------------------------
@@ -372,25 +379,18 @@
 	/**
 	 * Rollback Transaction
 	 *
-	 * @access	public
 	 * @return	bool
 	 */
 	public function trans_rollback()
 	{
-		if ( ! $this->trans_enabled)
-		{
-			return TRUE;
-		}
-
 		// When transactions are nested we only begin/commit/rollback the outermost ones
-		if ($this->_trans_depth > 0)
+		if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
 		{
 			return TRUE;
 		}
 
-		$ret = oci_rollback($this->conn_id);
-		$this->_commit = OCI_COMMIT_ON_SUCCESS;
-		return $ret;
+		$this->commit_mode = OCI_COMMIT_ON_SUCCESS;
+		return oci_rollback($this->conn_id);
 	}
 
 	// --------------------------------------------------------------------
@@ -398,10 +398,9 @@
 	/**
 	 * Escape String
 	 *
-	 * @access  public
-	 * @param   string
+	 * @param	string
 	 * @param	bool	whether or not the string will be used in a LIKE condition
-	 * @return  string
+	 * @return	string
 	 */
 	public function escape_str($str, $like = FALSE)
 	{
@@ -415,15 +414,14 @@
 			return $str;
 		}
 
-		$str = remove_invisible_characters($str);
-		$str = str_replace("'", "''", $str);
+		$str = str_replace("'", "''", remove_invisible_characters($str));
 
 		// escape LIKE condition wildcards
 		if ($like === TRUE)
 		{
-			$str = str_replace(	array('%', '_', $this->_like_escape_chr),
-								array($this->_like_escape_chr.'%', $this->_like_escape_chr.'_', $this->_like_escape_chr.$this->_like_escape_chr),
-								$str);
+			return str_replace(array($this->_like_escape_chr, '%', '_'),
+						array($this->_like_escape_chr.$this->_like_escape_chr, $this->_like_escape_chr.'%', $this->_like_escape_chr.'_'),
+						$str);
 		}
 
 		return $str;
@@ -434,8 +432,7 @@
 	/**
 	 * Affected Rows
 	 *
-	 * @access  public
-	 * @return  integer
+	 * @return	int
 	 */
 	public function affected_rows()
 	{
@@ -447,8 +444,7 @@
 	/**
 	 * Insert ID
 	 *
-	 * @access  public
-	 * @return  integer
+	 * @return	int
 	 */
 	public function insert_id()
 	{
@@ -459,52 +455,20 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 * "Count All" query
-	 *
-	 * Generates a platform-specific query string that counts all records in
-	 * the specified database
-	 *
-	 * @access  public
-	 * @param   string
-	 * @return  string
-	 */
-	public function count_all($table = '')
-	{
-		if ($table == '')
-		{
-			return 0;
-		}
-
-		$query = $this->query($this->_count_string . $this->_protect_identifiers('numrows') . " FROM " . $this->_protect_identifiers($table, TRUE, NULL, FALSE));
-
-		if ($query == FALSE)
-		{
-			return 0;
-		}
-
-		$row = $query->row();
-		$this->_reset_select();
-		return (int) $row->numrows;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
 	 * Show table query
 	 *
 	 * Generates a platform-specific query string so that the table names can be fetched
 	 *
-	 * @access	protected
-	 * @param	boolean
+	 * @param	bool
 	 * @return	string
 	 */
 	protected function _list_tables($prefix_limit = FALSE)
 	{
-		$sql = "SELECT TABLE_NAME FROM ALL_TABLES";
+		$sql = 'SELECT TABLE_NAME FROM ALL_TABLES';
 
-		if ($prefix_limit !== FALSE AND $this->dbprefix != '')
+		if ($prefix_limit !== FALSE && $this->dbprefix !== '')
 		{
-			$sql .= " WHERE TABLE_NAME LIKE '".$this->escape_like_str($this->dbprefix)."%' ".sprintf($this->_like_escape_str, $this->_like_escape_chr);
+			return $sql." WHERE TABLE_NAME LIKE '".$this->escape_like_str($this->dbprefix)."%' ".sprintf($this->_like_escape_str, $this->_like_escape_chr);
 		}
 
 		return $sql;
@@ -517,13 +481,12 @@
 	 *
 	 * Generates a platform-specific query string so that the column names can be fetched
 	 *
-	 * @access  protected
-	 * @param   string  the table name
-	 * @return  string
+	 * @param	string	the table name
+	 * @return	string
 	 */
 	protected function _list_columns($table = '')
 	{
-		return "SELECT COLUMN_NAME FROM all_tab_columns WHERE table_name = '$table'";
+		return 'SELECT COLUMN_NAME FROM all_tab_columns WHERE table_name = \''.$table.'\'';
 	}
 
 	// --------------------------------------------------------------------
@@ -533,85 +496,43 @@
 	 *
 	 * Generates a platform-specific query so that the column data can be retrieved
 	 *
-	 * @access  public
-	 * @param   string  the table name
-	 * @return  object
+	 * @param	string	the table name
+	 * @return	string
 	 */
 	protected function _field_data($table)
 	{
-		return "SELECT * FROM ".$table." where rownum = 1";
+		return 'SELECT * FROM '.$table.' WHERE rownum = 1';
 	}
 
 	// --------------------------------------------------------------------
 
 	/**
-	 * The error message string
+	 * Error
 	 *
-	 * @access  protected
-	 * @return  string
+	 * Returns an array containing code and message of the last
+	 * database error that has occured.
+	 *
+	 * @return	array
 	 */
-	protected function _error_message()
+	public function error()
 	{
-		// If the error was during connection, no conn_id should be passed
-		$error = is_resource($this->conn_id) ? oci_error($this->conn_id) : oci_error();
-		return $error['message'];
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * The error message number
-	 *
-	 * @access  protected
-	 * @return  integer
-	 */
-	protected function _error_number()
-	{
-		// Same as _error_message()
-		$error = is_resource($this->conn_id) ? oci_error($this->conn_id) : oci_error();
-		return $error['code'];
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Escape the SQL Identifiers
-	 *
-	 * This function escapes column and table names
-	 *
-	 * @access	protected
-	 * @param	string
-	 * @return	string
-	 */
-	protected function _escape_identifiers($item)
-	{
-		if ($this->_escape_char == '')
+		/* oci_error() returns an array that already contains the
+		 * 'code' and 'message' keys, so we can just return it.
+		 */
+		if (is_resource($this->curs_id))
 		{
-			return $item;
+			return oci_error($this->curs_id);
+		}
+		elseif (is_resource($this->stmt_id))
+		{
+			return oci_error($this->stmt_id);
+		}
+		elseif (is_resource($this->conn_id))
+		{
+			return oci_error($this->conn_id);
 		}
 
-		foreach ($this->_reserved_identifiers as $id)
-		{
-			if (strpos($item, '.'.$id) !== FALSE)
-			{
-				$str = $this->_escape_char. str_replace('.', $this->_escape_char.'.', $item);
-
-				// remove duplicates if the user already included the escape
-				return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str);
-			}
-		}
-
-		if (strpos($item, '.') !== FALSE)
-		{
-			$str = $this->_escape_char.str_replace('.', $this->_escape_char.'.'.$this->_escape_char, $item).$this->_escape_char;
-		}
-		else
-		{
-			$str = $this->_escape_char.$item.$this->_escape_char;
-		}
-
-		// remove duplicates if the user already included the escape
-		return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str);
+		return oci_error();
 	}
 
 	// --------------------------------------------------------------------
@@ -622,36 +543,12 @@
 	 * This function implicitly groups FROM tables so there is no confusion
 	 * about operator precedence in harmony with SQL standards
 	 *
-	 * @access	protected
-	 * @param	type
-	 * @return	type
+	 * @param	array
+	 * @return	string
 	 */
 	protected function _from_tables($tables)
 	{
-		if ( ! is_array($tables))
-		{
-			$tables = array($tables);
-		}
-
-		return implode(', ', $tables);
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Insert statement
-	 *
-	 * Generates a platform-specific insert string from the supplied data
-	 *
-	 * @access  public
-	 * @param   string  the table name
-	 * @param   array   the insert keys
-	 * @param   array   the insert values
-	 * @return  string
-	 */
-	protected function _insert($table, $keys, $values)
-	{
-		return "INSERT INTO ".$table." (".implode(', ', $keys).") VALUES (".implode(', ', $values).")";
+		return is_array($tables) ? implode(', ', $tables) : $tables;
 	}
 
 	// --------------------------------------------------------------------
@@ -661,10 +558,10 @@
 	 *
 	 * Generates a platform-specific insert string from the supplied data
 	 *
-	 * @param	string  the table name
-	 * @param	array   the insert keys
-	 * @param 	array   the insert values
-	 * @return 	string
+	 * @param	string	the table name
+	 * @param	array	the insert keys
+	 * @param 	array	the insert values
+	 * @return	string
 	 */
 	protected function _insert_batch($table, $keys, $values)
 	{
@@ -673,47 +570,10 @@
 
 		for ($i = 0, $c = count($values); $i < $c; $i++)
 		{
-			$sql .= '	INTO ' . $table . ' (' . $keys . ') VALUES ' . $values[$i] . "\n";
+			$sql .= '	INTO '.$table.' ('.$keys.') VALUES '.$values[$i]."\n";
 		}
 
-		$sql .= 'SELECT * FROM dual';
-
-		return $sql;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Update statement
-	 *
-	 * Generates a platform-specific update string from the supplied data
-	 *
-	 * @access	protected
-	 * @param	string	the table name
-	 * @param	array	the update data
-	 * @param	array	the where clause
-	 * @param	array	the orderby clause
-	 * @param	array	the limit clause
-	 * @return	string
-	 */
-	protected function _update($table, $values, $where, $orderby = array(), $limit = FALSE)
-	{
-		foreach ($values as $key => $val)
-		{
-			$valstr[] = $key." = ".$val;
-		}
-
-		$limit = ( ! $limit) ? '' : ' LIMIT '.$limit;
-
-		$orderby = (count($orderby) >= 1)?' ORDER BY '.implode(", ", $orderby):'';
-
-		$sql = "UPDATE ".$table." SET ".implode(', ', $valstr);
-
-		$sql .= ($where != '' AND count($where) >=1) ? " WHERE ".implode(" ", $where) : '';
-
-		$sql .= $orderby.$limit;
-
-		return $sql;
+		return $sql.'SELECT * FROM dual';
 	}
 
 	// --------------------------------------------------------------------
@@ -722,16 +582,16 @@
 	 * Truncate statement
 	 *
 	 * Generates a platform-specific truncate string from the supplied data
-	 * If the database does not support the truncate() command
-	 * This function maps to "DELETE FROM table"
 	 *
-	 * @access	protected
+	 * If the database does not support the truncate() command,
+	 * then this method maps to 'DELETE FROM table'
+	 *
 	 * @param	string	the table name
 	 * @return	string
 	 */
 	protected function _truncate($table)
 	{
-		return "TRUNCATE TABLE ".$table;
+		return 'TRUNCATE TABLE '.$table;
 	}
 
 	// --------------------------------------------------------------------
@@ -741,31 +601,21 @@
 	 *
 	 * Generates a platform-specific delete string from the supplied data
 	 *
-	 * @access	protected
 	 * @param	string	the table name
 	 * @param	array	the where clause
+	 * @param	array	the like clause
 	 * @param	string	the limit clause
 	 * @return	string
 	 */
 	protected function _delete($table, $where = array(), $like = array(), $limit = FALSE)
 	{
-		$conditions = '';
+		$conditions = array();
 
-		if (count($where) > 0 OR count($like) > 0)
-		{
-			$conditions = "\nWHERE ";
-			$conditions .= implode("\n", $this->ar_where);
+		empty($where) OR $conditions[] = implode(' ', $where);
+		empty($like) OR $conditions[] = implode(' ', $like);
+		empty($limit) OR $conditions[] = 'rownum <= '.$limit;
 
-			if (count($where) > 0 && count($like) > 0)
-			{
-				$conditions .= " AND ";
-			}
-			$conditions .= implode("\n", $like);
-		}
-
-		$limit = ( ! $limit) ? '' : ' LIMIT '.$limit;
-
-		return "DELETE FROM ".$table.$conditions.$limit;
+		return 'DELETE FROM '.$table.(count($conditions) > 0 ? ' WHERE '.implode(' AND ', $conditions) : '');
 	}
 
 	// --------------------------------------------------------------------
@@ -775,26 +625,16 @@
 	 *
 	 * Generates a platform-specific LIMIT clause
 	 *
-	 * @access  protected
-	 * @param   string  the sql query string
-	 * @param   integer the number of rows to limit the query to
-	 * @param   integer the offset value
-	 * @return  string
+	 * @param	string	the sql query string
+	 * @param	int	the number of rows to limit the query to
+	 * @param	int	the offset value
+	 * @return	string
 	 */
 	protected function _limit($sql, $limit, $offset)
 	{
-		$limit = $offset + $limit;
-		$newsql = "SELECT * FROM (select inner_query.*, rownum rnum FROM ($sql) inner_query WHERE rownum < $limit)";
-
-		if ($offset != 0)
-		{
-			$newsql .= " WHERE rnum >= $offset";
-		}
-
-		// remember that we used limits
 		$this->limit_used = TRUE;
-
-		return $newsql;
+		return 'SELECT * FROM (SELECT inner_query.*, rownum rnum FROM ('.$sql.') inner_query WHERE rownum < '.($offset + $limit).')'
+			.($offset !== 0 ? ' WHERE rnum >= '.$offset : '');
 	}
 
 	// --------------------------------------------------------------------
@@ -802,19 +642,14 @@
 	/**
 	 * Close DB Connection
 	 *
-	 * @access  protected
-	 * @param   resource
-	 * @return  void
+	 * @return	void
 	 */
-	protected function _close($conn_id)
+	protected function _close()
 	{
-		@oci_close($conn_id);
+		@oci_close($this->conn_id);
 	}
 
-
 }
 
-
-
 /* End of file oci8_driver.php */
-/* Location: ./system/database/drivers/oci8/oci8_driver.php */
+/* Location: ./system/database/drivers/oci8/oci8_driver.php */
\ No newline at end of file
diff --git a/system/database/drivers/oci8/oci8_forge.php b/system/database/drivers/oci8/oci8_forge.php
index b4a24cd..92e8c02 100644
--- a/system/database/drivers/oci8/oci8_forge.php
+++ b/system/database/drivers/oci8/oci8_forge.php
@@ -1,13 +1,13 @@
-<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
- * 
+ *
  * Licensed under the Open Software License version 3.0
- * 
+ *
  * This source file is subject to the Open Software License (OSL 3.0) that is
  * bundled with this package in the files license.txt / license.rst.  It is
  * also available through the world wide web at this URL:
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * Oracle Forge Class
  *
@@ -36,46 +34,21 @@
  */
 class CI_DB_oci8_forge extends CI_DB_forge {
 
-	/**
-	 * Create database
-	 *
-	 * @access	public
-	 * @param	string	the database name
-	 * @return	bool
-	 */
-	function _create_database($name)
-	{
-		return FALSE;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Drop database
-	 *
-	 * @access	private
-	 * @param	string	the database name
-	 * @return	bool
-	 */
-	function _drop_database($name)
-	{
-		return FALSE;
-	}
-
-	// --------------------------------------------------------------------
+	protected $_create_database	= FALSE;
+	protected $_drop_database	= FALSE;
+	protected $_drop_table		= 'DROP TABLE %s';
 
 	/**
 	 * Create Table
 	 *
-	 * @access	private
 	 * @param	string	the table name
 	 * @param	array	the fields
 	 * @param	mixed	primary key(s)
 	 * @param	mixed	key(s)
-	 * @param	boolean	should 'IF NOT EXISTS' be added to the SQL
-	 * @return	bool
+	 * @param	bool	should 'IF NOT EXISTS' be added to the SQL
+	 * @return	string
 	 */
-	function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists)
+	protected function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists)
 	{
 		$sql = 'CREATE TABLE ';
 
@@ -84,54 +57,38 @@
 			$sql .= 'IF NOT EXISTS ';
 		}
 
-		$sql .= $this->db->_escape_identifiers($table)." (";
+		$sql .= $this->db->escape_identifiers($table).' (';
 		$current_field_count = 0;
 
-		foreach ($fields as $field=>$attributes)
+		foreach ($fields as $field => $attributes)
 		{
 			// Numeric field names aren't allowed in databases, so if the key is
 			// numeric, we know it was assigned by PHP and the developer manually
 			// entered the field information, so we'll simply add it to the list
 			if (is_numeric($field))
 			{
-				$sql .= "\n\t$attributes";
+				$sql .= "\n\t".$attributes;
 			}
 			else
 			{
 				$attributes = array_change_key_case($attributes, CASE_UPPER);
 
-				$sql .= "\n\t".$this->db->_protect_identifiers($field);
+				$sql .= "\n\t".$this->db->escape_identifiers($field).' '.$attributes['TYPE'];
 
-				$sql .=  ' '.$attributes['TYPE'];
-
-				if (array_key_exists('CONSTRAINT', $attributes))
-				{
-					$sql .= '('.$attributes['CONSTRAINT'].')';
-				}
-
-				if (array_key_exists('UNSIGNED', $attributes) && $attributes['UNSIGNED'] === TRUE)
+				if (isset($attributes['UNSINGED']) && $attributes['UNSIGNED'] === TRUE)
 				{
 					$sql .= ' UNSIGNED';
 				}
 
-				if (array_key_exists('DEFAULT', $attributes))
+				if (isset($attributes['DEFAULT']))
 				{
-					$sql .= ' DEFAULT \''.$attributes['DEFAULT'].'\'';
+					$sql .= " DEFAULT '".$attributes['DEFAULT']."'";
 				}
 
-				if (array_key_exists('NULL', $attributes) && $attributes['NULL'] === TRUE)
-				{
-					$sql .= ' NULL';
-				}
-				else
-				{
-					$sql .= ' NOT NULL';
-				}
+				$sql .= (isset($attributes['NULL']) && $attributes['NULL'] === TRUE)
+					? '' : ' NOT NULL';
 
-				if (array_key_exists('AUTO_INCREMENT', $attributes) && $attributes['AUTO_INCREMENT'] === TRUE)
-				{
-					$sql .= ' AUTO_INCREMENT';
-				}
+				empty($attributes['CONSTRAINT']) OR ' CONSTRAINT '.$attributes['CONSTRAINT'];
 			}
 
 			// don't add a comma on the end of the last field
@@ -143,43 +100,22 @@
 
 		if (count($primary_keys) > 0)
 		{
-			$primary_keys = $this->db->_protect_identifiers($primary_keys);
-			$sql .= ",\n\tPRIMARY KEY (" . implode(', ', $primary_keys) . ")";
+			$sql .= ",\n\tCONSTRAINT ".$table.' PRIMARY KEY ('.implode(', ', $this->db->escape_identifiers($primary_keys)).')';
 		}
 
 		if (is_array($keys) && count($keys) > 0)
 		{
 			foreach ($keys as $key)
 			{
-				if (is_array($key))
-				{
-					$key = $this->db->_protect_identifiers($key);
-				}
-				else
-				{
-					$key = array($this->db->_protect_identifiers($key));
-				}
+				$key = is_array($key)
+					? $this->db->escape_identifiers($key)
+					: array($this->db->escape_identifiers($key));
 
-				$sql .= ",\n\tUNIQUE COLUMNS (" . implode(', ', $key) . ")";
+				$sql .= ",\n\tUNIQUE COLUMNS (".implode(', ', $key).')';
 			}
 		}
 
-		$sql .= "\n)";
-
-		return $sql;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Drop Table
-	 *
-	 * @access	private
-	 * @return	bool
-	 */
-	function _drop_table($table)
-	{
-		return FALSE;
+		return $sql."\n)";
 	}
 
 	// --------------------------------------------------------------------
@@ -190,70 +126,32 @@
 	 * Generates a platform-specific query so that a table can be altered
 	 * Called by add_column(), drop_column(), and column_alter(),
 	 *
-	 * @access	private
 	 * @param	string	the ALTER type (ADD, DROP, CHANGE)
 	 * @param	string	the column name
 	 * @param	string	the table name
 	 * @param	string	the column definition
 	 * @param	string	the default value
-	 * @param	boolean	should 'NOT NULL' be added
+	 * @param	bool	should 'NOT NULL' be added
 	 * @param	string	the field after which we should add the new field
-	 * @return	object
+	 * @return	string
 	 */
-	function _alter_table($alter_type, $table, $column_name, $column_definition = '', $default_value = '', $null = '', $after_field = '')
+	protected function _alter_table($alter_type, $table, $column_name, $column_definition = '', $default_value = '', $null = '', $after_field = '')
 	{
-		$sql = 'ALTER TABLE '.$this->db->_protect_identifiers($table)." $alter_type ".$this->db->_protect_identifiers($column_name);
+		$sql = 'ALTER TABLE '.$this->db->escape_identifiers($table).' '.$alter_type.' '.$this->db->escape_identifiers($column_name);
 
 		// DROP has everything it needs now.
-		if ($alter_type == 'DROP')
+		if ($alter_type === 'DROP')
 		{
 			return $sql;
 		}
 
-		$sql .= " $column_definition";
-
-		if ($default_value != '')
-		{
-			$sql .= " DEFAULT \"$default_value\"";
-		}
-
-		if ($null === NULL)
-		{
-			$sql .= ' NULL';
-		}
-		else
-		{
-			$sql .= ' NOT NULL';
-		}
-
-		if ($after_field != '')
-		{
-			$sql .= ' AFTER ' . $this->db->_protect_identifiers($after_field);
-		}
-
-		return $sql;
+		return $sql.' '.$column_definition
+			.($default_value !== '' ? ' DEFAULT "'.$default_value.'"' : '')
+			.($null === NULL ? ' NULL' : ' NOT NULL')
+			.($after_field !== '' ? ' AFTER '.$this->db->escape_identifiers($after_field) : '');
 
 	}
 
-	// --------------------------------------------------------------------
-
-	/**
-	 * Rename a table
-	 *
-	 * Generates a platform-specific query so that a table can be renamed
-	 *
-	 * @access	private
-	 * @param	string	the old table name
-	 * @param	string	the new table name
-	 * @return	string
-	 */
-	function _rename_table($table_name, $new_table_name)
-	{
-		$sql = 'ALTER TABLE '.$this->db->_protect_identifiers($table_name)." RENAME TO ".$this->db->_protect_identifiers($new_table_name);
-		return $sql;
-	}
-
-
 }
 
 /* End of file oci8_forge.php */
diff --git a/system/database/drivers/oci8/oci8_result.php b/system/database/drivers/oci8/oci8_result.php
index 0f69fa9..6fb6c81 100644
--- a/system/database/drivers/oci8/oci8_result.php
+++ b/system/database/drivers/oci8/oci8_result.php
@@ -1,13 +1,13 @@
-<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
- * 
+ *
  * Licensed under the Open Software License version 3.0
- * 
+ *
  * This source file is subject to the Open Software License (OSL 3.0) that is
  * bundled with this package in the files license.txt / license.rst.  It is
  * also available through the world wide web at this URL:
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * oci8 Result Class
  *
@@ -38,31 +36,48 @@
  */
 class CI_DB_oci8_result extends CI_DB_result {
 
-	var $stmt_id;
-	var $curs_id;
-	var $limit_used;
+	public $stmt_id;
+	public $curs_id;
+	public $limit_used;
+	public $commit_mode;
+
+	/* Overwriting the parent here, so we have a way to know if it's
+	 * already called or not:
+	 */
+	public $num_rows;
+
+	public function __construct(&$driver_object)
+	{
+		parent::__construct($driver_object);
+		$this->stmt_id = $driver_object->stmt_id;
+		$this->curs_id = $driver_object->curs_id;
+		$this->limit_used = $driver_object->limit_used;
+		$this->commit_mode =& $driver_object->commit_mode;
+		$driver_object->stmt_id = FALSE;
+	}
 
 	/**
 	 * Number of rows in the result set.
 	 *
-	 * Oracle doesn't have a graceful way to retun the number of rows
+	 * Oracle doesn't have a graceful way to return the number of rows
 	 * so we have to use what amounts to a hack.
 	 *
-	 *
-	 * @access  public
-	 * @return  integer
+	 * @return	int
 	 */
 	public function num_rows()
 	{
-		if ($this->num_rows === 0 && count($this->result_array()) > 0)
+		if ( ! is_int($this->num_rows))
 		{
-			$this->num_rows = count($this->result_array());
-			@oci_execute($this->stmt_id, OCI_DEFAULT);
-
-			if ($this->curs_id)
+			if (count($this->result_array) > 0)
 			{
-				@oci_execute($this->curs_id, OCI_DEFAULT);
+				return $this->num_rows = count($this->result_array);
 			}
+			elseif (count($this->result_object) > 0)
+			{
+				return $this->num_rows = count($this->result_object);
+			}
+
+			return $this->num_rows = count($this->result_array());
 		}
 
 		return $this->num_rows;
@@ -73,20 +88,14 @@
 	/**
 	 * Number of fields in the result set
 	 *
-	 * @access  public
-	 * @return  integer
+	 * @return	int
 	 */
 	public function num_fields()
 	{
 		$count = @oci_num_fields($this->stmt_id);
 
 		// if we used a limit we subtract it
-		if ($this->limit_used)
-		{
-			$count = $count - 1;
-		}
-
-		return $count;
+		return ($this->limit_used) ? $count - 1 : $count;
 	}
 
 	// --------------------------------------------------------------------
@@ -96,7 +105,6 @@
 	 *
 	 * Generates an array of column names
 	 *
-	 * @access	public
 	 * @return	array
 	 */
 	public function list_fields()
@@ -116,18 +124,17 @@
 	 *
 	 * Generates an array of objects containing field meta-data
 	 *
-	 * @access  public
-	 * @return  array
+	 * @return	array
 	 */
 	public function field_data()
 	{
 		$retval = array();
 		for ($c = 1, $fieldCount = $this->num_fields(); $c <= $fieldCount; $c++)
 		{
-			$F			= new stdClass();
-			$F->name		= oci_field_name($this->stmt_id, $c);
-			$F->type		= oci_field_type($this->stmt_id, $c);
-			$F->max_length		= oci_field_size($this->stmt_id, $c);
+			$F		= new stdClass();
+			$F->name	= oci_field_name($this->stmt_id, $c);
+			$F->type	= oci_field_type($this->stmt_id, $c);
+			$F->max_length	= oci_field_size($this->stmt_id, $c);
 
 			$retval[] = $F;
 		}
@@ -140,7 +147,7 @@
 	/**
 	 * Free the result
 	 *
-	 * @return	null
+	 * @return	void
 	 */
 	public function free_result()
 	{
@@ -149,6 +156,17 @@
 			oci_free_statement($this->result_id);
 			$this->result_id = FALSE;
 		}
+
+		if (is_resource($this->stmt_id))
+		{
+			oci_free_statement($this->stmt_id);
+		}
+
+		if (is_resource($this->curs_id))
+		{
+			oci_cancel($this->curs_id);
+			$this->curs_id = NULL;
+		}
 	}
 
 	// --------------------------------------------------------------------
@@ -158,8 +176,7 @@
 	 *
 	 * Returns the result set as an array
 	 *
-	 * @access  protected
-	 * @return  array
+	 * @return	array
 	 */
 	protected function _fetch_assoc()
 	{
@@ -174,22 +191,20 @@
 	 *
 	 * Returns the result set as an object
 	 *
-	 * @access  protected
-	 * @return  object
+	 * @return	object
 	 */
 	protected function _fetch_object()
 	{
 		$id = ($this->curs_id) ? $this->curs_id : $this->stmt_id;
-		return @oci_fetch_object($id);
+		return oci_fetch_object($id);
 	}
 
 	// --------------------------------------------------------------------
 
 	/**
-	 * Query result.  "array" version.
+	 * Query result. Array version.
 	 *
-	 * @access  public
-	 * @return  array
+	 * @return	array
 	 */
 	public function result_array()
 	{
@@ -197,14 +212,429 @@
 		{
 			return $this->result_array;
 		}
+		elseif (count($this->result_object) > 0)
+		{
+			for ($i = 0, $c = count($this->result_object); $i < $c; $i++)
+			{
+				$this->result_array[$i] = (array) $this->result_object[$i];
+			}
+
+			return $this->result_array;
+		}
+		elseif (is_array($this->row_data))
+		{
+			if (count($this->row_data) === 0)
+			{
+				return $this->result_array;
+			}
+			else
+			{
+				$row_index = count($this->row_data);
+			}
+		}
+		else
+		{
+			$row_index = 0;
+			$this->row_data = array();
+		}
 
 		$row = NULL;
 		while ($row = $this->_fetch_assoc())
 		{
-			$this->result_array[] = $row;
+			$this->row_data[$row_index++] = $row;
 		}
 
-		return $this->result_array;
+		return $this->result_array = $this->row_data;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Query result. "object" version.
+	 *
+	 * @return	array
+	 */
+	public function result_object()
+	{
+		if (count($this->result_object) > 0)
+		{
+			return $this->result_object;
+		}
+		elseif (count($this->result_array) > 0)
+		{
+			for ($i = 0, $c = count($this->result_array); $i < $c; $i++)
+			{
+				$this->result_object[] = (object) $this->result_array[$i];
+			}
+
+			return $this->result_object;
+		}
+		elseif (is_array($this->row_data))
+		{
+			if (count($this->row_data) === 0)
+			{
+				return $this->result_object;
+			}
+			else
+			{
+				$row_index = count($this->row_data);
+				for ($i = 0; $i < $row_index; $i++)
+				{
+					$this->result_object[$i] = (object) $this->row_data[$i];
+				}
+			}
+		}
+		else
+		{
+			$row_index = 0;
+			$this->row_data = array();
+		}
+
+		$row = NULL;
+		while ($row = $this->_fetch_object())
+		{
+			$this->row_data[$row_index] = (array) $row;
+			$this->result_object[$row_index++] = $row;
+		}
+
+		return $this->result_object;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Query result. Custom object version.
+	 *
+	 * @param	string	class name used to instantiate rows to
+	 * @return	array
+	 */
+	public function custom_result_object($class_name)
+	{
+		if (isset($this->custom_result_object[$class_name]))
+		{
+			return $this->custom_result_object[$class_name];
+		}
+
+		if ( ! class_exists($class_name) OR $this->result_id === FALSE OR $this->num_rows() === 0)
+		{
+			return array();
+		}
+
+		/* Even if we didn't have result_array or result_object
+		 * set prior to custom_result_object() being called,
+		 * num_rows() has already done so.
+		 * Pass by reference, as we don't know how
+		 * large it might be and we don't want 1000 row
+		 * sets being copied.
+		 */
+		if (count($this->result_array) > 0)
+		{
+			$data = &$this->result_array;
+		}
+		elseif (count($this->result_object) > 0)
+		{
+			$data = &$this->result_object;
+		}
+
+		$this->custom_result_object[$class_name] = array();
+		for ($i = 0, $c = count($data); $i < $c; $i++)
+		{
+			$this->custom_result_object[$class_name][$i] = new $class_name();
+			foreach ($data[$i] as $key => $value)
+			{
+				$this->custom_result_object[$class_name][$i]->$key = $value;
+			}
+		}
+
+		return $this->custom_result_object[$class_name];
+	}
+
+	// --------------------------------------------------------------------
+
+	/* Single row result.
+	 *
+	 * Acts as a wrapper for row_object(), row_array()
+	 * and custom_row_object(). Also used by first_row(), next_row()
+	 * and previous_row().
+	 *
+	 * @param	int	row index
+	 * @param	string	('object', 'array' or a custom class name)
+	 * @return	mixed	whatever was passed to the second parameter
+	 */
+	public function row($n = 0, $type = 'object')
+	{
+		if ($type === 'object')
+		{
+			return $this->row_object($n);
+		}
+		elseif ($type === 'array')
+		{
+			return $this->row_array($n);
+		}
+
+		return $this->custom_row_object($n, $type);
+	}
+
+	// --------------------------------------------------------------------
+
+	/* Single row result. Array version.
+	 *
+	 * @param	int	row index
+	 * @return	array
+	 */
+	public function row_array($n = 0)
+	{
+		// Make sure $n is not a string
+		if ( ! is_int($n))
+		{
+			$n = (int) $n;
+		}
+
+		/* If row_data is initialized, it means that we've already tried
+		 * (at least) to fetch some data, so ... check if we already have
+		 * this row.
+		*/
+		if (is_array($this->row_data))
+		{
+			/* If we already have row_data[$n] - return it.
+			 *
+			 * If we enter the elseif, there's a number of reasons to
+			 * return an empty array:
+			 *
+			 *	- count($this->row_data) === 0 means there are no results
+			 *	- num_rows being set, result_array and/or result_object
+			 *	  having count() > 0 means that we've already fetched all
+			 *	  data and $n is greater than our highest row index available
+			 *	- $n < $this->current_row means that if such row existed,
+			 *	  we would've already returned it, therefore $n is an
+			 *	  invalid index
+			 */
+			if (isset($this->row_data[$n])) // We already have this row
+			{
+				$this->current_row = $n;
+				return $this->row_data[$n];
+			}
+			elseif (count($this->row_data) === 0 OR is_int($this->num_rows)
+				OR count($this->result_array) > 0 OR count($this->result_object) > 0
+				OR $n < $this->current_row)
+			{
+				// No such row exists
+				return NULL;
+			}
+
+			// Get the next row index that would actually need to be fetched
+			$current_row = ($this->current_row < count($this->row_data)) ? count($this->row_data) : $this->current_row + 1;
+		}
+		else
+		{
+			$current_row = $this->current_row = 0;
+			$this->row_data = array();
+		}
+
+		/* Fetch more data, if available
+		 *
+		 * NOTE: Operator precedence is important here, if you change
+		 *	 'AND' with '&&' - it WILL BREAK the results, as
+		 *	 $row will be assigned the scalar value of both
+		 *	 expressions!
+		 */
+		while ($row = $this->_fetch_assoc() AND $current_row <= $n)
+		{
+			$this->row_data[$current_row++] = $row;
+		}
+
+		// This would mean that there's no (more) data to fetch
+		if ( ! is_array($this->row_data) OR ! isset($this->row_data[$n]))
+		{
+			// Cache what we already have
+			if (is_array($this->row_data))
+			{
+				$this->num_rows = count($this->row_data);
+				/* Usually, row_data could have less elements than result_array,
+				 * but at this point - they should be exactly the same.
+				 */
+				$this->result_array = $this->row_data;
+			}
+			else
+			{
+				$this->num_rows = 0;
+			}
+
+			return NULL;
+		}
+
+		$this->current_row = $n;
+		return $this->row_data[$n];
+	}
+
+	// --------------------------------------------------------------------
+
+	/* Single row result. Object version.
+	 *
+	 * @param	int	row index
+	 * @return	mixed	object if row found; empty array if not
+	 */
+	public function row_object($n = 0)
+	{
+		// Make sure $n is not a string
+		if ( ! is_int($n))
+		{
+			$n = (int) $n;
+		}
+		/* Logic here is exactly the same as in row_array,
+		 * except we have to cast row_data[$n] to an object.
+		 *
+		 * If we already have result_object though - we can
+		 * directly return from it.
+		 */
+		if (isset($this->result_object[$n]))
+		{
+			$this->current_row = $n;
+			// Set this, if not already done.
+			if ( ! is_int($this->num_rows))
+			{
+				$this->num_rows = count($this->result_object);
+			}
+
+			return $this->result_object[$n];
+		}
+
+		$row = $this->row_array($n);
+		// Cast only if the row exists
+		if (count($row) > 0)
+		{
+			$this->current_row = $n;
+			return (object) $row;
+		}
+
+		return NULL;
+	}
+
+	// --------------------------------------------------------------------
+
+	/* Single row result. Custom object version.
+	 *
+	 * @param	int	row index
+	 * @param	string	custom class name
+	 * @return	mixed	custom object if row found; empty array otherwise
+	 */
+	public function custom_row_object($n = 0, $class_name)
+	{
+		// Make sure $n is not a string
+		if ( ! is_int($n))
+		{
+			$n = (int) $n;
+		}
+
+		if (array_key_exists($class_name, $this->custom_result_object))
+		{
+			/* We already have a the whole result set with this class_name,
+			 * return the specified row if it exists, and an empty array if
+			 * it doesn't.
+			 */
+			if (isset($this->custom_result_object[$class_name][$n]))
+			{
+				$this->current_row = $n;
+				return $this->custom_result_object[$class_name][$n];
+			}
+			else
+			{
+				return NULL;
+			}
+		}
+		elseif ( ! class_exists($class_name)) // No such class exists
+		{
+			return NULL;
+		}
+
+		$row = $this->row_array($n);
+		// A non-array would mean that the row doesn't exist
+		if ( ! is_array($row))
+		{
+			return NULL;
+		}
+
+		// Convert to the desired class and return
+		$row_object = new $class_name();
+		foreach ($row as $key => $value)
+		{
+			$row_object->$key = $value;
+		}
+
+		$this->current_row = $n;
+		return $row_object;
+	}
+
+	// --------------------------------------------------------------------
+
+	/* First row result.
+	 *
+	 * @param	string	('object', 'array' or a custom class name)
+	 * @return	mixed	whatever was passed to the second parameter
+	 */
+	public function first_row($type = 'object')
+	{
+		return $this->row(0, $type);
+	}
+
+	// --------------------------------------------------------------------
+
+	/* Last row result.
+	 *
+	 * @param	string	('object', 'array' or a custom class name)
+	 * @return	mixed	whatever was passed to the second parameter
+	 */
+	public function last_row($type = 'object')
+	{
+		$result = &$this->result($type);
+		if ( ! isset($this->num_rows))
+		{
+			$this->num_rows = count($result);
+		}
+		$this->current_row = $this->num_rows - 1;
+		return $result[$this->current_row];
+	}
+
+	// --------------------------------------------------------------------
+
+	/* Next row result.
+	 *
+	 * @param	string	('object', 'array' or a custom class name)
+	 * @return	mixed	whatever was passed to the second parameter
+	 */
+	public function next_row($type = 'object')
+	{
+		if (is_array($this->row_data))
+		{
+			$count = count($this->row_data);
+			if ($this->current_row > $count OR ($this->current_row === 0 && $count === 0))
+			{
+				$n = $count;
+			}
+			else
+			{
+				$n = $this->current_row + 1;
+			}
+		}
+		else
+		{
+			$n = 0;
+		}
+
+		return $this->row($n, $type);
+	}
+
+	// --------------------------------------------------------------------
+
+	/* Previous row result.
+	 *
+	 * @param	string	('object', 'array' or a custom class name)
+	 * @return	mixed	whatever was passed to the second parameter
+	 */
+	public function previous_row($type = 'object')
+	{
+		$n = ($this->current_row !== 0) ? $this->current_row - 1 : 0;
+		return $this->row($n, $type);
 	}
 
 	// --------------------------------------------------------------------
@@ -212,20 +642,59 @@
 	/**
 	 * Data Seek
 	 *
-	 * Moves the internal pointer to the desired offset.  We call
+	 * Moves the internal pointer to the desired offset. We call
 	 * this internally before fetching results to make sure the
-	 * result set starts at zero
+	 * result set starts at zero.
 	 *
-	 * @access	protected
-	 * @return	array
+	 * Oracle's PHP extension doesn't have an easy way of doing this
+	 * and the only workaround is to (re)execute the statement or cursor
+	 * in order to go to the first (zero) index of the result set.
+	 * Then, we would need to "dummy" fetch ($n - 1) rows to get to the
+	 * right one.
+	 *
+	 * This is as ridiculous as it sounds and it's the reason why every
+	 * other method that is fetching data tries to use an already "cached"
+	 * result set. Keeping this just in case it becomes needed at
+	 * some point in the future, but it will only work for resetting the
+	 * pointer to zero.
+	 *
+	 * @return	bool
 	 */
-	protected function _data_seek($n = 0)
+	protected function _data_seek()
 	{
-		return FALSE; // Not needed
+		/* The PHP manual says that if OCI_NO_AUTO_COMMIT mode
+		 * is used, and oci_rollback() and/or oci_commit() are
+		 * not subsequently called - this will cause an unnecessary
+		 * rollback to be triggered at the end of the script execution.
+		 *
+		 * Therefore we'll try to avoid using that mode flag
+		 * if we're not currently in the middle of a transaction.
+		 */
+		if ($this->commit_mode !== OCI_COMMIT_ON_SUCCESS)
+		{
+			$result = @oci_execute($this->stmt_id, $this->commit_mode);
+		}
+		else
+		{
+			$result = @oci_execute($this->stmt_id);
+		}
+
+		if ($result && $this->curs_id)
+		{
+			if ($this->commit_mode !== OCI_COMMIT_ON_SUCCESS)
+			{
+				return @oci_execute($this->curs_id, $this->commit_mode);
+			}
+			else
+			{
+				return @oci_execute($this->curs_id);
+			}
+		}
+
+		return $result;
 	}
 
 }
 
-
 /* End of file oci8_result.php */
-/* Location: ./system/database/drivers/oci8/oci8_result.php */
+/* Location: ./system/database/drivers/oci8/oci8_result.php */
\ No newline at end of file
diff --git a/system/database/drivers/oci8/oci8_utility.php b/system/database/drivers/oci8/oci8_utility.php
index d60f98b..0183eda 100644
--- a/system/database/drivers/oci8/oci8_utility.php
+++ b/system/database/drivers/oci8/oci8_utility.php
@@ -1,13 +1,13 @@
-<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
- * 
+ *
  * Licensed under the Open Software License version 3.0
- * 
+ *
  * This source file is subject to the Open Software License (OSL 3.0) that is
  * bundled with this package in the files license.txt / license.rst.  It is
  * also available through the world wide web at this URL:
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * Oracle Utility Class
  *
@@ -36,63 +34,20 @@
  */
 class CI_DB_oci8_utility extends CI_DB_utility {
 
-	/**
-	 * List databases
-	 *
-	 * @access	private
-	 * @return	bool
-	 */
-	function _list_databases()
-	{
-		return FALSE;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Optimize table query
-	 *
-	 * Generates a platform-specific query so that a table can be optimized
-	 *
-	 * @access	private
-	 * @param	string	the table name
-	 * @return	object
-	 */
-	function _optimize_table($table)
-	{
-		return FALSE; // Is this supported in Oracle?
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Repair table query
-	 *
-	 * Generates a platform-specific query so that a table can be repaired
-	 *
-	 * @access	private
-	 * @param	string	the table name
-	 * @return	object
-	 */
-	function _repair_table($table)
-	{
-		return FALSE; // Is this supported in Oracle?
-	}
-
-	// --------------------------------------------------------------------
+	protected $_list_databases	= 'SELECT username FROM dba_users'; // Schemas are actual usernames
 
 	/**
 	 * Oracle Export
 	 *
-	 * @access	private
 	 * @param	array	Preferences
 	 * @return	mixed
 	 */
-	function _backup($params = array())
+	protected function _backup($params = array())
 	{
 		// Currently unsupported
 		return $this->db->display_error('db_unsuported_feature');
 	}
+
 }
 
 /* End of file oci8_utility.php */
diff --git a/system/database/drivers/odbc/odbc_driver.php b/system/database/drivers/odbc/odbc_driver.php
index 6ba39f0..222c311 100644
--- a/system/database/drivers/odbc/odbc_driver.php
+++ b/system/database/drivers/odbc/odbc_driver.php
@@ -1,13 +1,13 @@
-<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
- * 
+ *
  * Licensed under the Open Software License version 3.0
- * 
+ *
  * This source file is subject to the Open Software License (OSL 3.0) that is
  * bundled with this package in the files license.txt / license.rst.  It is
  * also available through the world wide web at this URL:
@@ -25,13 +25,11 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * ODBC Database Adapter Class
  *
  * Note: _DB is an extender class that the app controller
- * creates dynamically based on whether the active record
+ * creates dynamically based on whether the query builder
  * class is being used or not.
  *
  * @package		CodeIgniter
@@ -42,40 +40,44 @@
  */
 class CI_DB_odbc_driver extends CI_DB {
 
-	var $dbdriver = 'odbc';
+	public $dbdriver = 'odbc';
 
 	// the character used to excape - not necessary for ODBC
-	var $_escape_char = '';
+	protected $_escape_char = '';
 
 	// clause and character used for LIKE escape sequences
-	var $_like_escape_str = " {escape '%s'} ";
-	var $_like_escape_chr = '!';
+	protected $_like_escape_str = " {escape '%s'} ";
+	protected $_like_escape_chr = '!';
 
 	/**
 	 * The syntax to count rows is slightly different across different
 	 * database engines, so this string appears in each driver and is
 	 * used for the count_all() and count_all_results() functions.
 	 */
-	var $_count_string = "SELECT COUNT(*) AS ";
-	var $_random_keyword;
+	protected $_count_string = 'SELECT COUNT(*) AS ';
+	protected $_random_keyword;
 
-
-	function __construct($params)
+	public function __construct($params)
 	{
 		parent::__construct($params);
 
 		$this->_random_keyword = ' RND('.time().')'; // database specific random keyword
+
+		// Legacy support for DSN in the hostname field
+		if (empty($this->dsn))
+		{
+			$this->dsn = $this->hostname;
+		}
 	}
 
 	/**
 	 * Non-persistent database connection
 	 *
-	 * @access	private called by the base class
 	 * @return	resource
 	 */
-	function db_connect()
+	public function db_connect()
 	{
-		return @odbc_connect($this->hostname, $this->username, $this->password);
+		return @odbc_connect($this->dsn, $this->username, $this->password);
 	}
 
 	// --------------------------------------------------------------------
@@ -83,71 +85,11 @@
 	/**
 	 * Persistent database connection
 	 *
-	 * @access	private called by the base class
 	 * @return	resource
 	 */
-	function db_pconnect()
+	public function db_pconnect()
 	{
-		return @odbc_pconnect($this->hostname, $this->username, $this->password);
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Reconnect
-	 *
-	 * Keep / reestablish the db connection if no queries have been
-	 * sent for a length of time exceeding the server's idle timeout
-	 *
-	 * @access	public
-	 * @return	void
-	 */
-	function reconnect()
-	{
-		// not implemented in odbc
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Select the database
-	 *
-	 * @access	private called by the base class
-	 * @return	resource
-	 */
-	function db_select()
-	{
-		// Not needed for ODBC
-		return TRUE;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Set client character set
-	 *
-	 * @access	public
-	 * @param	string
-	 * @param	string
-	 * @return	resource
-	 */
-	function db_set_charset($charset, $collation)
-	{
-		// @todo - add support if needed
-		return TRUE;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Version number query string
-	 *
-	 * @access	public
-	 * @return	string
-	 */
-	function _version()
-	{
-		return "SELECT version() AS ver";
+		return @odbc_pconnect($this->dsn, $this->username, $this->password);
 	}
 
 	// --------------------------------------------------------------------
@@ -155,49 +97,25 @@
 	/**
 	 * Execute the query
 	 *
-	 * @access	private called by the base class
 	 * @param	string	an SQL query
 	 * @return	resource
 	 */
-	function _execute($sql)
+	protected function _execute($sql)
 	{
-		$sql = $this->_prep_query($sql);
 		return @odbc_exec($this->conn_id, $sql);
 	}
 
 	// --------------------------------------------------------------------
 
 	/**
-	 * Prep the query
-	 *
-	 * If needed, each database adapter can prep the query string
-	 *
-	 * @access	private called by execute()
-	 * @param	string	an SQL query
-	 * @return	string
-	 */
-	function _prep_query($sql)
-	{
-		return $sql;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
 	 * Begin Transaction
 	 *
-	 * @access	public
 	 * @return	bool
 	 */
-	function trans_begin($test_mode = FALSE)
+	public function trans_begin($test_mode = FALSE)
 	{
-		if ( ! $this->trans_enabled)
-		{
-			return TRUE;
-		}
-
 		// When transactions are nested we only begin/commit/rollback the outermost ones
-		if ($this->_trans_depth > 0)
+		if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
 		{
 			return TRUE;
 		}
@@ -205,7 +123,7 @@
 		// Reset the transaction failure flag.
 		// If the $test_mode flag is set to TRUE transactions will be rolled back
 		// even if the queries produce a successful result.
-		$this->_trans_failure = ($test_mode === TRUE) ? TRUE : FALSE;
+		$this->_trans_failure = ($test_mode === TRUE);
 
 		return odbc_autocommit($this->conn_id, FALSE);
 	}
@@ -215,18 +133,12 @@
 	/**
 	 * Commit Transaction
 	 *
-	 * @access	public
 	 * @return	bool
 	 */
-	function trans_commit()
+	public function trans_commit()
 	{
-		if ( ! $this->trans_enabled)
-		{
-			return TRUE;
-		}
-
 		// When transactions are nested we only begin/commit/rollback the outermost ones
-		if ($this->_trans_depth > 0)
+		if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
 		{
 			return TRUE;
 		}
@@ -241,18 +153,12 @@
 	/**
 	 * Rollback Transaction
 	 *
-	 * @access	public
 	 * @return	bool
 	 */
-	function trans_rollback()
+	public function trans_rollback()
 	{
-		if ( ! $this->trans_enabled)
-		{
-			return TRUE;
-		}
-
 		// When transactions are nested we only begin/commit/rollback the outermost ones
-		if ($this->_trans_depth > 0)
+		if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
 		{
 			return TRUE;
 		}
@@ -267,12 +173,11 @@
 	/**
 	 * Escape String
 	 *
-	 * @access	public
 	 * @param	string
 	 * @param	bool	whether or not the string will be used in a LIKE condition
 	 * @return	string
 	 */
-	function escape_str($str, $like = FALSE)
+	public function escape_str($str, $like = FALSE)
 	{
 		if (is_array($str))
 		{
@@ -284,15 +189,14 @@
 			return $str;
 		}
 
-		// ODBC doesn't require escaping
 		$str = remove_invisible_characters($str);
 
 		// escape LIKE condition wildcards
 		if ($like === TRUE)
 		{
-			$str = str_replace(	array('%', '_', $this->_like_escape_chr),
-								array($this->_like_escape_chr.'%', $this->_like_escape_chr.'_', $this->_like_escape_chr.$this->_like_escape_chr),
-								$str);
+			return str_replace(array($this->_like_escape_chr, '%', '_'),
+						array($this->_like_escape_chr.$this->_like_escape_chr, $this->_like_escape_chr.'%', $this->_like_escape_chr.'_'),
+						$str);
 		}
 
 		return $str;
@@ -303,10 +207,9 @@
 	/**
 	 * Affected Rows
 	 *
-	 * @access	public
-	 * @return	integer
+	 * @return	int
 	 */
-	function affected_rows()
+	public function affected_rows()
 	{
 		return @odbc_num_rows($this->conn_id);
 	}
@@ -316,43 +219,11 @@
 	/**
 	 * Insert ID
 	 *
-	 * @access	public
-	 * @return	integer
+	 * @return	bool
 	 */
-	function insert_id()
+	public function insert_id()
 	{
-		return @odbc_insert_id($this->conn_id);
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * "Count All" query
-	 *
-	 * Generates a platform-specific query string that counts all records in
-	 * the specified database
-	 *
-	 * @access	public
-	 * @param	string
-	 * @return	string
-	 */
-	function count_all($table = '')
-	{
-		if ($table == '')
-		{
-			return 0;
-		}
-
-		$query = $this->query($this->_count_string . $this->_protect_identifiers('numrows') . " FROM " . $this->_protect_identifiers($table, TRUE, NULL, FALSE));
-
-		if ($query->num_rows() == 0)
-		{
-			return 0;
-		}
-
-		$row = $query->row();
-		$this->_reset_select();
-		return (int) $row->numrows;
+		return ($this->db->db_debug) ? $this->db->display_error('db_unsuported_feature') : FALSE;
 	}
 
 	// --------------------------------------------------------------------
@@ -362,15 +233,14 @@
 	 *
 	 * Generates a platform-specific query string so that the table names can be fetched
 	 *
-	 * @access	private
-	 * @param	boolean
+	 * @param	bool
 	 * @return	string
 	 */
-	function _list_tables($prefix_limit = FALSE)
+	protected function _list_tables($prefix_limit = FALSE)
 	{
-		$sql = "SHOW TABLES FROM `".$this->database."`";
+		$sql = 'SHOW TABLES FROM '.$this->database;
 
-		if ($prefix_limit !== FALSE AND $this->dbprefix != '')
+		if ($prefix_limit !== FALSE && $this->dbprefix !== '')
 		{
 			//$sql .= " LIKE '".$this->escape_like_str($this->dbprefix)."%' ".sprintf($this->_like_escape_str, $this->_like_escape_chr);
 			return FALSE; // not currently supported
@@ -386,13 +256,12 @@
 	 *
 	 * Generates a platform-specific query string so that the column names can be fetched
 	 *
-	 * @access	public
 	 * @param	string	the table name
 	 * @return	string
 	 */
-	function _list_columns($table = '')
+	protected function _list_columns($table = '')
 	{
-		return "SHOW COLUMNS FROM ".$table;
+		return 'SHOW COLUMNS FROM '.$table;
 	}
 
 	// --------------------------------------------------------------------
@@ -402,81 +271,27 @@
 	 *
 	 * Generates a platform-specific query so that the column data can be retrieved
 	 *
-	 * @access	public
 	 * @param	string	the table name
-	 * @return	object
-	 */
-	function _field_data($table)
-	{
-		return "SELECT TOP 1 FROM ".$table;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * The error message string
-	 *
-	 * @access	private
 	 * @return	string
 	 */
-	function _error_message()
+	protected function _field_data($table)
 	{
-		return odbc_errormsg($this->conn_id);
+		return 'SELECT TOP 1 FROM '.$table;
 	}
 
 	// --------------------------------------------------------------------
 
 	/**
-	 * The error message number
+	 * Error
 	 *
-	 * @access	private
-	 * @return	integer
+	 * Returns an array containing code and message of the last
+	 * database error that has occured.
+	 *
+	 * @return	array
 	 */
-	function _error_number()
+	public function error()
 	{
-		return odbc_error($this->conn_id);
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Escape the SQL Identifiers
-	 *
-	 * This function escapes column and table names
-	 *
-	 * @access	private
-	 * @param	string
-	 * @return	string
-	 */
-	function _escape_identifiers($item)
-	{
-		if ($this->_escape_char == '')
-		{
-			return $item;
-		}
-
-		foreach ($this->_reserved_identifiers as $id)
-		{
-			if (strpos($item, '.'.$id) !== FALSE)
-			{
-				$str = $this->_escape_char. str_replace('.', $this->_escape_char.'.', $item);
-
-				// remove duplicates if the user already included the escape
-				return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str);
-			}
-		}
-
-		if (strpos($item, '.') !== FALSE)
-		{
-			$str = $this->_escape_char.str_replace('.', $this->_escape_char.'.'.$this->_escape_char, $item).$this->_escape_char;
-		}
-		else
-		{
-			$str = $this->_escape_char.$item.$this->_escape_char;
-		}
-
-		// remove duplicates if the user already included the escape
-		return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str);
+		return array('code' => odbc_error($this->conn_id), 'message' => odbc_errormsg($this->conn_id));
 	}
 
 	// --------------------------------------------------------------------
@@ -487,124 +302,30 @@
 	 * This function implicitly groups FROM tables so there is no confusion
 	 * about operator precedence in harmony with SQL standards
 	 *
-	 * @access	public
-	 * @param	type
-	 * @return	type
-	 */
-	function _from_tables($tables)
-	{
-		if ( ! is_array($tables))
-		{
-			$tables = array($tables);
-		}
-
-		return '('.implode(', ', $tables).')';
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Insert statement
-	 *
-	 * Generates a platform-specific insert string from the supplied data
-	 *
-	 * @access	public
-	 * @param	string	the table name
-	 * @param	array	the insert keys
-	 * @param	array	the insert values
+	 * @param	array
 	 * @return	string
 	 */
-	function _insert($table, $keys, $values)
+	protected function _from_tables($tables)
 	{
-		return "INSERT INTO ".$table." (".implode(', ', $keys).") VALUES (".implode(', ', $values).")";
+		return is_array($tables) ? implode(', ', $tables) : $tables;
 	}
 
 	// --------------------------------------------------------------------
 
 	/**
-	 * Update statement
-	 *
-	 * Generates a platform-specific update string from the supplied data
-	 *
-	 * @access	public
-	 * @param	string	the table name
-	 * @param	array	the update data
-	 * @param	array	the where clause
-	 * @param	array	the orderby clause
-	 * @param	array	the limit clause
-	 * @return	string
-	 */
-	function _update($table, $values, $where, $orderby = array(), $limit = FALSE)
-	{
-		foreach ($values as $key => $val)
-		{
-			$valstr[] = $key." = ".$val;
-		}
-
-		$limit = ( ! $limit) ? '' : ' LIMIT '.$limit;
-
-		$orderby = (count($orderby) >= 1)?' ORDER BY '.implode(", ", $orderby):'';
-
-		$sql = "UPDATE ".$table." SET ".implode(', ', $valstr);
-
-		$sql .= ($where != '' AND count($where) >=1) ? " WHERE ".implode(" ", $where) : '';
-
-		$sql .= $orderby.$limit;
-
-		return $sql;
-	}
-
-
-	// --------------------------------------------------------------------
-
-	/**
 	 * Truncate statement
 	 *
 	 * Generates a platform-specific truncate string from the supplied data
-	 * If the database does not support the truncate() command
-	 * This function maps to "DELETE FROM table"
 	 *
-	 * @access	public
+	 * If the database does not support the truncate() command,
+	 * then this method maps to 'DELETE FROM table'
+	 *
 	 * @param	string	the table name
 	 * @return	string
 	 */
-	function _truncate($table)
+	protected function _truncate($table)
 	{
-		return $this->_delete($table);
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Delete statement
-	 *
-	 * Generates a platform-specific delete string from the supplied data
-	 *
-	 * @access	public
-	 * @param	string	the table name
-	 * @param	array	the where clause
-	 * @param	string	the limit clause
-	 * @return	string
-	 */
-	function _delete($table, $where = array(), $like = array(), $limit = FALSE)
-	{
-		$conditions = '';
-
-		if (count($where) > 0 OR count($like) > 0)
-		{
-			$conditions = "\nWHERE ";
-			$conditions .= implode("\n", $this->ar_where);
-
-			if (count($where) > 0 && count($like) > 0)
-			{
-				$conditions .= " AND ";
-			}
-			$conditions .= implode("\n", $like);
-		}
-
-		$limit = ( ! $limit) ? '' : ' LIMIT '.$limit;
-
-		return "DELETE FROM ".$table.$conditions.$limit;
+		return 'DELETE FROM '.$table;
 	}
 
 	// --------------------------------------------------------------------
@@ -614,16 +335,14 @@
 	 *
 	 * Generates a platform-specific LIMIT clause
 	 *
-	 * @access	public
 	 * @param	string	the sql query string
-	 * @param	integer	the number of rows to limit the query to
-	 * @param	integer	the offset value
+	 * @param	int	the number of rows to limit the query to
+	 * @param	int	the offset value
 	 * @return	string
 	 */
-	function _limit($sql, $limit, $offset)
+	protected function _limit($sql, $limit, $offset)
 	{
-		// Does ODBC doesn't use the LIMIT clause?
-		return $sql;
+		return $sql.($offset == 0 ? '' : $offset.', ').$limit;
 	}
 
 	// --------------------------------------------------------------------
@@ -631,19 +350,14 @@
 	/**
 	 * Close DB Connection
 	 *
-	 * @access	public
-	 * @param	resource
 	 * @return	void
 	 */
-	function _close($conn_id)
+	protected function _close()
 	{
-		@odbc_close($conn_id);
+		@odbc_close($this->conn_id);
 	}
 
-
 }
 
-
-
 /* End of file odbc_driver.php */
 /* Location: ./system/database/drivers/odbc/odbc_driver.php */
\ No newline at end of file
diff --git a/system/database/drivers/odbc/odbc_forge.php b/system/database/drivers/odbc/odbc_forge.php
index e0ec687..b074c58 100644
--- a/system/database/drivers/odbc/odbc_forge.php
+++ b/system/database/drivers/odbc/odbc_forge.php
@@ -1,13 +1,13 @@
-<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
- * 
+ *
  * Licensed under the Open Software License version 3.0
- * 
+ *
  * This source file is subject to the Open Software License (OSL 3.0) that is
  * bundled with this package in the files license.txt / license.rst.  It is
  * also available through the world wide web at this URL:
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * ODBC Forge Class
  *
@@ -36,58 +34,20 @@
  */
 class CI_DB_odbc_forge extends CI_DB_forge {
 
-	/**
-	 * Create database
-	 *
-	 * @access	private
-	 * @param	string	the database name
-	 * @return	bool
-	 */
-	function _create_database()
-	{
-		// ODBC has no "create database" command since it's
-		// designed to connect to an existing database
-		if ($this->db->db_debug)
-		{
-			return $this->db->display_error('db_unsuported_feature');
-		}
-		return FALSE;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Drop database
-	 *
-	 * @access	private
-	 * @param	string	the database name
-	 * @return	bool
-	 */
-	function _drop_database($name)
-	{
-		// ODBC has no "drop database" command since it's
-		// designed to connect to an existing database
-		if ($this->db->db_debug)
-		{
-			return $this->db->display_error('db_unsuported_feature');
-		}
-		return FALSE;
-	}
-
-	// --------------------------------------------------------------------
+	protected $_drop_database	= 'DROP DATABASE %s';
+	protected $_drop_table		= 'DROP TABLE %s';
 
 	/**
 	 * Create Table
 	 *
-	 * @access	private
 	 * @param	string	the table name
 	 * @param	array	the fields
 	 * @param	mixed	primary key(s)
 	 * @param	mixed	key(s)
-	 * @param	boolean	should 'IF NOT EXISTS' be added to the SQL
+	 * @param	bool	should 'IF NOT EXISTS' be added to the SQL
 	 * @return	bool
 	 */
-	function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists)
+	protected function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists)
 	{
 		$sql = 'CREATE TABLE ';
 
@@ -96,51 +56,40 @@
 			$sql .= 'IF NOT EXISTS ';
 		}
 
-		$sql .= $this->db->_escape_identifiers($table)." (";
+		$sql .= $this->db->escape_identifiers($table).' (';
 		$current_field_count = 0;
 
-		foreach ($fields as $field=>$attributes)
+		foreach ($fields as $field => $attributes)
 		{
 			// Numeric field names aren't allowed in databases, so if the key is
 			// numeric, we know it was assigned by PHP and the developer manually
 			// entered the field information, so we'll simply add it to the list
 			if (is_numeric($field))
 			{
-				$sql .= "\n\t$attributes";
+				$sql .= "\n\t".$attributes;
 			}
 			else
 			{
 				$attributes = array_change_key_case($attributes, CASE_UPPER);
 
-				$sql .= "\n\t".$this->db->_protect_identifiers($field);
+				$sql .= "\n\t".$this->db->escape_identifiers($field).' '.$attributes['TYPE'];
 
-				$sql .=  ' '.$attributes['TYPE'];
+				empty($attributes['CONSTRAINT']) OR $sql .= '('.$attributes['CONSTRAINT'].')';
 
-				if (array_key_exists('CONSTRAINT', $attributes))
-				{
-					$sql .= '('.$attributes['CONSTRAINT'].')';
-				}
-
-				if (array_key_exists('UNSIGNED', $attributes) && $attributes['UNSIGNED'] === TRUE)
+				if ( ! empty($attributes['UNSIGNED']) && $attributes['UNSIGNED'] === TRUE)
 				{
 					$sql .= ' UNSIGNED';
 				}
 
-				if (array_key_exists('DEFAULT', $attributes))
+				if (isset($attributes['DEFAULT']))
 				{
-					$sql .= ' DEFAULT \''.$attributes['DEFAULT'].'\'';
+					$sql .= " DEFAULT '".$attributes['DEFAULT']."'";
 				}
 
-				if (array_key_exists('NULL', $attributes) && $attributes['NULL'] === TRUE)
-				{
-					$sql .= ' NULL';
-				}
-				else
-				{
-					$sql .= ' NOT NULL';
-				}
+				$sql .= ( ! empty($attributes['NULL']) && $attributes['NULL'] === TRUE)
+					? ' NULL' : ' NOT NULL';
 
-				if (array_key_exists('AUTO_INCREMENT', $attributes) && $attributes['AUTO_INCREMENT'] === TRUE)
+				if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE)
 				{
 					$sql .= ' AUTO_INCREMENT';
 				}
@@ -155,48 +104,22 @@
 
 		if (count($primary_keys) > 0)
 		{
-			$primary_keys = $this->db->_protect_identifiers($primary_keys);
-			$sql .= ",\n\tPRIMARY KEY (" . implode(', ', $primary_keys) . ")";
+			$sql .= ",\n\tPRIMARY KEY (".implode(', ', $this->escape_identifiers($primary_keys)).')';
 		}
 
 		if (is_array($keys) && count($keys) > 0)
 		{
 			foreach ($keys as $key)
 			{
-				if (is_array($key))
-				{
-					$key = $this->db->_protect_identifiers($key);
-				}
-				else
-				{
-					$key = array($this->db->_protect_identifiers($key));
-				}
+				$key = is_array($key)
+					? $this->db->escape_identifiers($key)
+					: array($this->db->escape_identifiers($key));
 
-				$sql .= ",\n\tFOREIGN KEY (" . implode(', ', $key) . ")";
+				$sql .= ",\n\tFOREIGN KEY (".implode(', ', $key).')';
 			}
 		}
 
-		$sql .= "\n)";
-
-		return $sql;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Drop Table
-	 *
-	 * @access	private
-	 * @return	bool
-	 */
-	function _drop_table($table)
-	{
-		// Not a supported ODBC feature
-		if ($this->db->db_debug)
-		{
-			return $this->db->display_error('db_unsuported_feature');
-		}
-		return FALSE;
+		return $sql."\n)";
 	}
 
 	// --------------------------------------------------------------------
@@ -207,71 +130,31 @@
 	 * Generates a platform-specific query so that a table can be altered
 	 * Called by add_column(), drop_column(), and column_alter(),
 	 *
-	 * @access	private
 	 * @param	string	the ALTER type (ADD, DROP, CHANGE)
 	 * @param	string	the column name
 	 * @param	string	the table name
 	 * @param	string	the column definition
 	 * @param	string	the default value
-	 * @param	boolean	should 'NOT NULL' be added
+	 * @param	bool	should 'NOT NULL' be added
 	 * @param	string	the field after which we should add the new field
-	 * @return	object
+	 * @return	string
 	 */
-	function _alter_table($alter_type, $table, $column_name, $column_definition = '', $default_value = '', $null = '', $after_field = '')
+	protected function _alter_table($alter_type, $table, $column_name, $column_definition = '', $default_value = '', $null = '', $after_field = '')
 	{
-		$sql = 'ALTER TABLE '.$this->db->_protect_identifiers($table)." $alter_type ".$this->db->_protect_identifiers($column_name);
+		$sql = 'ALTER TABLE '.$this->db->escape_identifiers($table).' '.$alter_type.' '.$this->db->escape_identifiers($column_name);
 
 		// DROP has everything it needs now.
-		if ($alter_type == 'DROP')
+		if ($alter_type === 'DROP')
 		{
 			return $sql;
 		}
 
-		$sql .= " $column_definition";
-
-		if ($default_value != '')
-		{
-			$sql .= " DEFAULT \"$default_value\"";
-		}
-
-		if ($null === NULL)
-		{
-			$sql .= ' NULL';
-		}
-		else
-		{
-			$sql .= ' NOT NULL';
-		}
-
-		if ($after_field != '')
-		{
-			$sql .= ' AFTER ' . $this->db->_protect_identifiers($after_field);
-		}
-
-		return $sql;
-
+		return $sql.' '.$column_definition
+			.($default_value != '' ? ' DEFAULT "'.$default_value.'"' : '')
+			.($null === NULL ? ' NULL' : ' NOT NULL')
+			.($after_field != '' ? ' AFTER '.$this->db->escape_identifiers($after_field) : '');
 	}
 
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Rename a table
-	 *
-	 * Generates a platform-specific query so that a table can be renamed
-	 *
-	 * @access	private
-	 * @param	string	the old table name
-	 * @param	string	the new table name
-	 * @return	string
-	 */
-	function _rename_table($table_name, $new_table_name)
-	{
-		$sql = 'ALTER TABLE '.$this->db->_protect_identifiers($table_name)." RENAME TO ".$this->db->_protect_identifiers($new_table_name);
-		return $sql;
-	}
-
-
 }
 
 /* End of file odbc_forge.php */
diff --git a/system/database/drivers/odbc/odbc_result.php b/system/database/drivers/odbc/odbc_result.php
index ba66085..227fe4f 100644
--- a/system/database/drivers/odbc/odbc_result.php
+++ b/system/database/drivers/odbc/odbc_result.php
@@ -1,13 +1,13 @@
-<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
- * 
+ *
  * Licensed under the Open Software License version 3.0
- * 
+ *
  * This source file is subject to the Open Software License (OSL 3.0) that is
  * bundled with this package in the files license.txt / license.rst.  It is
  * also available through the world wide web at this URL:
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * ODBC Result Class
  *
@@ -38,26 +36,35 @@
  */
 class CI_DB_odbc_result extends CI_DB_result {
 
+	public $num_rows;
+
 	/**
 	 * Number of rows in the result set
 	 *
-	 * @access	public
-	 * @return	integer
+	 * @return	int
 	 */
-	function num_rows()
+	public function num_rows()
 	{
-		return @odbc_num_rows($this->result_id);
-	}
+		if (is_int($this->num_rows))
+		{
+			return $this->num_rows;
+		}
 
-	// --------------------------------------------------------------------
+		// Work-around for ODBC subdrivers that don't support num_rows()
+		if (($this->num_rows = @odbc_num_rows($this->result_id)) === -1)
+		{
+			$this->num_rows = count($this->result_array());
+		}
+
+		return $this->num_rows;
+	}
 
 	/**
 	 * Number of fields in the result set
 	 *
-	 * @access	public
-	 * @return	integer
+	 * @return	int
 	 */
-	function num_fields()
+	public function num_fields()
 	{
 		return @odbc_num_fields($this->result_id);
 	}
@@ -69,15 +76,19 @@
 	 *
 	 * Generates an array of column names
 	 *
-	 * @access	public
 	 * @return	array
 	 */
-	function list_fields()
+	public function list_fields()
 	{
 		$field_names = array();
-		for ($i = 0; $i < $this->num_fields(); $i++)
+		$num_fields = $this->num_fields();
+
+		if ($num_fields > 0)
 		{
-			$field_names[]	= odbc_field_name($this->result_id, $i);
+			for ($i = 1; $i <= $num_fields; $i++)
+			{
+				$field_names[] = odbc_field_name($this->result_id, $i);
+			}
 		}
 
 		return $field_names;
@@ -90,22 +101,19 @@
 	 *
 	 * Generates an array of objects containing field meta-data
 	 *
-	 * @access	public
 	 * @return	array
 	 */
-	function field_data()
+	public function field_data()
 	{
 		$retval = array();
-		for ($i = 0; $i < $this->num_fields(); $i++)
+		for ($i = 0, $odbc_index = 1, $c = $this->num_fields(); $i < $c; $i++, $odbc_index++)
 		{
-			$F				= new stdClass();
-			$F->name		= odbc_field_name($this->result_id, $i);
-			$F->type		= odbc_field_type($this->result_id, $i);
-			$F->max_length	= odbc_field_len($this->result_id, $i);
-			$F->primary_key = 0;
-			$F->default		= '';
-
-			$retval[] = $F;
+			$retval[$i]			= new stdClass();
+			$retval[$i]->name		= odbc_field_name($this->result_id, $odbc_index);
+			$retval[$i]->type		= odbc_field_type($this->result_id, $odbc_index);
+			$retval[$i]->max_length		= odbc_field_len($this->result_id, $odbc_index);
+			$retval[$i]->primary_key	= 0;
+			$retval[$i]->default		= '';
 		}
 
 		return $retval;
@@ -116,9 +124,9 @@
 	/**
 	 * Free the result
 	 *
-	 * @return	null
+	 * @return	void
 	 */
-	function free_result()
+	public function free_result()
 	{
 		if (is_resource($this->result_id))
 		{
@@ -130,40 +138,17 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 * Data Seek
-	 *
-	 * Moves the internal pointer to the desired offset.  We call
-	 * this internally before fetching results to make sure the
-	 * result set starts at zero
-	 *
-	 * @access	private
-	 * @return	array
-	 */
-	function _data_seek($n = 0)
-	{
-		return FALSE;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
 	 * Result - associative array
 	 *
 	 * Returns the result set as an array
 	 *
-	 * @access	private
 	 * @return	array
 	 */
-	function _fetch_assoc()
+	protected function _fetch_assoc()
 	{
-		if (function_exists('odbc_fetch_object'))
-		{
-			return odbc_fetch_array($this->result_id);
-		}
-		else
-		{
-			return $this->_odbc_fetch_array($this->result_id);
-		}
+		return function_exists('odbc_fetch_array')
+			? odbc_fetch_array($this->result_id)
+			: $this->_odbc_fetch_array($this->result_id);
 	}
 
 	// --------------------------------------------------------------------
@@ -173,21 +158,16 @@
 	 *
 	 * Returns the result set as an object
 	 *
-	 * @access	private
 	 * @return	object
 	 */
-	function _fetch_object()
+	protected function _fetch_object()
 	{
-		if (function_exists('odbc_fetch_object'))
-		{
-			return odbc_fetch_object($this->result_id);
-		}
-		else
-		{
-			return $this->_odbc_fetch_object($this->result_id);
-		}
+		return function_exists('odbc_fetch_object')
+			? odbc_fetch_object($this->result_id)
+			: $this->_odbc_fetch_object($this->result_id);
 	}
 
+	// --------------------------------------------------------------------
 
 	/**
 	 * Result - object
@@ -195,21 +175,27 @@
 	 * subsititutes the odbc_fetch_object function when
 	 * not available (odbc_fetch_object requires unixODBC)
 	 *
-	 * @access	private
 	 * @return	object
 	 */
-	function _odbc_fetch_object(& $odbc_result) {
+	protected function _odbc_fetch_object(& $odbc_result)
+	{
 		$rs = array();
-		$rs_obj = FALSE;
-		if (odbc_fetch_into($odbc_result, $rs)) {
-			foreach ($rs as $k=>$v) {
-				$field_name= odbc_field_name($odbc_result, $k+1);
-				$rs_obj->$field_name = $v;
-			}
+		if ( ! odbc_fetch_into($odbc_result, $rs))
+		{
+			return FALSE;
 		}
+
+		$rs_obj = new stdClass();
+		foreach ($rs as $k => $v)
+		{
+			$field_name = odbc_field_name($odbc_result, $k+1);
+			$rs_obj->$field_name = $v;
+		}
+
 		return $rs_obj;
 	}
 
+	// --------------------------------------------------------------------
 
 	/**
 	 * Result - array
@@ -217,24 +203,97 @@
 	 * subsititutes the odbc_fetch_array function when
 	 * not available (odbc_fetch_array requires unixODBC)
 	 *
-	 * @access	private
 	 * @return	array
 	 */
-	function _odbc_fetch_array(& $odbc_result) {
+	protected function _odbc_fetch_array(& $odbc_result)
+	{
 		$rs = array();
-		$rs_assoc = FALSE;
-		if (odbc_fetch_into($odbc_result, $rs)) {
-			$rs_assoc=array();
-			foreach ($rs as $k=>$v) {
-				$field_name= odbc_field_name($odbc_result, $k+1);
-				$rs_assoc[$field_name] = $v;
-			}
+		if ( ! odbc_fetch_into($odbc_result, $rs))
+		{
+			return FALSE;
 		}
+
+		$rs_assoc = array();
+		foreach ($rs as $k => $v)
+		{
+			$field_name = odbc_field_name($odbc_result, $k+1);
+			$rs_assoc[$field_name] = $v;
+		}
+
 		return $rs_assoc;
 	}
 
-}
+	// --------------------------------------------------------------------
 
+	/**
+	 * Query result. Array version.
+	 *
+	 * @return	array
+	 */
+	public function result_array()
+	{
+		if (count($this->result_array) > 0)
+		{
+			return $this->result_array;
+		}
+		elseif (($c = count($this->result_object)) > 0)
+		{
+			for ($i = 0; $i < $c; $i++)
+			{
+				$this->result_array[$i] = (array) $this->result_object[$i];
+			}
+		}
+		elseif ($this->result_id === FALSE)
+		{
+			return array();
+		}
+		else
+		{
+			while ($row = $this->_fetch_assoc())
+			{
+				$this->result_array[] = $row;
+			}
+		}
+
+		return $this->result_array;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Query result. Object version.
+	 *
+	 * @return	array
+	 */
+	public function result_object()
+	{
+		if (count($this->result_object) > 0)
+		{
+			return $this->result_object;
+		}
+		elseif (($c = count($this->result_array)) > 0)
+		{
+			for ($i = 0; $i < $c; $i++)
+			{
+				$this->result_object[$i] = (object) $this->result_array[$i];
+			}
+		}
+		elseif ($this->result_id === FALSE)
+		{
+			return array();
+		}
+		else
+		{
+			while ($row = $this->_fetch_object())
+			{
+				$this->result_object[] = $row;
+			}
+		}
+
+		return $this->result_object;
+	}
+
+}
 
 /* End of file odbc_result.php */
 /* Location: ./system/database/drivers/odbc/odbc_result.php */
\ No newline at end of file
diff --git a/system/database/drivers/odbc/odbc_utility.php b/system/database/drivers/odbc/odbc_utility.php
index bae3fe8..224d48d 100644
--- a/system/database/drivers/odbc/odbc_utility.php
+++ b/system/database/drivers/odbc/odbc_utility.php
@@ -1,13 +1,13 @@
-<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
- * 
+ *
  * Licensed under the Open Software License version 3.0
- * 
+ *
  * This source file is subject to the Open Software License (OSL 3.0) that is
  * bundled with this package in the files license.txt / license.rst.  It is
  * also available through the world wide web at this URL:
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * ODBC Utility Class
  *
@@ -36,74 +34,15 @@
  */
 class CI_DB_odbc_utility extends CI_DB_utility {
 
-	/**
-	 * List databases
-	 *
-	 * @access	private
-	 * @return	bool
-	 */
-	function _list_databases()
-	{
-		// Not sure if ODBC lets you list all databases...
-		if ($this->db->db_debug)
-		{
-			return $this->db->display_error('db_unsuported_feature');
-		}
-		return FALSE;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Optimize table query
-	 *
-	 * Generates a platform-specific query so that a table can be optimized
-	 *
-	 * @access	private
-	 * @param	string	the table name
-	 * @return	object
-	 */
-	function _optimize_table($table)
-	{
-		// Not a supported ODBC feature
-		if ($this->db->db_debug)
-		{
-			return $this->db->display_error('db_unsuported_feature');
-		}
-		return FALSE;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Repair table query
-	 *
-	 * Generates a platform-specific query so that a table can be repaired
-	 *
-	 * @access	private
-	 * @param	string	the table name
-	 * @return	object
-	 */
-	function _repair_table($table)
-	{
-		// Not a supported ODBC feature
-		if ($this->db->db_debug)
-		{
-			return $this->db->display_error('db_unsuported_feature');
-		}
-		return FALSE;
-	}
-
-	// --------------------------------------------------------------------
+	protected $_list_databases	= FALSE;
 
 	/**
 	 * ODBC Export
 	 *
-	 * @access	private
 	 * @param	array	Preferences
 	 * @return	mixed
 	 */
-	function _backup($params = array())
+	protected function _backup($params = array())
 	{
 		// Currently unsupported
 		return $this->db->display_error('db_unsuported_feature');
diff --git a/system/database/drivers/pdo/pdo_driver.php b/system/database/drivers/pdo/pdo_driver.php
index 4f4f44b..e25013a 100644
--- a/system/database/drivers/pdo/pdo_driver.php
+++ b/system/database/drivers/pdo/pdo_driver.php
@@ -1,13 +1,13 @@
-<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
- * 
+ *
  * Licensed under the Open Software License version 3.0
- * 
+ *
  * This source file is subject to the Open Software License (OSL 3.0) that is
  * bundled with this package in the files license.txt / license.rst.  It is
  * also available through the world wide web at this URL:
@@ -25,13 +25,11 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * PDO Database Adapter Class
  *
  * Note: _DB is an extender class that the app controller
- * creates dynamically based on whether the active record
+ * creates dynamically based on whether the query builder
  * class is being used or not.
  *
  * @package		CodeIgniter
@@ -42,75 +40,159 @@
  */
 class CI_DB_pdo_driver extends CI_DB {
 
-	var $dbdriver = 'pdo';
+	public $dbdriver = 'pdo';
 
 	// the character used to excape - not necessary for PDO
-	var $_escape_char = '';
-	var $_like_escape_str;
-	var $_like_escape_chr;
-	
+	protected $_escape_char = '';
+
+	// clause and character used for LIKE escape sequences
+	protected $_like_escape_str = " ESCAPE '%s' ";
+	protected $_like_escape_chr = '!';
 
 	/**
 	 * The syntax to count rows is slightly different across different
 	 * database engines, so this string appears in each driver and is
 	 * used for the count_all() and count_all_results() functions.
 	 */
-	var $_count_string = "SELECT COUNT(*) AS ";
-	var $_random_keyword;
-	
-	var $options = array();
+	protected $_count_string = 'SELECT COUNT(*) AS ';
+	protected $_random_keyword;
 
-	function __construct($params)
+	// need to track the pdo driver and options
+	public $pdodriver;
+	public $options = array();
+
+	public function __construct($params)
 	{
 		parent::__construct($params);
-		
-		// clause and character used for LIKE escape sequences
-		if (strpos($this->hostname, 'mysql') !== FALSE)
+
+		if (preg_match('/([^;]+):/', $this->dsn, $match) && count($match) === 2)
 		{
-			$this->_like_escape_str = '';
-			$this->_like_escape_chr = '';
-			
-			//Prior to this version, the charset can't be set in the dsn
-			if(is_php('5.3.6'))
-			{
-				$this->hostname .= ";charset={$this->char_set}";
-			}
-			
-			//Set the charset with the connection options
-			$this->options['PDO::MYSQL_ATTR_INIT_COMMAND'] = "SET NAMES {$this->char_set}";
-		}
-		else if (strpos($this->hostname, 'odbc') !== FALSE)
-		{
-			$this->_like_escape_str = " {escape '%s'} ";
-			$this->_like_escape_chr = '!';
+			// 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.
+			$this->pdodriver = end($match);
 		}
 		else
 		{
-			$this->_like_escape_str = " ESCAPE '%s' ";
-			$this->_like_escape_chr = '!';
+			// Try to build a complete DSN string from params
+			$this->_connect_string($params);
 		}
-		
-		if (strpos($this->hostname, 'sqlite') === FALSE)
-		{
-			$this->hostname .= ";dbname=".$this->database;
-		}
-		
-		$this->trans_enabled = FALSE;
 
+		// clause and character used for LIKE escape sequences
+		// this one depends on the driver being used
+		if ($this->pdodriver === 'mysql')
+		{
+			$this->_escape_char = '`';
+			$this->_like_escape_str = '';
+			$this->_like_escape_chr = '\\';
+		}
+		elseif ($this->pdodriver === 'odbc')
+		{
+			$this->_like_escape_str = " {escape '%s'} ";
+		}
+		elseif ( ! in_array($this->pdodriver, array('sqlsrv', 'mssql', 'dblib', 'sybase')))
+		{
+			$this->_escape_char = '"';
+		}
+
+		$this->trans_enabled = FALSE;
 		$this->_random_keyword = ' RND('.time().')'; // database specific random keyword
 	}
 
 	/**
+	 * Connection String
+	 *
+	 * @param	array
+	 * @return	void
+	 */
+	protected function _connect_string($params)
+	{
+		if (strpos($this->hostname, ':'))
+		{
+			// hostname generally would have this prototype
+			// $db['hostname'] = 'pdodriver:host(/Server(/DSN))=hostname(/DSN);';
+			// We need to get the prefix (pdodriver used by PDO).
+			$dsnarray = explode(':', $this->hostname);
+			$this->pdodriver = $dsnarray[0];
+
+			// End dsn with a semicolon for extra backward compability
+			// if database property was not empty.
+			if ( ! empty($this->database))
+			{
+				$this->dsn .= rtrim($this->hostname, ';').';';
+			}
+		}
+		else
+		{
+			// Invalid DSN, display an error
+			if ( ! array_key_exists('pdodriver', $params))
+			{
+				show_error('Invalid DB Connection String for PDO');
+			}
+
+			// Assuming that the following DSN string format is used:
+			// $dsn = 'pdo://username:password@hostname:port/database?pdodriver=pgsql';
+			$this->dsn = $this->pdodriver.':';
+
+			// Add hostname to the DSN for databases that need it
+			if ( ! empty($this->hostname)
+				&& strpos($this->hostname, ':') === FALSE
+				&& in_array($this->pdodriver, array('informix', 'mysql', 'pgsql', 'sybase', 'mssql', 'dblib', 'cubrid')))
+			{
+			    $this->dsn .= 'host='.$this->hostname.';';
+			}
+
+			// Add a port to the DSN for databases that can use it
+			if ( ! empty($this->port) && in_array($this->pdodriver, array('informix', 'mysql', 'pgsql', 'ibm', 'cubrid')))
+			{
+			    $this->dsn .= 'port='.$this->port.';';
+			}
+		}
+
+		// Add the database name to the DSN, if needed
+	    if (stripos($this->dsn, 'dbname') === FALSE
+	       && in_array($this->pdodriver, array('4D', 'pgsql', 'mysql', 'firebird', 'sybase', 'mssql', 'dblib', 'cubrid')))
+	    {
+	        $this->dsn .= 'dbname='.$this->database.';';
+	    }
+	    elseif (stripos($this->dsn, 'database') === FALSE && in_array($this->pdodriver, array('ibm', 'sqlsrv')))
+	    {
+	    	if (stripos($this->dsn, 'dsn') === FALSE)
+	    	{
+		        $this->dsn .= 'database='.$this->database.';';
+	    	}
+	    }
+	    elseif ($this->pdodriver === 'sqlite' && $this->dsn === 'sqlite:')
+	    {
+	        if ($this->database !== ':memory')
+	        {
+	            if ( ! file_exists($this->database))
+	            {
+	                show_error('Invalid DB Connection string for PDO SQLite');
+	            }
+
+	            $this->dsn .= (strpos($this->database, DIRECTORY_SEPARATOR) !== 0) ? DIRECTORY_SEPARATOR : '';
+	        }
+
+	        $this->dsn .= $this->database;
+	    }
+
+	    // Add charset to the DSN, if needed
+	    if ( ! empty($this->char_set) && in_array($this->pdodriver, array('4D', 'mysql', 'sybase', 'mssql', 'dblib', 'oci')))
+	    {
+	        $this->dsn .= 'charset='.$this->char_set.';';
+	    }
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
 	 * Non-persistent database connection
 	 *
-	 * @access	private called by the base class
-	 * @return	resource
+	 * @return	object
 	 */
-	function db_connect()
+	public function db_connect()
 	{
-		$this->options['PDO::ATTR_ERRMODE'] = PDO::ERRMODE_SILENT;
-		
-		return new PDO($this->hostname, $this->username, $this->password, $this->options);
+		return $this->_pdo_connect();
 	}
 
 	// --------------------------------------------------------------------
@@ -118,78 +200,65 @@
 	/**
 	 * Persistent database connection
 	 *
-	 * @access	private called by the base class
-	 * @return	resource
+	 * @return	object
 	 */
-	function db_pconnect()
+	public function db_pconnect()
 	{
-		$this->options['PDO::ATTR_ERRMODE'] = PDO::ERRMODE_SILENT;
-		$this->options['PDO::ATTR_PERSISTENT'] = TRUE;
-	
-		return new PDO($this->hostname, $this->username, $this->password, $this->options);
+		return $this->_pdo_connect(TRUE);
 	}
 
 	// --------------------------------------------------------------------
 
 	/**
-	 * Reconnect
+	 * PDO connection
 	 *
-	 * Keep / reestablish the db connection if no queries have been
-	 * sent for a length of time exceeding the server's idle timeout
-	 *
-	 * @access	public
-	 * @return	void
+	 * @param	bool
+	 * @return	object
 	 */
-	function reconnect()
+	protected function _pdo_connect($persistent = FALSE)
 	{
-		if ($this->db->db_debug)
+		$this->options[PDO::ATTR_ERRMODE] = PDO::ERRMODE_SILENT;
+		$persistent === FALSE OR $this->options[PDO::ATTR_PERSISTENT] = TRUE;
+
+		/* Prior to PHP 5.3.6, even if the charset was supplied in the DSN
+		 * on connect - it was ignored. This is a work-around for the issue.
+		 *
+		 * Reference: http://www.php.net/manual/en/ref.pdo-mysql.connection.php
+		 */
+		if ($this->pdodriver === 'mysql' && ! is_php('5.3.6') && ! empty($this->char_set))
 		{
-			return $this->db->display_error('db_unsuported_feature');
+			$this->options[PDO::MYSQL_ATTR_INIT_COMMAND] = 'SET NAMES '.$this->char_set
+					.( ! empty($this->db_collat) ? " COLLATE '".$this->dbcollat."'" : '');
 		}
-		return FALSE;
+
+		// Connecting...
+		try
+		{
+			return new PDO($this->dsn, $this->username, $this->password, $this->options);
+		}
+		catch (PDOException $e)
+		{
+			if ($this->db_debug && empty($this->failover))
+			{
+				$this->display_error($e->getMessage(), '', TRUE);
+			}
+
+			return FALSE;
+		}
 	}
 
 	// --------------------------------------------------------------------
 
 	/**
-	 * Select the database
+	 * Database version number
 	 *
-	 * @access	private called by the base class
-	 * @return	resource
-	 */
-	function db_select()
-	{
-		// Not needed for PDO
-		return TRUE;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Set client character set
-	 *
-	 * @access	public
-	 * @param	string
-	 * @param	string
-	 * @return	resource
-	 */
-	function db_set_charset($charset, $collation)
-	{
-		// @todo - add support if needed
-		return TRUE;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Version number query string
-	 *
-	 * @access	public
 	 * @return	string
 	 */
-	function _version()
+	public function version()
 	{
-		return $this->conn_id->getAttribute(PDO::ATTR_CLIENT_VERSION);
+		return isset($this->data_cache['version'])
+			? $this->data_cache['version']
+			: $this->data_cache['version'] = $this->conn_id->getAttribute(PDO::ATTR_SERVER_VERSION);
 	}
 
 	// --------------------------------------------------------------------
@@ -197,41 +266,12 @@
 	/**
 	 * Execute the query
 	 *
-	 * @access	private called by the base class
 	 * @param	string	an SQL query
-	 * @return	object
+	 * @return	mixed
 	 */
-	function _execute($sql)
+	protected function _execute($sql)
 	{
-		$sql = $this->_prep_query($sql);
-		$result_id = $this->conn_id->query($sql);
-		
-		if (is_object($result_id))
-		{
-			$this->affect_rows = $result_id->rowCount();
-		}
-		else
-		{
-			$this->affect_rows = 0;
-		}
-		
-		return $result_id;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Prep the query
-	 *
-	 * If needed, each database adapter can prep the query string
-	 *
-	 * @access	private called by execute()
-	 * @param	string	an SQL query
-	 * @return	string
-	 */
-	function _prep_query($sql)
-	{
-		return $sql;
+		return $this->conn_id->query($sql);
 	}
 
 	// --------------------------------------------------------------------
@@ -239,18 +279,12 @@
 	/**
 	 * Begin Transaction
 	 *
-	 * @access	public
 	 * @return	bool
 	 */
-	function trans_begin($test_mode = FALSE)
+	public function trans_begin($test_mode = FALSE)
 	{
-		if ( ! $this->trans_enabled)
-		{
-			return TRUE;
-		}
-
 		// When transactions are nested we only begin/commit/rollback the outermost ones
-		if ($this->_trans_depth > 0)
+		if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
 		{
 			return TRUE;
 		}
@@ -258,7 +292,7 @@
 		// Reset the transaction failure flag.
 		// If the $test_mode flag is set to TRUE transactions will be rolled back
 		// even if the queries produce a successful result.
-		$this->_trans_failure = (bool) ($test_mode === TRUE);
+		$this->_trans_failure = ($test_mode === TRUE);
 
 		return $this->conn_id->beginTransaction();
 	}
@@ -268,24 +302,17 @@
 	/**
 	 * Commit Transaction
 	 *
-	 * @access	public
 	 * @return	bool
 	 */
-	function trans_commit()
+	public function trans_commit()
 	{
-		if ( ! $this->trans_enabled)
-		{
-			return TRUE;
-		}
-
 		// When transactions are nested we only begin/commit/rollback the outermost ones
-		if ($this->_trans_depth > 0)
+		if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
 		{
 			return TRUE;
 		}
 
-		$ret = $this->conn->commit();
-		return $ret;
+		return $this->conn_id->commit();
 	}
 
 	// --------------------------------------------------------------------
@@ -293,24 +320,17 @@
 	/**
 	 * Rollback Transaction
 	 *
-	 * @access	public
 	 * @return	bool
 	 */
-	function trans_rollback()
+	public function trans_rollback()
 	{
-		if ( ! $this->trans_enabled)
-		{
-			return TRUE;
-		}
-
 		// When transactions are nested we only begin/commit/rollback the outermost ones
-		if ($this->_trans_depth > 0)
+		if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
 		{
 			return TRUE;
 		}
 
-		$ret = $this->conn_id->rollBack();
-		return $ret;
+		return $this->conn_id->rollBack();
 	}
 
 	// --------------------------------------------------------------------
@@ -318,12 +338,11 @@
 	/**
 	 * Escape String
 	 *
-	 * @access	public
 	 * @param	string
 	 * @param	bool	whether or not the string will be used in a LIKE condition
 	 * @return	string
 	 */
-	function escape_str($str, $like = FALSE)
+	public function escape_str($str, $like = FALSE)
 	{
 		if (is_array($str))
 		{
@@ -334,22 +353,22 @@
 
 			return $str;
 		}
-		
-		//Escape the string
+
+		// Escape the string
 		$str = $this->conn_id->quote($str);
-		
-		//If there are duplicated quotes, trim them away
+
+		// If there are duplicated quotes, trim them away
 		if (strpos($str, "'") === 0)
 		{
 			$str = substr($str, 1, -1);
 		}
-		
+
 		// escape LIKE condition wildcards
 		if ($like === TRUE)
 		{
-			$str = str_replace(	array('%', '_', $this->_like_escape_chr),
-								array($this->_like_escape_chr.'%', $this->_like_escape_chr.'_', $this->_like_escape_chr.$this->_like_escape_chr),
-								$str);
+			return str_replace(array($this->_like_escape_chr, '%', '_'),
+						array($this->_like_escape_chr.$this->_like_escape_chr, $this->_like_escape_chr.'%', $this->_like_escape_chr.'_'),
+						$str);
 		}
 
 		return $str;
@@ -360,74 +379,31 @@
 	/**
 	 * Affected Rows
 	 *
-	 * @access	public
-	 * @return	integer
+	 * @return	int
 	 */
-	function affected_rows()
+	public function affected_rows()
 	{
-		return $this->affect_rows;
+		return is_object($this->result_id) ? $this->result_id->rowCount() : 0;
 	}
 
 	// --------------------------------------------------------------------
 
 	/**
 	 * Insert ID
-	 * 
-	 * @access	public
-	 * @return	integer
-	 */
-	function insert_id($name=NULL)
-	{
-		//Convenience method for postgres insertid
-		if (strpos($this->hostname, 'pgsql') !== FALSE)
-		{
-			$v = $this->_version();
-
-			$table	= func_num_args() > 0 ? func_get_arg(0) : NULL;
-
-			if ($table == NULL && $v >= '8.1')
-			{
-				$sql='SELECT LASTVAL() as ins_id';
-			}
-			$query = $this->query($sql);
-			$row = $query->row();
-			return $row->ins_id;
-		}
-		else
-		{
-			return $this->conn_id->lastInsertId($name);
-		}
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * "Count All" query
 	 *
-	 * Generates a platform-specific query string that counts all records in
-	 * the specified database
-	 *
-	 * @access	public
 	 * @param	string
-	 * @return	string
+	 * @return	int
 	 */
-	function count_all($table = '')
+	public function insert_id($name = NULL)
 	{
-		if ($table == '')
+		if ($this->pdodriver === 'pgsql' && $name === NULL && $this->version() >= '8.1')
 		{
-			return 0;
+			$query = $this->query('SELECT LASTVAL() AS ins_id');
+			$query = $query->row();
+			return $query->ins_id;
 		}
 
-		$query = $this->query($this->_count_string . $this->_protect_identifiers('numrows') . " FROM " . $this->_protect_identifiers($table, TRUE, NULL, FALSE));
-
-		if ($query->num_rows() == 0)
-		{
-			return 0;
-		}
-
-		$row = $query->row();
-		$this->_reset_select();
-		return (int) $row->numrows;
+		return $this->conn_id->lastInsertId($name);
 	}
 
 	// --------------------------------------------------------------------
@@ -437,18 +413,29 @@
 	 *
 	 * Generates a platform-specific query string so that the table names can be fetched
 	 *
-	 * @access	private
-	 * @param	boolean
+	 * @param	bool
 	 * @return	string
 	 */
-	function _list_tables($prefix_limit = FALSE)
+	protected function _list_tables($prefix_limit = FALSE)
 	{
-		$sql = "SHOW TABLES FROM `".$this->database."`";
-
-		if ($prefix_limit !== FALSE AND $this->dbprefix != '')
+		if ($this->pdodriver === 'pgsql')
 		{
-			//$sql .= " LIKE '".$this->escape_like_str($this->dbprefix)."%' ".sprintf($this->_like_escape_str, $this->_like_escape_chr);
-			return FALSE; // not currently supported
+			// Analog function to show all tables in postgre
+			$sql = "SELECT * FROM information_schema.tables WHERE table_schema = 'public'";
+		}
+		elseif ($this->pdodriver === 'sqlite')
+		{
+			// Analog function to show all tables in sqlite
+			$sql = "SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%'";
+		}
+		else
+		{
+			$sql = 'SHOW TABLES FROM '.$this->escape_identifiers($this->database);
+		}
+
+		if ($prefix_limit !== FALSE AND $this->dbprefix !== '')
+		{
+			return FALSE;
 		}
 
 		return $sql;
@@ -461,13 +448,12 @@
 	 *
 	 * Generates a platform-specific query string so that the column names can be fetched
 	 *
-	 * @access	public
 	 * @param	string	the table name
 	 * @return	string
 	 */
-	function _list_columns($table = '')
+	protected function _list_columns($table = '')
 	{
-		return "SHOW COLUMNS FROM ".$table;
+		return 'SHOW COLUMNS FROM '.$this->escape_identifiers($table);
 	}
 
 	// --------------------------------------------------------------------
@@ -477,195 +463,75 @@
 	 *
 	 * Generates a platform-specific query so that the column data can be retrieved
 	 *
-	 * @access	public
 	 * @param	string	the table name
-	 * @return	object
-	 */
-	function _field_data($table)
-	{
-		return "SELECT TOP 1 FROM ".$table;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * The error message string
-	 *
-	 * @access	private
 	 * @return	string
 	 */
-	function _error_message()
+	protected function _field_data($table)
 	{
-		$error_array = $this->conn_id->errorInfo();
-		return $error_array[2];
+		if ($this->pdodriver === 'mysql' or $this->pdodriver === 'pgsql')
+		{
+			// Analog function for mysql and postgre
+			return 'SELECT * FROM '.$this->escape_identifiers($table).' LIMIT 1';
+		}
+		elseif ($this->pdodriver === 'oci')
+		{
+			// Analog function for oci
+			return 'SELECT * FROM '.$this->escape_identifiers($table).' WHERE ROWNUM <= 1';
+		}
+		elseif ($this->pdodriver === 'sqlite')
+		{
+			// Analog function for sqlite
+			return 'PRAGMA table_info('.$this->escape_identifiers($table).')';
+		}
+
+		return 'SELECT TOP 1 FROM '.$this->escape_identifiers($table);
 	}
 
 	// --------------------------------------------------------------------
 
 	/**
-	 * The error message number
+	 * Error
 	 *
-	 * @access	private
-	 * @return	integer
+	 * Returns an array containing code and message of the last
+	 * database error that has occured.
+	 *
+	 * @return	array
 	 */
-	function _error_number()
+	public function error()
 	{
-		return $this->conn_id->errorCode();
-	}
+		$error = array('code' => '00000', 'message' => '');
+		$pdo_error = $this->conn_id->errorInfo();
 
-	// --------------------------------------------------------------------
-
-	/**
-	 * Escape the SQL Identifiers
-	 *
-	 * This function escapes column and table names
-	 *
-	 * @access	private
-	 * @param	string
-	 * @return	string
-	 */
-	function _escape_identifiers($item)
-	{
-		if ($this->_escape_char == '')
+		if (empty($pdo_error[0]))
 		{
-			return $item;
+			return $error;
 		}
 
-		foreach ($this->_reserved_identifiers as $id)
+		$error['code'] = isset($pdo_error[1]) ? $pdo_error[0].'/'.$pdo_error[1] : $pdo_error[0];
+		if (isset($pdo_error[2]))
 		{
-			if (strpos($item, '.'.$id) !== FALSE)
-			{
-				$str = $this->_escape_char. str_replace('.', $this->_escape_char.'.', $item);
-
-				// remove duplicates if the user already included the escape
-				return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str);
-			}
+			 $error['message'] = $pdo_error[2];
 		}
 
-		if (strpos($item, '.') !== FALSE)
-		{
-			$str = $this->_escape_char.str_replace('.', $this->_escape_char.'.'.$this->_escape_char, $item).$this->_escape_char;
-			
-		}
-		else
-		{
-			$str = $this->_escape_char.$item.$this->_escape_char;
-		}
-
-		// remove duplicates if the user already included the escape
-		return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str);
+		return $error;
 	}
 
 	// --------------------------------------------------------------------
 
 	/**
-	 * From Tables
-	 *
-	 * This function implicitly groups FROM tables so there is no confusion
-	 * about operator precedence in harmony with SQL standards
-	 *
-	 * @access	public
-	 * @param	type
-	 * @return	type
-	 */
-	function _from_tables($tables)
-	{
-		if ( ! is_array($tables))
-		{
-			$tables = array($tables);
-		}
-
-		return (count($tables) == 1) ? $tables[0] : '('.implode(', ', $tables).')';
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Insert statement
-	 *
-	 * Generates a platform-specific insert string from the supplied data
-	 *
-	 * @access	public
-	 * @param	string	the table name
-	 * @param	array	the insert keys
-	 * @param	array	the insert values
-	 * @return	string
-	 */
-	function _insert($table, $keys, $values)
-	{
-		return "INSERT INTO ".$table." (".implode(', ', $keys).") VALUES (".implode(', ', $values).")";
-	}
-	
-	// --------------------------------------------------------------------
-
-	/**
-	 * Insert_batch statement
-	 *
-	 * Generates a platform-specific insert string from the supplied data
-	 *
-	 * @access  public
-	 * @param   string  the table name
-	 * @param   array   the insert keys
-	 * @param   array   the insert values
-	 * @return  string
-	 */
-	function _insert_batch($table, $keys, $values)
-	{
-		return "INSERT INTO ".$table." (".implode(', ', $keys).") VALUES ".implode(', ', $values);
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Update statement
-	 *
-	 * Generates a platform-specific update string from the supplied data
-	 *
-	 * @access	public
-	 * @param	string	the table name
-	 * @param	array	the update data
-	 * @param	array	the where clause
-	 * @param	array	the orderby clause
-	 * @param	array	the limit clause
-	 * @return	string
-	 */
-	function _update($table, $values, $where, $orderby = array(), $limit = FALSE)
-	{
-		foreach ($values as $key => $val)
-		{
-			$valstr[] = $key." = ".$val;
-		}
-
-		$limit = ( ! $limit) ? '' : ' LIMIT '.$limit;
-
-		$orderby = (count($orderby) >= 1)?' ORDER BY '.implode(", ", $orderby):'';
-
-		$sql = "UPDATE ".$table." SET ".implode(', ', $valstr);
-
-		$sql .= ($where != '' AND count($where) >=1) ? " WHERE ".implode(" ", $where) : '';
-
-		$sql .= $orderby.$limit;
-
-		return $sql;
-	}
-	
-	// --------------------------------------------------------------------
-
-	/**
 	 * Update_Batch statement
 	 *
 	 * Generates a platform-specific batch update string from the supplied data
 	 *
-	 * @access	public
 	 * @param	string	the table name
 	 * @param	array	the update data
 	 * @param	array	the where clause
 	 * @return	string
 	 */
-	function _update_batch($table, $values, $index, $where = NULL)
+	protected function _update_batch($table, $values, $index, $where = NULL)
 	{
-		$ids = array();
-		$where = ($where != '' AND count($where) >=1) ? implode(" ", $where).' AND ' : '';
+		$ids   = array();
+		$where = ($where !== '' && count($where) >=1) ? implode(" ", $where).' AND ' : '';
 
 		foreach ($values as $key => $val)
 		{
@@ -673,19 +539,20 @@
 
 			foreach (array_keys($val) as $field)
 			{
-				if ($field != $index)
+				if ($field !== $index)
 				{
 					$final[$field][] =  'WHEN '.$index.' = '.$val[$index].' THEN '.$val[$field];
 				}
 			}
 		}
 
-		$sql = "UPDATE ".$table." SET ";
+		$sql   = 'UPDATE '.$table.' SET ';
 		$cases = '';
 
 		foreach ($final as $k => $v)
 		{
 			$cases .= $k.' = CASE '."\n";
+
 			foreach ($v as $row)
 			{
 				$cases .= $row."\n";
@@ -695,63 +562,27 @@
 		}
 
 		$sql .= substr($cases, 0, -2);
-
 		$sql .= ' WHERE '.$where.$index.' IN ('.implode(',', $ids).')';
 
 		return $sql;
 	}
 
-
 	// --------------------------------------------------------------------
 
 	/**
 	 * Truncate statement
 	 *
 	 * Generates a platform-specific truncate string from the supplied data
-	 * If the database does not support the truncate() command
-	 * This function maps to "DELETE FROM table"
 	 *
-	 * @access	public
+	 * If the database does not support the truncate() command,
+	 * then this method maps to 'DELETE FROM table'
+	 *
 	 * @param	string	the table name
 	 * @return	string
 	 */
-	function _truncate($table)
+	protected function _truncate($table)
 	{
-		return $this->_delete($table);
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Delete statement
-	 *
-	 * Generates a platform-specific delete string from the supplied data
-	 *
-	 * @access	public
-	 * @param	string	the table name
-	 * @param	array	the where clause
-	 * @param	string	the limit clause
-	 * @return	string
-	 */
-	function _delete($table, $where = array(), $like = array(), $limit = FALSE)
-	{
-		$conditions = '';
-
-		if (count($where) > 0 OR count($like) > 0)
-		{
-			$conditions = "\nWHERE ";
-			$conditions .= implode("\n", $this->ar_where);
-
-			if (count($where) > 0 && count($like) > 0)
-			{
-				$conditions .= " AND ";
-			}
-			$conditions .= implode("\n", $like);
-		}
-
-		$limit = ( ! $limit) ? '' : ' LIMIT '.$limit;
-
-		return "DELETE FROM ".$table.$conditions.$limit;
+		return 'DELETE FROM '.$table;
 	}
 
 	// --------------------------------------------------------------------
@@ -761,58 +592,29 @@
 	 *
 	 * Generates a platform-specific LIMIT clause
 	 *
-	 * @access	public
 	 * @param	string	the sql query string
-	 * @param	integer	the number of rows to limit the query to
-	 * @param	integer	the offset value
+	 * @param	int	the number of rows to limit the query to
+	 * @param	int	the offset value
 	 * @return	string
 	 */
-	function _limit($sql, $limit, $offset)
+	protected function _limit($sql, $limit, $offset)
 	{
-		if (strpos($this->hostname, 'cubrid') !== FALSE || strpos($this->hostname, 'sqlite') !== FALSE)
+		if ($this->pdodriver === 'cubrid' OR $this->pdodriver === 'sqlite')
 		{
-			if ($offset == 0)
-			{
-				$offset = '';
-			}
-			else
-			{
-				$offset .= ", ";
-			}
+			$offset = ($offset == 0) ? '' : $offset.', ';
 
-			return $sql."LIMIT ".$offset.$limit;
+			return $sql.'LIMIT '.$offset.$limit;
 		}
 		else
 		{
-			$sql .= "LIMIT ".$limit;
+			$sql .= 'LIMIT '.$limit;
+			$sql .= ($offset > 0) ? ' OFFSET '.$offset : '';
 
-			if ($offset > 0)
-			{
-				$sql .= " OFFSET ".$offset;
-			}
-			
 			return $sql;
 		}
 	}
 
-	// --------------------------------------------------------------------
-
-	/**
-	 * Close DB Connection
-	 *
-	 * @access	public
-	 * @param	resource
-	 * @return	void
-	 */
-	function _close($conn_id)
-	{
-		$this->conn_id = null;
-	}
-
-
 }
 
-
-
 /* End of file pdo_driver.php */
 /* Location: ./system/database/drivers/pdo/pdo_driver.php */
\ No newline at end of file
diff --git a/system/database/drivers/pdo/pdo_forge.php b/system/database/drivers/pdo/pdo_forge.php
index 0764159..02ceb74 100644
--- a/system/database/drivers/pdo/pdo_forge.php
+++ b/system/database/drivers/pdo/pdo_forge.php
@@ -1,13 +1,13 @@
-<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
- * 
+ *
  * Licensed under the Open Software License version 3.0
- * 
+ *
  * This source file is subject to the Open Software License (OSL 3.0) that is
  * bundled with this package in the files license.txt / license.rst.  It is
  * also available through the world wide web at this URL:
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * PDO Forge Class
  *
@@ -36,58 +34,20 @@
  */
 class CI_DB_pdo_forge extends CI_DB_forge {
 
-	/**
-	 * Create database
-	 *
-	 * @access	private
-	 * @param	string	the database name
-	 * @return	bool
-	 */
-	function _create_database()
-	{
-		// PDO has no "create database" command since it's
-		// designed to connect to an existing database
-		if ($this->db->db_debug)
-		{
-			return $this->db->display_error('db_unsuported_feature');
-		}
-		return FALSE;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Drop database
-	 *
-	 * @access	private
-	 * @param	string	the database name
-	 * @return	bool
-	 */
-	function _drop_database($name)
-	{
-		// PDO has no "drop database" command since it's
-		// designed to connect to an existing database
-		if ($this->db->db_debug)
-		{
-			return $this->db->display_error('db_unsuported_feature');
-		}
-		return FALSE;
-	}
-
-	// --------------------------------------------------------------------
+	protected $_drop_database	= 'DROP DATABASE %s';
+	protected $_drop_table		= 'DROP TABLE %s';
 
 	/**
 	 * Create Table
 	 *
-	 * @access	private
 	 * @param	string	the table name
 	 * @param	array	the fields
 	 * @param	mixed	primary key(s)
 	 * @param	mixed	key(s)
-	 * @param	boolean	should 'IF NOT EXISTS' be added to the SQL
+	 * @param	bool	should 'IF NOT EXISTS' be added to the SQL
 	 * @return	bool
 	 */
-	function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists)
+	protected function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists)
 	{
 		$sql = 'CREATE TABLE ';
 
@@ -96,51 +56,48 @@
 			$sql .= 'IF NOT EXISTS ';
 		}
 
-		$sql .= $this->db->_escape_identifiers($table)." (";
+		$sql .= $this->db->escape_identifiers($table).' (';
 		$current_field_count = 0;
 
-		foreach ($fields as $field=>$attributes)
+		foreach ($fields as $field => $attributes)
 		{
 			// Numeric field names aren't allowed in databases, so if the key is
 			// numeric, we know it was assigned by PHP and the developer manually
 			// entered the field information, so we'll simply add it to the list
 			if (is_numeric($field))
 			{
-				$sql .= "\n\t$attributes";
+				$sql .= "\n\t".$attributes;
 			}
 			else
 			{
 				$attributes = array_change_key_case($attributes, CASE_UPPER);
+				$numeric = array('SERIAL', 'INTEGER');
 
-				$sql .= "\n\t".$this->db->_protect_identifiers($field);
+				$sql .= "\n\t".$this->db->escape_identifiers($field).' '.$attributes['TYPE'];
 
-				$sql .=  ' '.$attributes['TYPE'];
-
-				if (array_key_exists('CONSTRAINT', $attributes))
+				if ( ! empty($attributes['CONSTRAINT']))
 				{
-					$sql .= '('.$attributes['CONSTRAINT'].')';
+					// Exception for Postgre numeric which not too happy with constraint within those type
+					if ( ! ($this->db->pdodriver === 'pgsql' && in_array($attributes['TYPE'], $numeric)))
+					{
+						$sql .= '('.$attributes['CONSTRAINT'].')';
+					}
 				}
 
-				if (array_key_exists('UNSIGNED', $attributes) && $attributes['UNSIGNED'] === TRUE)
+				if ( ! empty($attributes['UNSIGNED']) && $attributes['UNSIGNED'] === TRUE)
 				{
 					$sql .= ' UNSIGNED';
 				}
 
-				if (array_key_exists('DEFAULT', $attributes))
+				if (isset($attributes['DEFAULT']))
 				{
-					$sql .= ' DEFAULT \''.$attributes['DEFAULT'].'\'';
+					$sql .= " DEFAULT '".$attributes['DEFAULT']."'";
 				}
 
-				if (array_key_exists('NULL', $attributes) && $attributes['NULL'] === TRUE)
-				{
-					$sql .= ' NULL';
-				}
-				else
-				{
-					$sql .= ' NOT NULL';
-				}
+				$sql .= ( ! empty($attributes['NULL']) && $attributes['NULL'] === TRUE)
+					? ' NULL' : ' NOT NULL';
 
-				if (array_key_exists('AUTO_INCREMENT', $attributes) && $attributes['AUTO_INCREMENT'] === TRUE)
+				if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE)
 				{
 					$sql .= ' AUTO_INCREMENT';
 				}
@@ -155,48 +112,22 @@
 
 		if (count($primary_keys) > 0)
 		{
-			$primary_keys = $this->db->_protect_identifiers($primary_keys);
-			$sql .= ",\n\tPRIMARY KEY (" . implode(', ', $primary_keys) . ")";
+			$sql .= ",\n\tPRIMARY KEY (".implode(', ', $this->db->escape_identifiers($primary_keys)).')';
 		}
 
 		if (is_array($keys) && count($keys) > 0)
 		{
 			foreach ($keys as $key)
 			{
-				if (is_array($key))
-				{
-					$key = $this->db->_protect_identifiers($key);
-				}
-				else
-				{
-					$key = array($this->db->_protect_identifiers($key));
-				}
+				$key = is_array($key)
+					? $this->db->escape_identifiers($key)
+					: array($this->db->escape_identifiers($key));
 
-				$sql .= ",\n\tFOREIGN KEY (" . implode(', ', $key) . ")";
+				$sql .= ",\n\tFOREIGN KEY (".implode(', ', $key).')';
 			}
 		}
 
-		$sql .= "\n)";
-
-		return $sql;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Drop Table
-	 *
-	 * @access	private
-	 * @return	bool
-	 */
-	function _drop_table($table)
-	{
-		// Not a supported PDO feature
-		if ($this->db->db_debug)
-		{
-			return $this->db->display_error('db_unsuported_feature');
-		}
-		return FALSE;
+		return $sql."\n)";
 	}
 
 	// --------------------------------------------------------------------
@@ -207,71 +138,31 @@
 	 * Generates a platform-specific query so that a table can be altered
 	 * Called by add_column(), drop_column(), and column_alter(),
 	 *
-	 * @access	private
 	 * @param	string	the ALTER type (ADD, DROP, CHANGE)
 	 * @param	string	the column name
 	 * @param	string	the table name
 	 * @param	string	the column definition
 	 * @param	string	the default value
-	 * @param	boolean	should 'NOT NULL' be added
+	 * @param	bool	should 'NOT NULL' be added
 	 * @param	string	the field after which we should add the new field
-	 * @return	object
+	 * @return	string
 	 */
-	function _alter_table($alter_type, $table, $column_name, $column_definition = '', $default_value = '', $null = '', $after_field = '')
+	protected function _alter_table($alter_type, $table, $column_name, $column_definition = '', $default_value = '', $null = '', $after_field = '')
 	{
-		$sql = 'ALTER TABLE '.$this->db->_protect_identifiers($table)." $alter_type ".$this->db->_protect_identifiers($column_name);
+		$sql = 'ALTER TABLE '.$this->db->escape_identifiers($table).' '.$alter_type.' '.$this->db->escape_identifiers($column_name);
 
 		// DROP has everything it needs now.
-		if ($alter_type == 'DROP')
+		if ($alter_type === 'DROP')
 		{
 			return $sql;
 		}
 
-		$sql .= " $column_definition";
-
-		if ($default_value != '')
-		{
-			$sql .= " DEFAULT \"$default_value\"";
-		}
-
-		if ($null === NULL)
-		{
-			$sql .= ' NULL';
-		}
-		else
-		{
-			$sql .= ' NOT NULL';
-		}
-
-		if ($after_field != '')
-		{
-			$sql .= ' AFTER ' . $this->db->_protect_identifiers($after_field);
-		}
-
-		return $sql;
-
+		return $sql .' '.$column_definition
+			.($default_value !== '' ? " DEFAULT '".$default_value."'" : '')
+			.($null === NULL ? ' NULL' : ' NOT NULL')
+			.($after_field !== '' ? ' AFTER '.$this->db->escape_identifiers($after_field) : '');
 	}
 
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Rename a table
-	 *
-	 * Generates a platform-specific query so that a table can be renamed
-	 *
-	 * @access	private
-	 * @param	string	the old table name
-	 * @param	string	the new table name
-	 * @return	string
-	 */
-	function _rename_table($table_name, $new_table_name)
-	{
-		$sql = 'ALTER TABLE '.$this->db->_protect_identifiers($table_name)." RENAME TO ".$this->db->_protect_identifiers($new_table_name);
-		return $sql;
-	}
-
-
 }
 
 /* End of file pdo_forge.php */
diff --git a/system/database/drivers/pdo/pdo_result.php b/system/database/drivers/pdo/pdo_result.php
index 6b523b0..0b8937c 100644
--- a/system/database/drivers/pdo/pdo_result.php
+++ b/system/database/drivers/pdo/pdo_result.php
@@ -1,13 +1,13 @@
-<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
- * 
+ *
  * Licensed under the Open Software License version 3.0
- * 
+ *
  * This source file is subject to the Open Software License (OSL 3.0) that is
  * bundled with this package in the files license.txt / license.rst.  It is
  * also available through the world wide web at this URL:
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * PDO Result Class
  *
@@ -39,14 +37,68 @@
 class CI_DB_pdo_result extends CI_DB_result {
 
 	/**
+	 * @var bool  Hold the flag whether a result handler already fetched before
+	 */
+	protected $is_fetched = FALSE;
+
+	/**
+	 * @var mixed Hold the fetched assoc array of a result handler
+	 */
+	protected $result_assoc;
+
+	/**
 	 * Number of rows in the result set
 	 *
-	 * @access	public
-	 * @return	integer
+	 * @return	int
 	 */
-	function num_rows()
+	public function num_rows()
 	{
-		return $this->result_id->rowCount();
+		if (empty($this->result_id) OR ! is_object($this->result_id))
+		{
+			// invalid result handler
+			return 0;
+		}
+		elseif (($num_rows = $this->result_id->rowCount()) && $num_rows > 0)
+		{
+			// If rowCount return something, we're done.
+			return $num_rows;
+		}
+
+		// Fetch the result, instead perform another extra query
+		return ($this->is_fetched && is_array($this->result_assoc)) ? count($this->result_assoc) : count($this->result_assoc());
+	}
+
+	/**
+	 * Fetch the result handler
+	 *
+	 * @return	mixed
+	 */
+	public function result_assoc()
+	{
+		// If the result already fetched before, use that one
+		if (count($this->result_array) > 0 OR $this->is_fetched)
+		{
+			return $this->result_array();
+		}
+
+		// Define the output
+		$output = array('assoc', 'object');
+
+		// Initial value
+		$this->result_assoc = array() and $this->result_object = array();
+
+		// Fetch the result
+		while ($row = $this->_fetch_assoc())
+		{
+			$this->result_assoc[] = $row;
+			$this->result_object[] = (object) $row;
+		}
+
+		// Save this as buffer and marked the fetch flag
+		$this->result_array = $this->result_assoc;
+		$this->is_fetched = TRUE;
+
+		return $this->result_assoc;
 	}
 
 	// --------------------------------------------------------------------
@@ -54,10 +106,9 @@
 	/**
 	 * Number of fields in the result set
 	 *
-	 * @access	public
-	 * @return	integer
+	 * @return	int
 	 */
-	function num_fields()
+	public function num_fields()
 	{
 		return $this->result_id->columnCount();
 	}
@@ -69,15 +120,15 @@
 	 *
 	 * Generates an array of column names
 	 *
-	 * @access	public
-	 * @return	array
+	 * @return	bool
 	 */
-	function list_fields()
+	public function list_fields()
 	{
 		if ($this->db->db_debug)
 		{
 			return $this->db->display_error('db_unsuported_feature');
 		}
+
 		return FALSE;
 	}
 
@@ -88,20 +139,58 @@
 	 *
 	 * Generates an array of objects containing field meta-data
 	 *
-	 * @access	public
 	 * @return	array
 	 */
-	function field_data()
+	public function field_data()
 	{
 		$data = array();
-	
+
 		try
 		{
-			for($i = 0; $i < $this->num_fields(); $i++)
+			if (strpos($this->result_id->queryString, 'PRAGMA') !== FALSE)
 			{
-				$data[] = $this->result_id->getColumnMeta($i);
+				foreach ($this->result_array() as $field)
+				{
+					preg_match('/([a-zA-Z]+)(\(\d+\))?/', $field['type'], $matches);
+
+					$F		= new stdClass();
+					$F->name	= $field['name'];
+					$F->type	= ( ! empty($matches[1])) ? $matches[1] : NULL;
+					$F->default	= NULL;
+					$F->max_length	= ( ! empty($matches[2])) ? preg_replace('/[^\d]/', '', $matches[2]) : NULL;
+					$F->primary_key = (int) $field['pk'];
+					$F->pdo_type	= NULL;
+
+					$data[] = $F;
+				}
 			}
-			
+			else
+			{
+				for($i = 0, $max = $this->num_fields(); $i < $max; $i++)
+				{
+					$field = $this->result_id->getColumnMeta($i);
+
+					$F		= new stdClass();
+					$F->name	= $field['name'];
+					$F->type	= $field['native_type'];
+					$F->default	= NULL;
+					$F->pdo_type	= $field['pdo_type'];
+
+					if ($field['precision'] < 0)
+					{
+						$F->max_length	= NULL;
+						$F->primary_key = 0;
+					}
+					else
+					{
+						$F->max_length	= ($field['len'] > 255) ? 0 : $field['len'];
+						$F->primary_key = (int) ( ! empty($field['flags']) && in_array('primary_key', $field['flags']));
+					}
+
+					$data[] = $F;
+				}
+			}
+
 			return $data;
 		}
 		catch (Exception $e)
@@ -110,6 +199,7 @@
 			{
 				return $this->db->display_error('db_unsuported_feature');
 			}
+
 			return FALSE;
 		}
 	}
@@ -119,9 +209,9 @@
 	/**
 	 * Free the result
 	 *
-	 * @return	null
+	 * @return	void
 	 */
-	function free_result()
+	public function free_result()
 	{
 		if (is_object($this->result_id))
 		{
@@ -132,31 +222,13 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 * Data Seek
-	 *
-	 * Moves the internal pointer to the desired offset.  We call
-	 * this internally before fetching results to make sure the
-	 * result set starts at zero
-	 *
-	 * @access	private
-	 * @return	array
-	 */
-	function _data_seek($n = 0)
-	{
-		return FALSE;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
 	 * Result - associative array
 	 *
 	 * Returns the result set as an array
 	 *
-	 * @access	private
 	 * @return	array
 	 */
-	function _fetch_assoc()
+	protected function _fetch_assoc()
 	{
 		return $this->result_id->fetch(PDO::FETCH_ASSOC);
 	}
@@ -168,16 +240,14 @@
 	 *
 	 * Returns the result set as an object
 	 *
-	 * @access	private
 	 * @return	object
 	 */
-	function _fetch_object()
-	{	
-		return $this->result_id->fetchObject();
+	protected function _fetch_object()
+	{
+		return $this->result_id->fetch(PDO::FETCH_OBJ);
 	}
 
 }
 
-
 /* End of file pdo_result.php */
 /* Location: ./system/database/drivers/pdo/pdo_result.php */
\ No newline at end of file
diff --git a/system/database/drivers/pdo/pdo_utility.php b/system/database/drivers/pdo/pdo_utility.php
index 971ec88..9308421 100644
--- a/system/database/drivers/pdo/pdo_utility.php
+++ b/system/database/drivers/pdo/pdo_utility.php
@@ -1,13 +1,13 @@
-<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
- * 
+ *
  * Licensed under the Open Software License version 3.0
- * 
+ *
  * This source file is subject to the Open Software License (OSL 3.0) that is
  * bundled with this package in the files license.txt / license.rst.  It is
  * also available through the world wide web at this URL:
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * PDO Utility Class
  *
@@ -36,74 +34,15 @@
  */
 class CI_DB_pdo_utility extends CI_DB_utility {
 
-	/**
-	 * List databases
-	 *
-	 * @access	private
-	 * @return	bool
-	 */
-	function _list_databases()
-	{
-		// Not sure if PDO lets you list all databases...
-		if ($this->db->db_debug)
-		{
-			return $this->db->display_error('db_unsuported_feature');
-		}
-		return FALSE;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Optimize table query
-	 *
-	 * Generates a platform-specific query so that a table can be optimized
-	 *
-	 * @access	private
-	 * @param	string	the table name
-	 * @return	object
-	 */
-	function _optimize_table($table)
-	{
-		// Not a supported PDO feature
-		if ($this->db->db_debug)
-		{
-			return $this->db->display_error('db_unsuported_feature');
-		}
-		return FALSE;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Repair table query
-	 *
-	 * Generates a platform-specific query so that a table can be repaired
-	 *
-	 * @access	private
-	 * @param	string	the table name
-	 * @return	object
-	 */
-	function _repair_table($table)
-	{
-		// Not a supported PDO feature
-		if ($this->db->db_debug)
-		{
-			return $this->db->display_error('db_unsuported_feature');
-		}
-		return FALSE;
-	}
-
-	// --------------------------------------------------------------------
+	protected $_list_databases = FALSE;
 
 	/**
 	 * PDO Export
 	 *
-	 * @access	private
 	 * @param	array	Preferences
 	 * @return	mixed
 	 */
-	function _backup($params = array())
+	protected function _backup($params = array())
 	{
 		// Currently unsupported
 		return $this->db->display_error('db_unsuported_feature');
diff --git a/system/database/drivers/postgre/postgre_driver.php b/system/database/drivers/postgre/postgre_driver.php
index 42329bd..ad9ac90 100644
--- a/system/database/drivers/postgre/postgre_driver.php
+++ b/system/database/drivers/postgre/postgre_driver.php
@@ -1,13 +1,13 @@
-<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
- * 
+ *
  * Licensed under the Open Software License version 3.0
- * 
+ *
  * This source file is subject to the Open Software License (OSL 3.0) that is
  * bundled with this package in the files license.txt / license.rst.  It is
  * also available through the world wide web at this URL:
@@ -25,13 +25,11 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * Postgre Database Adapter Class
  *
  * Note: _DB is an extender class that the app controller
- * creates dynamically based on whether the active record
+ * creates dynamically based on whether the query builder
  * class is being used or not.
  *
  * @package		CodeIgniter
@@ -42,47 +40,81 @@
  */
 class CI_DB_postgre_driver extends CI_DB {
 
-	var $dbdriver = 'postgre';
+	public $dbdriver = 'postgre';
 
-	var $_escape_char = '"';
+	protected $_escape_char = '"';
 
 	// clause and character used for LIKE escape sequences
-	var $_like_escape_str = " ESCAPE '%s' ";
-	var $_like_escape_chr = '!';
+	protected $_like_escape_str = " ESCAPE '%s' ";
+	protected $_like_escape_chr = '!';
 
 	/**
 	 * The syntax to count rows is slightly different across different
 	 * database engines, so this string appears in each driver and is
 	 * used for the count_all() and count_all_results() functions.
 	 */
-	var $_count_string = "SELECT COUNT(*) AS ";
-	var $_random_keyword = ' RANDOM()'; // database specific random keyword
+	protected $_count_string = 'SELECT COUNT(*) AS ';
+	protected $_random_keyword = ' RANDOM()'; // database specific random keyword
 
 	/**
-	 * Connection String
+	 * Constructor
 	 *
-	 * @access	private
-	 * @return	string
+	 * Creates a DSN string to be used for db_connect() and db_pconnect()
+	 *
+	 * @return	void
 	 */
-	function _connect_string()
+	public function __construct($params)
 	{
-		$components = array(
-								'hostname'	=> 'host',
-								'port'		=> 'port',
-								'database'	=> 'dbname',
-								'username'	=> 'user',
-								'password'	=> 'password'
-							);
+		parent::__construct($params);
 
-		$connect_string = "";
-		foreach ($components as $key => $val)
+		if ( ! empty($this->dsn))
 		{
-			if (isset($this->$key) && $this->$key != '')
+			return;
+		}
+
+		$this->dsn === '' OR $this->dsn = '';
+
+		if (strpos($this->hostname, '/') !== FALSE)
+		{
+			// If UNIX sockets are used, we shouldn't set a port
+			$this->port = '';
+		}
+
+		$this->hostname === '' OR $this->dsn = 'host='.$this->hostname.' ';
+
+		if ( ! empty($this->port) && ctype_digit($this->port))
+		{
+			$this->dsn .= 'port='.$this->port.' ';
+		}
+
+		if ($this->username !== '')
+		{
+			$this->dsn .= 'user='.$this->username.' ';
+
+			/* An empty password is valid!
+			 *
+			 * $db['password'] = NULL must be done in order to ignore it.
+			 */
+			$this->password === NULL OR $this->dsn .= "password='".$this->password."' ";
+		}
+
+		$this->database === '' OR $this->dsn .= 'dbname='.$this->database.' ';
+
+		/* We don't have these options as elements in our standard configuration
+		 * array, but they might be set by parse_url() if the configuration was
+		 * provided via string. Example:
+		 *
+		 * postgre://username:password@localhost:5432/database?connect_timeout=5&sslmode=1
+		 */
+		foreach (array('connect_timeout', 'options', 'sslmode', 'service') as $key)
+		{
+			if (isset($this->$key) && is_string($this->key) && $this->key !== '')
 			{
-				$connect_string .= " $val=".$this->$key;
+				$this->dsn .= $key."='".$this->key."' ";
 			}
 		}
-		return trim($connect_string);
+
+		$this->dsn = rtrim($this->dsn);
 	}
 
 	// --------------------------------------------------------------------
@@ -90,12 +122,11 @@
 	/**
 	 * Non-persistent database connection
 	 *
-	 * @access	private called by the base class
 	 * @return	resource
 	 */
-	function db_connect()
+	public function db_connect()
 	{
-		return @pg_connect($this->_connect_string());
+		return @pg_connect($this->dsn);
 	}
 
 	// --------------------------------------------------------------------
@@ -103,12 +134,11 @@
 	/**
 	 * Persistent database connection
 	 *
-	 * @access	private called by the base class
 	 * @return	resource
 	 */
-	function db_pconnect()
+	public function db_pconnect()
 	{
-		return @pg_pconnect($this->_connect_string());
+		return @pg_pconnect($this->dsn);
 	}
 
 	// --------------------------------------------------------------------
@@ -119,10 +149,9 @@
 	 * Keep / reestablish the db connection if no queries have been
 	 * sent for a length of time exceeding the server's idle timeout
 	 *
-	 * @access	public
 	 * @return	void
 	 */
-	function reconnect()
+	public function reconnect()
 	{
 		if (pg_ping($this->conn_id) === FALSE)
 		{
@@ -133,44 +162,43 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 * Select the database
-	 *
-	 * @access	private called by the base class
-	 * @return	resource
-	 */
-	function db_select()
-	{
-		// Not needed for Postgre so we'll return TRUE
-		return TRUE;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
 	 * Set client character set
 	 *
-	 * @access	public
 	 * @param	string
-	 * @param	string
-	 * @return	resource
+	 * @return	bool
 	 */
-	function db_set_charset($charset, $collation)
+	protected function _db_set_charset($charset)
 	{
-		// @todo - add support if needed
-		return TRUE;
+		return (pg_set_client_encoding($this->conn_id, $charset) === 0);
 	}
 
 	// --------------------------------------------------------------------
 
 	/**
-	 * Version number query string
+	 * Database version number
 	 *
-	 * @access	public
 	 * @return	string
 	 */
-	function _version()
+	public function version()
 	{
-		return "SELECT version() AS ver";
+		if (isset($this->data_cache['version']))
+		{
+			return $this->data_cache['version'];
+		}
+
+		if (($pg_version = pg_version($this->conn_id)) === FALSE)
+		{
+			return FALSE;
+		}
+
+		/* If PHP was compiled with PostgreSQL lib versions earlier
+		 * than 7.4, pg_version() won't return the server version
+		 * and so we'll have to fall back to running a query in
+		 * order to get it.
+		 */
+		return isset($pg_version['server'])
+			? $this->data_cache['version'] = $pg_version['server']
+			: parent::version();
 	}
 
 	// --------------------------------------------------------------------
@@ -178,49 +206,26 @@
 	/**
 	 * Execute the query
 	 *
-	 * @access	private called by the base class
 	 * @param	string	an SQL query
 	 * @return	resource
 	 */
-	function _execute($sql)
+	protected function _execute($sql)
 	{
-		$sql = $this->_prep_query($sql);
 		return @pg_query($this->conn_id, $sql);
 	}
 
 	// --------------------------------------------------------------------
 
 	/**
-	 * Prep the query
-	 *
-	 * If needed, each database adapter can prep the query string
-	 *
-	 * @access	private called by execute()
-	 * @param	string	an SQL query
-	 * @return	string
-	 */
-	function _prep_query($sql)
-	{
-		return $sql;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
 	 * Begin Transaction
 	 *
-	 * @access	public
+	 * @param	bool
 	 * @return	bool
 	 */
-	function trans_begin($test_mode = FALSE)
+	public function trans_begin($test_mode = FALSE)
 	{
-		if ( ! $this->trans_enabled)
-		{
-			return TRUE;
-		}
-
 		// When transactions are nested we only begin/commit/rollback the outermost ones
-		if ($this->_trans_depth > 0)
+		if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
 		{
 			return TRUE;
 		}
@@ -228,9 +233,9 @@
 		// Reset the transaction failure flag.
 		// If the $test_mode flag is set to TRUE transactions will be rolled back
 		// even if the queries produce a successful result.
-		$this->_trans_failure = ($test_mode === TRUE) ? TRUE : FALSE;
+		$this->_trans_failure = ($test_mode === TRUE);
 
-		return @pg_exec($this->conn_id, "begin");
+		return (bool) @pg_query($this->conn_id, 'BEGIN');
 	}
 
 	// --------------------------------------------------------------------
@@ -238,23 +243,17 @@
 	/**
 	 * Commit Transaction
 	 *
-	 * @access	public
 	 * @return	bool
 	 */
-	function trans_commit()
+	public function trans_commit()
 	{
-		if ( ! $this->trans_enabled)
-		{
-			return TRUE;
-		}
-
 		// When transactions are nested we only begin/commit/rollback the outermost ones
-		if ($this->_trans_depth > 0)
+		if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
 		{
 			return TRUE;
 		}
 
-		return @pg_exec($this->conn_id, "commit");
+		return (bool) @pg_query($this->conn_id, 'COMMIT');
 	}
 
 	// --------------------------------------------------------------------
@@ -262,23 +261,17 @@
 	/**
 	 * Rollback Transaction
 	 *
-	 * @access	public
 	 * @return	bool
 	 */
-	function trans_rollback()
+	public function trans_rollback()
 	{
-		if ( ! $this->trans_enabled)
-		{
-			return TRUE;
-		}
-
 		// When transactions are nested we only begin/commit/rollback the outermost ones
-		if ($this->_trans_depth > 0)
+		if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
 		{
 			return TRUE;
 		}
 
-		return @pg_exec($this->conn_id, "rollback");
+		return (bool) @pg_query($this->conn_id, 'ROLLBACK');
 	}
 
 	// --------------------------------------------------------------------
@@ -286,12 +279,11 @@
 	/**
 	 * Escape String
 	 *
-	 * @access	public
 	 * @param	string
 	 * @param	bool	whether or not the string will be used in a LIKE condition
 	 * @return	string
 	 */
-	function escape_str($str, $like = FALSE)
+	public function escape_str($str, $like = FALSE)
 	{
 		if (is_array($str))
 		{
@@ -308,9 +300,9 @@
 		// escape LIKE condition wildcards
 		if ($like === TRUE)
 		{
-			$str = str_replace(	array('%', '_', $this->_like_escape_chr),
-								array($this->_like_escape_chr.'%', $this->_like_escape_chr.'_', $this->_like_escape_chr.$this->_like_escape_chr),
-								$str);
+			return str_replace(array($this->_like_escape_chr, '%', '_'),
+						array($this->_like_escape_chr.$this->_like_escape_chr, $this->_like_escape_chr.'%', $this->_like_escape_chr.'_'),
+						$str);
 		}
 
 		return $str;
@@ -319,12 +311,32 @@
 	// --------------------------------------------------------------------
 
 	/**
+	 * "Smart" Escape String
+	 *
+	 * Escapes data based on type
+	 * Sets boolean and null types
+	 *
+	 * @param	string
+	 * @return	mixed
+	 */
+	public function escape($str)
+	{
+		if (is_bool($str))
+		{
+			return ($str) ? 'TRUE' : 'FALSE';
+		}
+
+		return parent::escape($str);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
 	 * Affected Rows
 	 *
-	 * @access	public
-	 * @return	integer
+	 * @return	int
 	 */
-	function affected_rows()
+	public function affected_rows()
 	{
 		return @pg_affected_rows($this->result_id);
 	}
@@ -334,71 +346,45 @@
 	/**
 	 * Insert ID
 	 *
-	 * @access	public
-	 * @return	integer
+	 * @return	string
 	 */
-	function insert_id()
+	public function insert_id()
 	{
-		$v = $this->_version();
-		$v = $v['server'];
+		$v = pg_version($this->conn_id);
+		$v = isset($v['server']) ? $v['server'] : 0; // 'server' key is only available since PosgreSQL 7.4
 
-		$table	= func_num_args() > 0 ? func_get_arg(0) : NULL;
-		$column	= func_num_args() > 1 ? func_get_arg(1) : NULL;
+		$table	= (func_num_args() > 0) ? func_get_arg(0) : NULL;
+		$column	= (func_num_args() > 1) ? func_get_arg(1) : NULL;
 
-		if ($table == NULL && $v >= '8.1')
+		if ($table === NULL && $v >= '8.1')
 		{
-			$sql='SELECT LASTVAL() as ins_id';
+			$sql = 'SELECT LASTVAL() AS ins_id';
 		}
-		elseif ($table != NULL && $column != NULL && $v >= '8.0')
+		elseif ($table !== NULL)
 		{
-			$sql = sprintf("SELECT pg_get_serial_sequence('%s','%s') as seq", $table, $column);
-			$query = $this->query($sql);
-			$row = $query->row();
-			$sql = sprintf("SELECT CURRVAL('%s') as ins_id", $row->seq);
-		}
-		elseif ($table != NULL)
-		{
-			// seq_name passed in table parameter
-			$sql = sprintf("SELECT CURRVAL('%s') as ins_id", $table);
+			if ($column !== NULL && $v >= '8.0')
+			{
+				$sql = 'SELECT pg_get_serial_sequence(\''.$table."', '".$column."') AS seq";
+				$query = $this->query($sql);
+				$query = $query->row();
+				$seq = $query->seq;
+			}
+			else
+			{
+				// seq_name passed in table parameter
+				$seq = $table;
+			}
+
+			$sql = 'SELECT CURRVAL(\''.$seq."') AS ins_id";
 		}
 		else
 		{
 			return pg_last_oid($this->result_id);
 		}
+
 		$query = $this->query($sql);
-		$row = $query->row();
-		return $row->ins_id;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * "Count All" query
-	 *
-	 * Generates a platform-specific query string that counts all records in
-	 * the specified database
-	 *
-	 * @access	public
-	 * @param	string
-	 * @return	string
-	 */
-	function count_all($table = '')
-	{
-		if ($table == '')
-		{
-			return 0;
-		}
-
-		$query = $this->query($this->_count_string . $this->_protect_identifiers('numrows') . " FROM " . $this->_protect_identifiers($table, TRUE, NULL, FALSE));
-
-		if ($query->num_rows() == 0)
-		{
-			return 0;
-		}
-
-		$row = $query->row();
-		$this->_reset_select();
-		return (int) $row->numrows;
+		$query = $query->row();
+		return (int) $query->ins_id;
 	}
 
 	// --------------------------------------------------------------------
@@ -408,17 +394,16 @@
 	 *
 	 * Generates a platform-specific query string so that the table names can be fetched
 	 *
-	 * @access	private
-	 * @param	boolean
+	 * @param	bool
 	 * @return	string
 	 */
-	function _list_tables($prefix_limit = FALSE)
+	protected function _list_tables($prefix_limit = FALSE)
 	{
 		$sql = "SELECT table_name FROM information_schema.tables WHERE table_schema = 'public'";
 
-		if ($prefix_limit !== FALSE AND $this->dbprefix != '')
+		if ($prefix_limit !== FALSE && $this->dbprefix !== '')
 		{
-			$sql .= " AND table_name LIKE '".$this->escape_like_str($this->dbprefix)."%' ".sprintf($this->_like_escape_str, $this->_like_escape_chr);
+			return $sql." AND table_name LIKE '".$this->escape_like_str($this->dbprefix)."%' ".sprintf($this->_like_escape_str, $this->_like_escape_chr);
 		}
 
 		return $sql;
@@ -431,13 +416,12 @@
 	 *
 	 * Generates a platform-specific query string so that the column names can be fetched
 	 *
-	 * @access	public
 	 * @param	string	the table name
 	 * @return	string
 	 */
-	function _list_columns($table = '')
+	protected function _list_columns($table = '')
 	{
-		return "SELECT column_name FROM information_schema.columns WHERE table_name ='".$table."'";
+		return "SELECT column_name FROM information_schema.columns WHERE table_name = '".$table."'";
 	}
 
 	// --------------------------------------------------------------------
@@ -447,81 +431,27 @@
 	 *
 	 * Generates a platform-specific query so that the column data can be retrieved
 	 *
-	 * @access	public
 	 * @param	string	the table name
-	 * @return	object
-	 */
-	function _field_data($table)
-	{
-		return "SELECT * FROM ".$table." LIMIT 1";
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * The error message string
-	 *
-	 * @access	private
 	 * @return	string
 	 */
-	function _error_message()
+	protected function _field_data($table)
 	{
-		return pg_last_error($this->conn_id);
+		return 'SELECT * FROM '.$table.' LIMIT 1';
 	}
 
 	// --------------------------------------------------------------------
 
 	/**
-	 * The error message number
+	 * Error
 	 *
-	 * @access	private
-	 * @return	integer
+	 * Returns an array containing code and message of the last
+	 * database error that has occured.
+	 *
+	 * @return	array
 	 */
-	function _error_number()
+	public function error()
 	{
-		return '';
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Escape the SQL Identifiers
-	 *
-	 * This function escapes column and table names
-	 *
-	 * @access	private
-	 * @param	string
-	 * @return	string
-	 */
-	function _escape_identifiers($item)
-	{
-		if ($this->_escape_char == '')
-		{
-			return $item;
-		}
-
-		foreach ($this->_reserved_identifiers as $id)
-		{
-			if (strpos($item, '.'.$id) !== FALSE)
-			{
-				$str = $this->_escape_char. str_replace('.', $this->_escape_char.'.', $item);
-
-				// remove duplicates if the user already included the escape
-				return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str);
-			}
-		}
-
-		if (strpos($item, '.') !== FALSE)
-		{
-			$str = $this->_escape_char.str_replace('.', $this->_escape_char.'.'.$this->_escape_char, $item).$this->_escape_char;
-		}
-		else
-		{
-			$str = $this->_escape_char.$item.$this->_escape_char;
-		}
-
-		// remove duplicates if the user already included the escape
-		return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str);
+		return array('code' => '', 'message' => pg_last_error($this->conn_id));
 	}
 
 	// --------------------------------------------------------------------
@@ -532,54 +462,12 @@
 	 * This function implicitly groups FROM tables so there is no confusion
 	 * about operator precedence in harmony with SQL standards
 	 *
-	 * @access	public
-	 * @param	type
-	 * @return	type
-	 */
-	function _from_tables($tables)
-	{
-		if ( ! is_array($tables))
-		{
-			$tables = array($tables);
-		}
-
-		return implode(', ', $tables);
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Insert statement
-	 *
-	 * Generates a platform-specific insert string from the supplied data
-	 *
-	 * @access	public
-	 * @param	string	the table name
-	 * @param	array	the insert keys
-	 * @param	array	the insert values
+	 * @param	array
 	 * @return	string
 	 */
-	function _insert($table, $keys, $values)
+	protected function _from_tables($tables)
 	{
-		return "INSERT INTO ".$table." (".implode(', ', $keys).") VALUES (".implode(', ', $values).")";
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Insert_batch statement
-	 *
-	 * Generates a platform-specific insert string from the supplied data
-	 *
-	 * @access  public
-	 * @param   string  the table name
-	 * @param   array   the insert keys
-	 * @param   array   the insert values
-	 * @return  string
-	 */
-	function _insert_batch($table, $keys, $values)
-	{
-		return "INSERT INTO ".$table." (".implode(', ', $keys).") VALUES ".implode(', ', $values);
+		return is_array($tables) ? implode(', ', $tables) : $tables;
 	}
 
 	// --------------------------------------------------------------------
@@ -589,50 +477,70 @@
 	 *
 	 * Generates a platform-specific update string from the supplied data
 	 *
-	 * @access	public
 	 * @param	string	the table name
 	 * @param	array	the update data
 	 * @param	array	the where clause
-	 * @param	array	the orderby clause
-	 * @param	array	the limit clause
+	 * @param	array	the orderby clause (ignored)
+	 * @param	array	the limit clause (ignored)
+	 * @param	array	the like clause
 	 * @return	string
 	 */
-	function _update($table, $values, $where, $orderby = array(), $limit = FALSE)
+	protected function _update($table, $values, $where, $orderby = array(), $limit = FALSE, $like = array())
 	{
 		foreach ($values as $key => $val)
 		{
-			$valstr[] = $key." = ".$val;
+			$valstr[] = $key.' = '.$val;
 		}
 
-		$limit = ( ! $limit) ? '' : ' LIMIT '.$limit;
+		$where = empty($where) ? '' : ' WHERE '.implode(' ', $where);
 
-		$orderby = (count($orderby) >= 1)?' ORDER BY '.implode(", ", $orderby):'';
+		if ( ! empty($like))
+		{
+			$where .= ($where === '' ? ' WHERE ' : ' AND ').implode(' ', $like);
+		}
 
-		$sql = "UPDATE ".$table." SET ".implode(', ', $valstr);
-
-		$sql .= ($where != '' AND count($where) >=1) ? " WHERE ".implode(" ", $where) : '';
-
-		$sql .= $orderby.$limit;
-
-		return $sql;
+		return 'UPDATE '.$table.' SET '.implode(', ', $valstr).$where;
 	}
 
 	// --------------------------------------------------------------------
 
 	/**
-	 * Truncate statement
+	 * Update_Batch statement
 	 *
-	 * Generates a platform-specific truncate string from the supplied data
-	 * If the database does not support the truncate() command
-	 * This function maps to "DELETE FROM table"
+	 * Generates a platform-specific batch update string from the supplied data
 	 *
-	 * @access	public
 	 * @param	string	the table name
+	 * @param	array	the update data
+	 * @param	array	the where clause
 	 * @return	string
 	 */
-	function _truncate($table)
+	protected function _update_batch($table, $values, $index, $where = NULL)
 	{
-		return "TRUNCATE ".$table;
+		$ids = array();
+		foreach ($values as $key => $val)
+		{
+			$ids[] = $val[$index];
+
+			foreach (array_keys($val) as $field)
+			{
+				if ($field !== $index)
+				{
+					$final[$field][] =  'WHEN '.$val[$index].' THEN '.$val[$field];
+				}
+			}
+		}
+
+		$cases = '';
+		foreach ($final as $k => $v)
+		{
+			$cases .= $k.' = (CASE '.$k."\n"
+				.implode("\n", $v)."\n"
+				.'ELSE '.$k.' END), ';
+		}
+
+		return 'UPDATE '.$table.' SET '.substr($cases, 0, -2)
+			.' WHERE '.(($where !== '' && count($where) > 0) ? implode(' ', $where).' AND ' : '')
+			.$index.' IN('.implode(',', $ids).')';
 	}
 
 	// --------------------------------------------------------------------
@@ -642,55 +550,108 @@
 	 *
 	 * Generates a platform-specific delete string from the supplied data
 	 *
-	 * @access	public
 	 * @param	string	the table name
 	 * @param	array	the where clause
-	 * @param	string	the limit clause
+	 * @param	array	the like clause
+	 * @param	string	the limit clause (ignored)
 	 * @return	string
 	 */
-	function _delete($table, $where = array(), $like = array(), $limit = FALSE)
+	protected function _delete($table, $where = array(), $like = array(), $limit = FALSE)
 	{
-		$conditions = '';
+		$conditions = array();
 
-		if (count($where) > 0 OR count($like) > 0)
-		{
-			$conditions = "\nWHERE ";
-			$conditions .= implode("\n", $this->ar_where);
+		empty($where) OR $conditions[] = implode(' ', $where);
+		empty($like) OR $conditions[] = implode(' ', $like);
 
-			if (count($where) > 0 && count($like) > 0)
-			{
-				$conditions .= " AND ";
-			}
-			$conditions .= implode("\n", $like);
-		}
-
-		$limit = ( ! $limit) ? '' : ' LIMIT '.$limit;
-
-		return "DELETE FROM ".$table.$conditions.$limit;
+		return 'DELETE FROM '.$table.(count($conditions) > 0 ? ' WHERE '.implode(' AND ', $conditions) : '');
 	}
 
 	// --------------------------------------------------------------------
+
 	/**
 	 * Limit string
 	 *
 	 * Generates a platform-specific LIMIT clause
 	 *
-	 * @access	public
 	 * @param	string	the sql query string
-	 * @param	integer	the number of rows to limit the query to
-	 * @param	integer	the offset value
+	 * @param	int	the number of rows to limit the query to
+	 * @param	int	the offset value
 	 * @return	string
 	 */
-	function _limit($sql, $limit, $offset)
+	protected function _limit($sql, $limit, $offset)
 	{
-		$sql .= "LIMIT ".$limit;
+		return $sql.' LIMIT '.$limit.($offset == 0 ? '' : ' OFFSET '.$offset);
+	}
 
-		if ($offset > 0)
+	// --------------------------------------------------------------------
+
+	/**
+	 * Where
+	 *
+	 * Called by where() or or_where()
+	 *
+	 * @param	mixed
+	 * @param	mixed
+	 * @param	string
+	 * @return	object
+	 *
+	 */
+	protected function _where($key, $value = NULL, $type = 'AND ', $escape = NULL)
+	{
+		$type = $this->_group_get_type($type);
+
+		if ( ! is_array($key))
 		{
-			$sql .= " OFFSET ".$offset;
+			$key = array($key => $value);
 		}
 
-		return $sql;
+		// If the escape value was not set will will base it on the global setting
+		if ( ! is_bool($escape))
+		{
+			$escape = $this->_protect_identifiers;
+		}
+
+		foreach ($key as $k => $v)
+		{
+			$prefix = (count($this->qb_where) === 0 && count($this->qb_cache_where) === 0) ? '' : $type;
+
+			$k = $this->_has_operator($k)
+				? $this->protect_identifiers(substr($k, 0, strpos(rtrim($k), ' ')), FALSE, $escape).strchr(rtrim($k), ' ')
+				: $this->protect_identifiers($k, FALSE, $escape);
+
+			if (is_null($v) && ! $this->_has_operator($k))
+			{
+				// value appears not to have been set, assign the test to IS NULL
+				$k .= ' IS NULL';
+			}
+
+			if ( ! is_null($v))
+			{
+				if ($escape === TRUE)
+				{
+					$v = ' '.$this->escape($v);
+				}
+				elseif (is_bool($v))
+				{
+					$v = ($v ? ' TRUE' : ' FALSE');
+				}
+
+				if ( ! $this->_has_operator($k))
+				{
+					$k .= ' = ';
+				}
+			}
+
+			$this->qb_where[] = $prefix.$k.$v;
+			if ($this->qb_caching === TRUE)
+			{
+				$this->qb_cache_where[] = $prefix.$k.$v;
+				$this->qb_cache_exists[] = 'where';
+			}
+
+		}
+
+		return $this;
 	}
 
 	// --------------------------------------------------------------------
@@ -698,18 +659,14 @@
 	/**
 	 * Close DB Connection
 	 *
-	 * @access	public
-	 * @param	resource
 	 * @return	void
 	 */
-	function _close($conn_id)
+	protected function _close()
 	{
-		@pg_close($conn_id);
+		@pg_close($this->conn_id);
 	}
 
-
 }
 
-
 /* End of file postgre_driver.php */
 /* Location: ./system/database/drivers/postgre/postgre_driver.php */
\ No newline at end of file
diff --git a/system/database/drivers/postgre/postgre_forge.php b/system/database/drivers/postgre/postgre_forge.php
index 756fd34..c434e95 100644
--- a/system/database/drivers/postgre/postgre_forge.php
+++ b/system/database/drivers/postgre/postgre_forge.php
@@ -1,13 +1,13 @@
-<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
- * 
+ *
  * Licensed under the Open Software License version 3.0
- * 
+ *
  * This source file is subject to the Open Software License (OSL 3.0) that is
  * bundled with this package in the files license.txt / license.rst.  It is
  * also available through the world wide web at this URL:
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * Postgre Forge Class
  *
@@ -36,61 +34,34 @@
  */
 class CI_DB_postgre_forge extends CI_DB_forge {
 
-	/**
-	 * Create database
-	 *
-	 * @access	private
-	 * @param	string	the database name
-	 * @return	bool
-	 */
-	function _create_database($name)
-	{
-		return "CREATE DATABASE ".$name;
-	}
+	protected $_drop_table	= 'DROP TABLE IF EXISTS %s CASCADE';
 
-	// --------------------------------------------------------------------
-
-	/**
-	 * Drop database
-	 *
-	 * @access	private
-	 * @param	string	the database name
-	 * @return	bool
-	 */
-	function _drop_database($name)
-	{
-		return "DROP DATABASE ".$name;
-	}
-
-	// --------------------------------------------------------------------
-	
 	/**
 	 * Process Fields
 	 *
 	 * @param	mixed	the fields
 	 * @return	string
 	 */
-	function _process_fields($fields, $primary_keys=array())
+	protected function _process_fields($fields, $primary_keys = array())
 	{
 		$sql = '';
 		$current_field_count = 0;
 
-		foreach ($fields as $field=>$attributes)
+		foreach ($fields as $field => $attributes)
 		{
 			// Numeric field names aren't allowed in databases, so if the key is
 			// numeric, we know it was assigned by PHP and the developer manually
 			// entered the field information, so we'll simply add it to the list
 			if (is_numeric($field))
 			{
-				$sql .= "\n\t$attributes";
+				$sql .= "\n\t".$attributes;
 			}
 			else
 			{
+				$sql .= "\n\t".$this->db->escape_identifiers($field);
+
 				$attributes = array_change_key_case($attributes, CASE_UPPER);
-
-				$sql .= "\n\t".$this->db->_protect_identifiers($field);
-
-				$is_unsigned = (array_key_exists('UNSIGNED', $attributes) && $attributes['UNSIGNED'] === TRUE);
+				$is_unsigned = ( ! empty($attributes['UNSIGNED']) && $attributes['UNSIGNED'] === TRUE);
 
 				// Convert datatypes to be PostgreSQL-compatible
 				switch (strtoupper($attributes['TYPE']))
@@ -122,41 +93,30 @@
 					case 'BLOB':
 						$attributes['TYPE'] = 'BYTEA';
 						break;
+					default:
+						break;
 				}
 
 				// If this is an auto-incrementing primary key, use the serial data type instead
-				if (in_array($field, $primary_keys) && array_key_exists('AUTO_INCREMENT', $attributes) 
-					&& $attributes['AUTO_INCREMENT'] === TRUE)
-				{
-					$sql .= ' SERIAL';
-				}
-				else
-				{
-					$sql .=  ' '.$attributes['TYPE'];
-				}
+				$sql .= (in_array($field, $primary_keys) && ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE)
+					? ' SERIAL' : ' '.$attributes['TYPE'];
 
 				// Modified to prevent constraints with integer data types
-				if (array_key_exists('CONSTRAINT', $attributes) && strpos($attributes['TYPE'], 'INT') === false)
+				if ( ! empty($attributes['CONSTRAINT']) && strpos($attributes['TYPE'], 'INT') === FALSE)
 				{
 					$sql .= '('.$attributes['CONSTRAINT'].')';
 				}
 
-				if (array_key_exists('DEFAULT', $attributes))
+				if (isset($attributes['DEFAULT']))
 				{
-					$sql .= ' DEFAULT \''.$attributes['DEFAULT'].'\'';
+					$sql .= " DEFAULT '".$attributes['DEFAULT']."'";
 				}
 
-				if (array_key_exists('NULL', $attributes) && $attributes['NULL'] === TRUE)
-				{
-					$sql .= ' NULL';
-				}
-				else
-				{
-					$sql .= ' NOT NULL';
-				}
+				$sql .= ( ! empty($attributes['NULL']) && $attributes['NULL'] === TRUE)
+					? ' NULL' : ' NOT NULL';
 
-				// Added new attribute to create unqite fields. Also works with MySQL
-				if (array_key_exists('UNIQUE', $attributes) && $attributes['UNIQUE'] === TRUE)
+				// Added new attribute to create unique fields. Also works with MySQL
+				if ( ! empty($attributes['UNIQUE']) && $attributes['UNIQUE'] === TRUE)
 				{
 					$sql .= ' UNIQUE';
 				}
@@ -168,7 +128,7 @@
 				$sql .= ',';
 			}
 		}
-		
+
 		return $sql;
 	}
 
@@ -177,39 +137,28 @@
 	/**
 	 * Create Table
 	 *
-	 * @access	private
 	 * @param	string	the table name
 	 * @param	array	the fields
 	 * @param	mixed	primary key(s)
 	 * @param	mixed	key(s)
-	 * @param	boolean	should 'IF NOT EXISTS' be added to the SQL
+	 * @param	bool	should 'IF NOT EXISTS' be added to the SQL
 	 * @return	bool
 	 */
-	function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists)
+	protected function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists)
 	{
 		$sql = 'CREATE TABLE ';
 
-		if ($if_not_exists === TRUE)
+		// PostgreSQL doesn't support IF NOT EXISTS syntax so we check if table exists manually
+		if ($if_not_exists === TRUE && $this->db->table_exists($table))
 		{
-			// PostgreSQL doesn't support IF NOT EXISTS syntax so we check if table exists manually
-			if ($this->db->table_exists($table))
-			{
-				return TRUE;
-			}
+			return TRUE;
 		}
 
-		$sql .= $this->db->_escape_identifiers($table)." (";
-		$sql .= $this->_process_fields($fields, $primary_keys);
+		$sql .= $this->db->escape_identifiers($table).' ('.$this->_process_fields($fields, $primary_keys);
 
 		if (count($primary_keys) > 0)
 		{
-			// Something seems to break when passing an array to _protect_identifiers()
-			foreach ($primary_keys as $index => $key)
-			{
-				$primary_keys[$index] = $this->db->_protect_identifiers($key);
-			}
-
-			$sql .= ",\n\tPRIMARY KEY (" . implode(', ', $primary_keys) . ")";
+			$sql .= ",\n\tPRIMARY KEY (".implode(', ', $this->db->escape_identifiers($primary_keys)).')';
 		}
 
 		$sql .= "\n);";
@@ -218,18 +167,14 @@
 		{
 			foreach ($keys as $key)
 			{
-				if (is_array($key))
-				{
-					$key = $this->db->_protect_identifiers($key);
-				}
-				else
-				{
-					$key = array($this->db->_protect_identifiers($key));
-				}
+				$key = is_array($key)
+					? $this->db->escape_identifiers($key)
+					: array($this->db->escape_identifiers($key));
 
 				foreach ($key as $field)
 				{
-					$sql .= "CREATE INDEX " . $table . "_" . str_replace(array('"', "'"), '', $field) . "_index ON $table ($field); ";
+					$sql .= "\nCREATE INDEX ".$this->db->escape_identifiers($table.'_'.str_replace(array('"', "'"), '', $field).'_index')
+						.' ON '.$this->db->escape_identifiers($table).' ('.$this->db->escape_identifiers($field).');';
 				}
 			}
 		}
@@ -240,68 +185,34 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 * Drop Table
-	 */
-	function _drop_table($table)
-	{
-		return "DROP TABLE IF EXISTS ".$this->db->_escape_identifiers($table)." CASCADE";
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
 	 * Alter table query
 	 *
 	 * Generates a platform-specific query so that a table can be altered
 	 * Called by add_column(), drop_column(), and column_alter(),
 	 *
-	 * @access	private
 	 * @param	string	the ALTER type (ADD, DROP, CHANGE)
 	 * @param	string	the column name
 	 * @param	string	the table name
 	 * @param	string	the column definition
 	 * @param	string	the default value
-	 * @param	boolean	should 'NOT NULL' be added
+	 * @param	bool	should 'NOT NULL' be added
 	 * @param	string	the field after which we should add the new field
-	 * @return	object
-	 */
- 	function _alter_table($alter_type, $table, $fields, $after_field = '')
- 	{
- 		$sql = 'ALTER TABLE '.$this->db->_protect_identifiers($table)." $alter_type ";
-
- 		// DROP has everything it needs now.
- 		if ($alter_type == 'DROP')
- 		{
- 			return $sql.$this->db->_protect_identifiers($fields);
- 		}
-
- 		$sql .= $this->_process_fields($fields);
-
- 		if ($after_field != '')
- 		{
- 			$sql .= ' AFTER ' . $this->db->_protect_identifiers($after_field);
- 		}
-
- 		return $sql;
- 	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Rename a table
-	 *
-	 * Generates a platform-specific query so that a table can be renamed
-	 *
-	 * @access	private
-	 * @param	string	the old table name
-	 * @param	string	the new table name
 	 * @return	string
 	 */
-	function _rename_table($table_name, $new_table_name)
-	{
-		$sql = 'ALTER TABLE '.$this->db->_protect_identifiers($table_name)." RENAME TO ".$this->db->_protect_identifiers($new_table_name);
-		return $sql;
-	}
+	protected function _alter_table($alter_type, $table, $fields, $after_field = '')
+ 	{
+ 		$sql = 'ALTER TABLE '.$this->db->escape_identifiers($table).' '.$alter_type.' ';
+
+ 		// DROP has everything it needs now.
+ 		if ($alter_type === 'DROP')
+ 		{
+ 			return $sql.$this->db->escape_identifiers($fields);
+ 		}
+
+ 		return $sql.$this->_process_fields($fields)
+			.($after_field !== '' ? ' AFTER '.$this->db->escape_identifiers($after_field) : '');
+ 	}
+
 }
 
 /* End of file postgre_forge.php */
diff --git a/system/database/drivers/postgre/postgre_result.php b/system/database/drivers/postgre/postgre_result.php
index 9161bf9..f913bc9 100644
--- a/system/database/drivers/postgre/postgre_result.php
+++ b/system/database/drivers/postgre/postgre_result.php
@@ -1,13 +1,13 @@
-<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
- * 
+ *
  * Licensed under the Open Software License version 3.0
- * 
+ *
  * This source file is subject to the Open Software License (OSL 3.0) that is
  * bundled with this package in the files license.txt / license.rst.  It is
  * also available through the world wide web at this URL:
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * Postgres Result Class
  *
@@ -41,10 +39,9 @@
 	/**
 	 * Number of rows in the result set
 	 *
-	 * @access	public
-	 * @return	integer
+	 * @return	int
 	 */
-	function num_rows()
+	public function num_rows()
 	{
 		return @pg_num_rows($this->result_id);
 	}
@@ -54,10 +51,9 @@
 	/**
 	 * Number of fields in the result set
 	 *
-	 * @access	public
-	 * @return	integer
+	 * @return	int
 	 */
-	function num_fields()
+	public function num_fields()
 	{
 		return @pg_num_fields($this->result_id);
 	}
@@ -69,13 +65,12 @@
 	 *
 	 * Generates an array of column names
 	 *
-	 * @access	public
 	 * @return	array
 	 */
-	function list_fields()
+	public function list_fields()
 	{
 		$field_names = array();
-		for ($i = 0; $i < $this->num_fields(); $i++)
+		for ($i = 0, $c = $this->num_fields(); $i < $c; $i++)
 		{
 			$field_names[] = pg_field_name($this->result_id, $i);
 		}
@@ -90,22 +85,19 @@
 	 *
 	 * Generates an array of objects containing field meta-data
 	 *
-	 * @access	public
 	 * @return	array
 	 */
-	function field_data()
+	public function field_data()
 	{
 		$retval = array();
-		for ($i = 0; $i < $this->num_fields(); $i++)
+		for ($i = 0, $c = $this->num_fields(); $i < $c; $i++)
 		{
-			$F				= new stdClass();
-			$F->name		= pg_field_name($this->result_id, $i);
-			$F->type		= pg_field_type($this->result_id, $i);
-			$F->max_length	= pg_field_size($this->result_id, $i);
-			$F->primary_key = 0;
-			$F->default		= '';
-
-			$retval[] = $F;
+			$retval[$i]			= new stdClass();
+			$retval[$i]->name		= pg_field_name($this->result_id, $i);
+			$retval[$i]->type		= pg_field_type($this->result_id, $i);
+			$retval[$i]->max_length		= pg_field_size($this->result_id, $i);
+			$retval[$i]->primary_key	= 0;
+			$retval[$i]->default		= '';
 		}
 
 		return $retval;
@@ -116,9 +108,9 @@
 	/**
 	 * Free the result
 	 *
-	 * @return	null
+	 * @return	void
 	 */
-	function free_result()
+	public function free_result()
 	{
 		if (is_resource($this->result_id))
 		{
@@ -132,14 +124,13 @@
 	/**
 	 * Data Seek
 	 *
-	 * Moves the internal pointer to the desired offset.  We call
+	 * Moves the internal pointer to the desired offset. We call
 	 * this internally before fetching results to make sure the
 	 * result set starts at zero
 	 *
-	 * @access	private
-	 * @return	array
+	 * @return	bool
 	 */
-	function _data_seek($n = 0)
+	protected function _data_seek($n = 0)
 	{
 		return pg_result_seek($this->result_id, $n);
 	}
@@ -151,10 +142,9 @@
 	 *
 	 * Returns the result set as an array
 	 *
-	 * @access	private
 	 * @return	array
 	 */
-	function _fetch_assoc()
+	protected function _fetch_assoc()
 	{
 		return pg_fetch_assoc($this->result_id);
 	}
@@ -166,16 +156,14 @@
 	 *
 	 * Returns the result set as an object
 	 *
-	 * @access	private
 	 * @return	object
 	 */
-	function _fetch_object()
+	protected function _fetch_object()
 	{
 		return pg_fetch_object($this->result_id);
 	}
 
 }
 
-
 /* End of file postgre_result.php */
 /* Location: ./system/database/drivers/postgre/postgre_result.php */
\ No newline at end of file
diff --git a/system/database/drivers/postgre/postgre_utility.php b/system/database/drivers/postgre/postgre_utility.php
index dffd8c5..c95e6df 100644
--- a/system/database/drivers/postgre/postgre_utility.php
+++ b/system/database/drivers/postgre/postgre_utility.php
@@ -1,13 +1,13 @@
-<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
- * 
+ *
  * Licensed under the Open Software License version 3.0
- * 
+ *
  * This source file is subject to the Open Software License (OSL 3.0) that is
  * bundled with this package in the files license.txt / license.rst.  It is
  * also available through the world wide web at this URL:
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * Postgre Utility Class
  *
@@ -36,65 +34,21 @@
  */
 class CI_DB_postgre_utility extends CI_DB_utility {
 
-	/**
-	 * List databases
-	 *
-	 * @access	private
-	 * @return	bool
-	 */
-	function _list_databases()
-	{
-		return "SELECT datname FROM pg_database";
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Optimize table query
-	 *
-	 * Is table optimization supported in Postgre?
-	 *
-	 * @access	private
-	 * @param	string	the table name
-	 * @return	object
-	 */
-	function _optimize_table($table)
-	{
-		return FALSE;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Repair table query
-	 *
-	 * Are table repairs supported in Postgre?
-	 *
-	 * @access	private
-	 * @param	string	the table name
-	 * @return	object
-	 */
-	function _repair_table($table)
-	{
-		return FALSE;
-	}
-
-	// --------------------------------------------------------------------
+	protected $_list_databases	= 'SELECT datname FROM pg_database';
+	protected $_optimize_table	= 'REINDEX TABLE %s';
 
 	/**
 	 * Postgre Export
 	 *
-	 * @access	private
 	 * @param	array	Preferences
 	 * @return	mixed
 	 */
-	function _backup($params = array())
+	protected function _backup($params = array())
 	{
 		// Currently unsupported
 		return $this->db->display_error('db_unsuported_feature');
 	}
 }
 
-
 /* End of file postgre_utility.php */
 /* Location: ./system/database/drivers/postgre/postgre_utility.php */
\ No newline at end of file
diff --git a/system/database/drivers/sqlite/sqlite_driver.php b/system/database/drivers/sqlite/sqlite_driver.php
index 28c3cae..3305f60 100644
--- a/system/database/drivers/sqlite/sqlite_driver.php
+++ b/system/database/drivers/sqlite/sqlite_driver.php
@@ -1,13 +1,13 @@
-<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
- * 
+ *
  * Licensed under the Open Software License version 3.0
- * 
+ *
  * This source file is subject to the Open Software License (OSL 3.0) that is
  * bundled with this package in the files license.txt / license.rst.  It is
  * also available through the world wide web at this URL:
@@ -25,15 +25,11 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
-
-
 /**
  * SQLite Database Adapter Class
  *
  * Note: _DB is an extender class that the app controller
- * creates dynamically based on whether the active record
+ * creates dynamically based on whether the query builder
  * class is being used or not.
  *
  * @package		CodeIgniter
@@ -44,30 +40,29 @@
  */
 class CI_DB_sqlite_driver extends CI_DB {
 
-	var $dbdriver = 'sqlite';
+	public $dbdriver = 'sqlite';
 
 	// The character used to escape with - not needed for SQLite
-	var $_escape_char = '';
+	protected $_escape_char = '"';
 
 	// clause and character used for LIKE escape sequences
-	var $_like_escape_str = " ESCAPE '%s' ";
-	var $_like_escape_chr = '!';
+	protected $_like_escape_str = " ESCAPE '%s' ";
+	protected $_like_escape_chr = '!';
 
 	/**
 	 * The syntax to count rows is slightly different across different
 	 * database engines, so this string appears in each driver and is
 	 * used for the count_all() and count_all_results() functions.
 	 */
-	var $_count_string = "SELECT COUNT(*) AS ";
-	var $_random_keyword = ' Random()'; // database specific random keyword
+	protected $_count_string = 'SELECT COUNT(*) AS ';
+	protected $_random_keyword = ' Random()'; // database specific random keyword
 
 	/**
 	 * Non-persistent database connection
 	 *
-	 * @access	private called by the base class
 	 * @return	resource
 	 */
-	function db_connect()
+	public function db_connect()
 	{
 		if ( ! $conn_id = @sqlite_open($this->database, FILE_WRITE_MODE, $error))
 		{
@@ -89,10 +84,9 @@
 	/**
 	 * Persistent database connection
 	 *
-	 * @access	private called by the base class
 	 * @return	resource
 	 */
-	function db_pconnect()
+	public function db_pconnect()
 	{
 		if ( ! $conn_id = @sqlite_popen($this->database, FILE_WRITE_MODE, $error))
 		{
@@ -112,59 +106,15 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 * Reconnect
+	 * Database version number
 	 *
-	 * Keep / reestablish the db connection if no queries have been
-	 * sent for a length of time exceeding the server's idle timeout
-	 *
-	 * @access	public
-	 * @return	void
-	 */
-	function reconnect()
-	{
-		// not implemented in SQLite
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Select the database
-	 *
-	 * @access	private called by the base class
-	 * @return	resource
-	 */
-	function db_select()
-	{
-		return TRUE;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Set client character set
-	 *
-	 * @access	public
-	 * @param	string
-	 * @param	string
-	 * @return	resource
-	 */
-	function db_set_charset($charset, $collation)
-	{
-		// @todo - add support if needed
-		return TRUE;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Version number query string
-	 *
-	 * @access	public
 	 * @return	string
 	 */
-	function _version()
+	public function version()
 	{
-		return sqlite_libversion();
+		return isset($this->data_cache['version'])
+			? $this->data_cache['version']
+			: $this->data_cache['version'] = sqlite_libversion();
 	}
 
 	// --------------------------------------------------------------------
@@ -172,30 +122,14 @@
 	/**
 	 * Execute the query
 	 *
-	 * @access	private called by the base class
 	 * @param	string	an SQL query
 	 * @return	resource
 	 */
-	function _execute($sql)
+	protected function _execute($sql)
 	{
-		$sql = $this->_prep_query($sql);
-		return @sqlite_query($this->conn_id, $sql);
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Prep the query
-	 *
-	 * If needed, each database adapter can prep the query string
-	 *
-	 * @access	private called by execute()
-	 * @param	string	an SQL query
-	 * @return	string
-	 */
-	function _prep_query($sql)
-	{
-		return $sql;
+		return $this->is_write_type($sql)
+			? @sqlite_exec($this->conn_id, $sql)
+			: @sqlite_query($this->conn_id, $sql);
 	}
 
 	// --------------------------------------------------------------------
@@ -203,18 +137,12 @@
 	/**
 	 * Begin Transaction
 	 *
-	 * @access	public
 	 * @return	bool
 	 */
-	function trans_begin($test_mode = FALSE)
+	public function trans_begin($test_mode = FALSE)
 	{
-		if ( ! $this->trans_enabled)
-		{
-			return TRUE;
-		}
-
 		// When transactions are nested we only begin/commit/rollback the outermost ones
-		if ($this->_trans_depth > 0)
+		if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
 		{
 			return TRUE;
 		}
@@ -222,7 +150,7 @@
 		// Reset the transaction failure flag.
 		// If the $test_mode flag is set to TRUE transactions will be rolled back
 		// even if the queries produce a successful result.
-		$this->_trans_failure = ($test_mode === TRUE) ? TRUE : FALSE;
+		$this->_trans_failure = ($test_mode === TRUE);
 
 		$this->simple_query('BEGIN TRANSACTION');
 		return TRUE;
@@ -233,18 +161,12 @@
 	/**
 	 * Commit Transaction
 	 *
-	 * @access	public
 	 * @return	bool
 	 */
-	function trans_commit()
+	public function trans_commit()
 	{
-		if ( ! $this->trans_enabled)
-		{
-			return TRUE;
-		}
-
 		// When transactions are nested we only begin/commit/rollback the outermost ones
-		if ($this->_trans_depth > 0)
+		if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
 		{
 			return TRUE;
 		}
@@ -258,18 +180,12 @@
 	/**
 	 * Rollback Transaction
 	 *
-	 * @access	public
 	 * @return	bool
 	 */
-	function trans_rollback()
+	public function trans_rollback()
 	{
-		if ( ! $this->trans_enabled)
-		{
-			return TRUE;
-		}
-
 		// When transactions are nested we only begin/commit/rollback the outermost ones
-		if ($this->_trans_depth > 0)
+		if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
 		{
 			return TRUE;
 		}
@@ -283,12 +199,11 @@
 	/**
 	 * Escape String
 	 *
-	 * @access	public
 	 * @param	string
 	 * @param	bool	whether or not the string will be used in a LIKE condition
 	 * @return	string
 	 */
-	function escape_str($str, $like = FALSE)
+	public function escape_str($str, $like = FALSE)
 	{
 		if (is_array($str))
 		{
@@ -305,9 +220,9 @@
 		// escape LIKE condition wildcards
 		if ($like === TRUE)
 		{
-			$str = str_replace(	array('%', '_', $this->_like_escape_chr),
-								array($this->_like_escape_chr.'%', $this->_like_escape_chr.'_', $this->_like_escape_chr.$this->_like_escape_chr),
-								$str);
+			return str_replace(array($this->_like_escape_chr, '%', '_'),
+						array($this->_like_escape_chr.$this->_like_escape_chr, $this->_like_escape_chr.'%', $this->_like_escape_chr.'_'),
+						$str);
 		}
 
 		return $str;
@@ -318,10 +233,9 @@
 	/**
 	 * Affected Rows
 	 *
-	 * @access	public
-	 * @return	integer
+	 * @return	int
 	 */
-	function affected_rows()
+	public function affected_rows()
 	{
 		return sqlite_changes($this->conn_id);
 	}
@@ -331,10 +245,9 @@
 	/**
 	 * Insert ID
 	 *
-	 * @access	public
-	 * @return	integer
+	 * @return	int
 	 */
-	function insert_id()
+	public function insert_id()
 	{
 		return @sqlite_last_insert_rowid($this->conn_id);
 	}
@@ -342,53 +255,22 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 * "Count All" query
-	 *
-	 * Generates a platform-specific query string that counts all records in
-	 * the specified database
-	 *
-	 * @access	public
-	 * @param	string
-	 * @return	string
-	 */
-	function count_all($table = '')
-	{
-		if ($table == '')
-		{
-			return 0;
-		}
-
-		$query = $this->query($this->_count_string . $this->_protect_identifiers('numrows') . " FROM " . $this->_protect_identifiers($table, TRUE, NULL, FALSE));
-
-		if ($query->num_rows() == 0)
-		{
-			return 0;
-		}
-
-		$row = $query->row();
-		$this->_reset_select();
-		return (int) $row->numrows;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
 	 * List table query
 	 *
 	 * Generates a platform-specific query string so that the table names can be fetched
 	 *
-	 * @access	private
-	 * @param	boolean
+	 * @param	bool
 	 * @return	string
 	 */
-	function _list_tables($prefix_limit = FALSE)
+	protected function _list_tables($prefix_limit = FALSE)
 	{
-		$sql = "SELECT name from sqlite_master WHERE type='table'";
+		$sql = "SELECT name FROM sqlite_master WHERE type='table'";
 
-		if ($prefix_limit !== FALSE AND $this->dbprefix != '')
+		if ($prefix_limit !== FALSE && $this->dbprefix != '')
 		{
-			$sql .= " AND 'name' LIKE '".$this->escape_like_str($this->dbprefix)."%' ".sprintf($this->_like_escape_str, $this->_like_escape_chr);
+			return $sql." AND 'name' LIKE '".$this->escape_like_str($this->dbprefix)."%' ".sprintf($this->_like_escape_str, $this->_like_escape_chr);
 		}
+
 		return $sql;
 	}
 
@@ -399,11 +281,10 @@
 	 *
 	 * Generates a platform-specific query string so that the column names can be fetched
 	 *
-	 * @access	public
 	 * @param	string	the table name
-	 * @return	string
+	 * @return	bool
 	 */
-	function _list_columns($table = '')
+	protected function _list_columns($table = '')
 	{
 		// Not supported
 		return FALSE;
@@ -416,209 +297,64 @@
 	 *
 	 * Generates a platform-specific query so that the column data can be retrieved
 	 *
-	 * @access	public
 	 * @param	string	the table name
-	 * @return	object
-	 */
-	function _field_data($table)
-	{
-		return "SELECT * FROM ".$table." LIMIT 1";
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * The error message string
-	 *
-	 * @access	private
 	 * @return	string
 	 */
-	function _error_message()
+	protected function _field_data($table)
 	{
-		return sqlite_error_string(sqlite_last_error($this->conn_id));
+		return 'SELECT * FROM '.$this->escape_identifiers($table).' LIMIT 1';
 	}
 
 	// --------------------------------------------------------------------
 
 	/**
-	 * The error message number
+	 * Error
 	 *
-	 * @access	private
-	 * @return	integer
+	 * Returns an array containing code and message of the last
+	 * database error that has occured.
+	 *
+	 * @return	array
 	 */
-	function _error_number()
+	public function error()
 	{
-		return sqlite_last_error($this->conn_id);
+		$error = array('code' => sqlite_last_error($this->conn_id));
+		$error['message'] = sqlite_error_string($error['code']);
+		return $error;
 	}
 
 	// --------------------------------------------------------------------
 
 	/**
-	 * Escape the SQL Identifiers
+	 * Replace statement
 	 *
-	 * This function escapes column and table names
+	 * Generates a platform-specific replace string from the supplied data
 	 *
-	 * @access	private
-	 * @param	string
-	 * @return	string
-	 */
-	function _escape_identifiers($item)
-	{
-		if ($this->_escape_char == '')
-		{
-			return $item;
-		}
-
-		foreach ($this->_reserved_identifiers as $id)
-		{
-			if (strpos($item, '.'.$id) !== FALSE)
-			{
-				$str = $this->_escape_char. str_replace('.', $this->_escape_char.'.', $item);
-
-				// remove duplicates if the user already included the escape
-				return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str);
-			}
-		}
-
-		if (strpos($item, '.') !== FALSE)
-		{
-			$str = $this->_escape_char.str_replace('.', $this->_escape_char.'.'.$this->_escape_char, $item).$this->_escape_char;
-		}
-		else
-		{
-			$str = $this->_escape_char.$item.$this->_escape_char;
-		}
-
-		// remove duplicates if the user already included the escape
-		return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str);
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * From Tables
-	 *
-	 * This function implicitly groups FROM tables so there is no confusion
-	 * about operator precedence in harmony with SQL standards
-	 *
-	 * @access	public
-	 * @param	type
-	 * @return	type
-	 */
-	function _from_tables($tables)
-	{
-		if ( ! is_array($tables))
-		{
-			$tables = array($tables);
-		}
-
-		return '('.implode(', ', $tables).')';
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Insert statement
-	 *
-	 * Generates a platform-specific insert string from the supplied data
-	 *
-	 * @access	public
 	 * @param	string	the table name
 	 * @param	array	the insert keys
 	 * @param	array	the insert values
 	 * @return	string
 	 */
-	function _insert($table, $keys, $values)
+	protected function _replace($table, $keys, $values)
 	{
-		return "INSERT INTO ".$table." (".implode(', ', $keys).") VALUES (".implode(', ', $values).")";
+		return 'INSERT OR '.parent::_replace($table, $keys, $values);
 	}
 
 	// --------------------------------------------------------------------
 
 	/**
-	 * Update statement
-	 *
-	 * Generates a platform-specific update string from the supplied data
-	 *
-	 * @access	public
-	 * @param	string	the table name
-	 * @param	array	the update data
-	 * @param	array	the where clause
-	 * @param	array	the orderby clause
-	 * @param	array	the limit clause
-	 * @return	string
-	 */
-	function _update($table, $values, $where, $orderby = array(), $limit = FALSE)
-	{
-		foreach ($values as $key => $val)
-		{
-			$valstr[] = $key." = ".$val;
-		}
-
-		$limit = ( ! $limit) ? '' : ' LIMIT '.$limit;
-
-		$orderby = (count($orderby) >= 1)?' ORDER BY '.implode(", ", $orderby):'';
-
-		$sql = "UPDATE ".$table." SET ".implode(', ', $valstr);
-
-		$sql .= ($where != '' AND count($where) >=1) ? " WHERE ".implode(" ", $where) : '';
-
-		$sql .= $orderby.$limit;
-
-		return $sql;
-	}
-
-
-	// --------------------------------------------------------------------
-
-	/**
 	 * Truncate statement
 	 *
 	 * Generates a platform-specific truncate string from the supplied data
-	 * If the database does not support the truncate() command
-	 * This function maps to "DELETE FROM table"
 	 *
-	 * @access	public
+	 * If the database does not support the truncate() command,
+	 * then this function maps to 'DELETE FROM table'
+	 *
 	 * @param	string	the table name
 	 * @return	string
 	 */
-	function _truncate($table)
+	protected function _truncate($table)
 	{
-		return $this->_delete($table);
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Delete statement
-	 *
-	 * Generates a platform-specific delete string from the supplied data
-	 *
-	 * @access	public
-	 * @param	string	the table name
-	 * @param	array	the where clause
-	 * @param	string	the limit clause
-	 * @return	string
-	 */
-	function _delete($table, $where = array(), $like = array(), $limit = FALSE)
-	{
-		$conditions = '';
-
-		if (count($where) > 0 OR count($like) > 0)
-		{
-			$conditions = "\nWHERE ";
-			$conditions .= implode("\n", $this->ar_where);
-
-			if (count($where) > 0 && count($like) > 0)
-			{
-				$conditions .= " AND ";
-			}
-			$conditions .= implode("\n", $like);
-		}
-
-		$limit = ( ! $limit) ? '' : ' LIMIT '.$limit;
-
-		return "DELETE FROM ".$table.$conditions.$limit;
+		return 'DELETE FROM '.$table;
 	}
 
 	// --------------------------------------------------------------------
@@ -628,24 +364,14 @@
 	 *
 	 * Generates a platform-specific LIMIT clause
 	 *
-	 * @access	public
 	 * @param	string	the sql query string
-	 * @param	integer	the number of rows to limit the query to
-	 * @param	integer	the offset value
+	 * @param	int	the number of rows to limit the query to
+	 * @param	int	the offset value
 	 * @return	string
 	 */
-	function _limit($sql, $limit, $offset)
+	protected function _limit($sql, $limit, $offset)
 	{
-		if ($offset == 0)
-		{
-			$offset = '';
-		}
-		else
-		{
-			$offset .= ", ";
-		}
-
-		return $sql."LIMIT ".$offset.$limit;
+		return $sql.'LIMIT '.($offset == 0 ? '' : $offset.', ').$limit;
 	}
 
 	// --------------------------------------------------------------------
@@ -653,18 +379,14 @@
 	/**
 	 * Close DB Connection
 	 *
-	 * @access	public
-	 * @param	resource
 	 * @return	void
 	 */
-	function _close($conn_id)
+	protected function _close()
 	{
-		@sqlite_close($conn_id);
+		@sqlite_close($this->conn_id);
 	}
 
-
 }
 
-
 /* End of file sqlite_driver.php */
 /* Location: ./system/database/drivers/sqlite/sqlite_driver.php */
\ No newline at end of file
diff --git a/system/database/drivers/sqlite/sqlite_forge.php b/system/database/drivers/sqlite/sqlite_forge.php
index 2b723be..e02e327 100644
--- a/system/database/drivers/sqlite/sqlite_forge.php
+++ b/system/database/drivers/sqlite/sqlite_forge.php
@@ -1,13 +1,13 @@
-<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
- * 
+ *
  * Licensed under the Open Software License version 3.0
- * 
+ *
  * This source file is subject to the Open Software License (OSL 3.0) that is
  * bundled with this package in the files license.txt / license.rst.  It is
  * also available through the world wide web at this URL:
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * SQLite Forge Class
  *
@@ -39,11 +37,10 @@
 	/**
 	 * Create database
 	 *
-	 * @access	public
 	 * @param	string	the database name
 	 * @return	bool
 	 */
-	function _create_database()
+	public function create_database($db_name = '')
 	{
 		// In SQLite, a database is created when you connect to the database.
 		// We'll return TRUE so that an error isn't generated
@@ -55,90 +52,84 @@
 	/**
 	 * Drop database
 	 *
-	 * @access	private
-	 * @param	string	the database name
+	 * @param	string	the database name (ignored)
 	 * @return	bool
 	 */
-	function _drop_database($name)
+	public function drop_database($db_name = '')
 	{
 		if ( ! @file_exists($this->db->database) OR ! @unlink($this->db->database))
 		{
-			if ($this->db->db_debug)
-			{
-				return $this->db->display_error('db_unable_to_drop');
-			}
-			return FALSE;
+			return ($this->db->db_debug) ? $this->db->display_error('db_unable_to_drop') : FALSE;
 		}
+		elseif ( ! empty($this->db->data_cache['db_names']))
+		{
+			$key = array_search(strtolower($this->db->database), array_map('strtolower', $this->db->data_cache['db_names']), TRUE);
+			if ($key !== FALSE)
+			{
+				unset($this->db->data_cache['db_names'][$key]);
+			}
+		}
+
 		return TRUE;
 	}
+
 	// --------------------------------------------------------------------
 
 	/**
 	 * Create Table
 	 *
-	 * @access	private
 	 * @param	string	the table name
 	 * @param	array	the fields
 	 * @param	mixed	primary key(s)
 	 * @param	mixed	key(s)
-	 * @param	boolean	should 'IF NOT EXISTS' be added to the SQL
+	 * @param	bool	should 'IF NOT EXISTS' be added to the SQL
 	 * @return	bool
 	 */
-	function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists)
+	protected function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists)
 	{
 		$sql = 'CREATE TABLE ';
 
 		// IF NOT EXISTS added to SQLite in 3.3.0
-		if ($if_not_exists === TRUE && version_compare($this->db->_version(), '3.3.0', '>=') === TRUE)
+		if ($if_not_exists === TRUE && version_compare($this->db->version(), '3.3.0', '>=') === TRUE)
 		{
 			$sql .= 'IF NOT EXISTS ';
 		}
 
-		$sql .= $this->db->_escape_identifiers($table)."(";
+		$sql .= $this->db->escape_identifiers($table).' (';
 		$current_field_count = 0;
 
-		foreach ($fields as $field=>$attributes)
+		foreach ($fields as $field => $attributes)
 		{
 			// Numeric field names aren't allowed in databases, so if the key is
 			// numeric, we know it was assigned by PHP and the developer manually
 			// entered the field information, so we'll simply add it to the list
 			if (is_numeric($field))
 			{
-				$sql .= "\n\t$attributes";
+				$sql .= "\n\t".$attributes;
 			}
 			else
 			{
 				$attributes = array_change_key_case($attributes, CASE_UPPER);
 
-				$sql .= "\n\t".$this->db->_protect_identifiers($field);
+				$sql .= "\n\t".$this->db->escape_identifiers($field).' '.$attributes['TYPE'];
 
-				$sql .=  ' '.$attributes['TYPE'];
+				empty($attributes['CONSTRAINT']) OR $sql .= '('.$attributes['CONSTRAINT'].')';
 
-				if (array_key_exists('CONSTRAINT', $attributes))
-				{
-					$sql .= '('.$attributes['CONSTRAINT'].')';
-				}
-
-				if (array_key_exists('UNSIGNED', $attributes) && $attributes['UNSIGNED'] === TRUE)
+				if ( ! empty($attributes['UNSIGNED']) && $attributes['UNSIGNED'] === TRUE)
 				{
 					$sql .= ' UNSIGNED';
 				}
 
-				if (array_key_exists('DEFAULT', $attributes))
+				if (isset($attributes['DEFAULT']))
 				{
-					$sql .= ' DEFAULT \''.$attributes['DEFAULT'].'\'';
+					$sql .= " DEFAULT '".$attributes['DEFAULT']."'";
 				}
 
-				if (array_key_exists('NULL', $attributes) && $attributes['NULL'] === TRUE)
-				{
-					$sql .= ' NULL';
-				}
-				else
-				{
-					$sql .= ' NOT NULL';
-				}
 
-				if (array_key_exists('AUTO_INCREMENT', $attributes) && $attributes['AUTO_INCREMENT'] === TRUE)
+				$sql .= ( ! empty($attributes['NULL']) && $attributes['NULL'] === TRUE)
+					? ' NULL' : ' NOT NULL';
+
+				if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE)
 				{
 					$sql .= ' AUTO_INCREMENT';
 				}
@@ -153,49 +144,22 @@
 
 		if (count($primary_keys) > 0)
 		{
-			$primary_keys = $this->db->_protect_identifiers($primary_keys);
-			$sql .= ",\n\tPRIMARY KEY (" . implode(', ', $primary_keys) . ")";
+			$sql .= ",\n\tPRIMARY KEY (".implode(', ', $this->db->escape_identifiers($primary_keys)).')';
 		}
 
 		if (is_array($keys) && count($keys) > 0)
 		{
 			foreach ($keys as $key)
 			{
-				if (is_array($key))
-				{
-					$key = $this->db->_protect_identifiers($key);
-				}
-				else
-				{
-					$key = array($this->db->_protect_identifiers($key));
-				}
+				$key = is_array($key)
+					? $this->db->escape_identifiers($key)
+					: array($this->db->escape_identifiers($key));
 
-				$sql .= ",\n\tUNIQUE (" . implode(', ', $key) . ")";
+				$sql .= ",\n\tUNIQUE (".implode(', ', $key).')';
 			}
 		}
 
-		$sql .= "\n)";
-
-		return $sql;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Drop Table
-	 *
-	 *  Unsupported feature in SQLite
-	 *
-	 * @access	private
-	 * @return	bool
-	 */
-	function _drop_table($table)
-	{
-		if ($this->db->db_debug)
-		{
-			return $this->db->display_error('db_unsuported_feature');
-		}
-		return array();
+		return $sql."\n)";
 	}
 
 	// --------------------------------------------------------------------
@@ -206,71 +170,34 @@
 	 * Generates a platform-specific query so that a table can be altered
 	 * Called by add_column(), drop_column(), and column_alter(),
 	 *
-	 * @access	private
 	 * @param	string	the ALTER type (ADD, DROP, CHANGE)
 	 * @param	string	the column name
 	 * @param	string	the table name
 	 * @param	string	the column definition
 	 * @param	string	the default value
-	 * @param	boolean	should 'NOT NULL' be added
+	 * @param	bool	should 'NOT NULL' be added
 	 * @param	string	the field after which we should add the new field
-	 * @return	object
+	 * @return	string
 	 */
-	function _alter_table($alter_type, $table, $column_name, $column_definition = '', $default_value = '', $null = '', $after_field = '')
+	protected function _alter_table($alter_type, $table, $column_name, $column_definition = '', $default_value = '', $null = '', $after_field = '')
 	{
-		$sql = 'ALTER TABLE '.$this->db->_protect_identifiers($table)." $alter_type ".$this->db->_protect_identifiers($column_name);
-
-		// DROP has everything it needs now.
-		if ($alter_type == 'DROP')
+		/* SQLite only supports adding new columns and it does
+		 * NOT support the AFTER statement. Each new column will
+		 * be added as the last one in the table.
+		 */
+		if ($alter_type !== 'ADD COLUMN')
 		{
-			// SQLite does not support dropping columns
-			// http://www.sqlite.org/omitted.html
-			// http://www.sqlite.org/faq.html#q11
+			// Not supported
 			return FALSE;
 		}
 
-		$sql .= " $column_definition";
-
-		if ($default_value != '')
-		{
-			$sql .= " DEFAULT \"$default_value\"";
-		}
-
-		if ($null === NULL)
-		{
-			$sql .= ' NULL';
-		}
-		else
-		{
-			$sql .= ' NOT NULL';
-		}
-
-		if ($after_field != '')
-		{
-			$sql .= ' AFTER ' . $this->db->_protect_identifiers($after_field);
-		}
-
-		return $sql;
-
+		return 'ALTER TABLE '.$this->db->escape_identifiers($table).' '.$alter_type.' '.$this->db->escape_identifiers($column_name)
+			.' '.$column_definition
+			.($default_value != '' ? " DEFAULT '".$default_value."'" : '')
+			// If NOT NULL is specified, the field must have a DEFAULT value other than NULL
+			.(($null !== NULL && $default_value !== 'NULL') ? ' NOT NULL' : ' NULL');
 	}
 
-	// --------------------------------------------------------------------
-
-	/**
-	 * Rename a table
-	 *
-	 * Generates a platform-specific query so that a table can be renamed
-	 *
-	 * @access	private
-	 * @param	string	the old table name
-	 * @param	string	the new table name
-	 * @return	string
-	 */
-	function _rename_table($table_name, $new_table_name)
-	{
-		$sql = 'ALTER TABLE '.$this->db->_protect_identifiers($table_name)." RENAME TO ".$this->db->_protect_identifiers($new_table_name);
-		return $sql;
-	}
 }
 
 /* End of file sqlite_forge.php */
diff --git a/system/database/drivers/sqlite/sqlite_result.php b/system/database/drivers/sqlite/sqlite_result.php
index 74c0dc5..741dc9d 100644
--- a/system/database/drivers/sqlite/sqlite_result.php
+++ b/system/database/drivers/sqlite/sqlite_result.php
@@ -1,13 +1,13 @@
-<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
- * 
+ *
  * Licensed under the Open Software License version 3.0
- * 
+ *
  * This source file is subject to the Open Software License (OSL 3.0) that is
  * bundled with this package in the files license.txt / license.rst.  It is
  * also available through the world wide web at this URL:
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * SQLite Result Class
  *
@@ -41,10 +39,9 @@
 	/**
 	 * Number of rows in the result set
 	 *
-	 * @access	public
-	 * @return	integer
+	 * @return	int
 	 */
-	function num_rows()
+	public function num_rows()
 	{
 		return @sqlite_num_rows($this->result_id);
 	}
@@ -54,10 +51,9 @@
 	/**
 	 * Number of fields in the result set
 	 *
-	 * @access	public
-	 * @return	integer
+	 * @return	int
 	 */
-	function num_fields()
+	public function num_fields()
 	{
 		return @sqlite_num_fields($this->result_id);
 	}
@@ -69,15 +65,14 @@
 	 *
 	 * Generates an array of column names
 	 *
-	 * @access	public
 	 * @return	array
 	 */
-	function list_fields()
+	public function list_fields()
 	{
 		$field_names = array();
-		for ($i = 0; $i < $this->num_fields(); $i++)
+		for ($i = 0, $c = $this->num_fields(); $i < $c; $i++)
 		{
-			$field_names[] = sqlite_field_name($this->result_id, $i);
+			$field_names[$i] = sqlite_field_name($this->result_id, $i);
 		}
 
 		return $field_names;
@@ -90,22 +85,19 @@
 	 *
 	 * Generates an array of objects containing field meta-data
 	 *
-	 * @access	public
 	 * @return	array
 	 */
-	function field_data()
+	public function field_data()
 	{
 		$retval = array();
-		for ($i = 0; $i < $this->num_fields(); $i++)
+		for ($i = 0, $c = $this->num_fields(); $i < $c; $i++)
 		{
-			$F				= new stdClass();
-			$F->name		= sqlite_field_name($this->result_id, $i);
-			$F->type		= 'varchar';
-			$F->max_length	= 0;
-			$F->primary_key = 0;
-			$F->default		= '';
-
-			$retval[] = $F;
+			$retval[$i]			= new stdClass();
+			$retval[$i]->name		= sqlite_field_name($this->result_id, $i);
+			$retval[$i]->type		= 'varchar';
+			$retval[$i]->max_length		= 0;
+			$retval[$i]->primary_key	= 0;
+			$retval[$i]->default		= '';
 		}
 
 		return $retval;
@@ -114,28 +106,15 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 * Free the result
-	 *
-	 * @return	null
-	 */
-	function free_result()
-	{
-		// Not implemented in SQLite
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
 	 * Data Seek
 	 *
-	 * Moves the internal pointer to the desired offset.  We call
+	 * Moves the internal pointer to the desired offset. We call
 	 * this internally before fetching results to make sure the
 	 * result set starts at zero
 	 *
-	 * @access	private
-	 * @return	array
+	 * @return	bool
 	 */
-	function _data_seek($n = 0)
+	protected function _data_seek($n = 0)
 	{
 		return sqlite_seek($this->result_id, $n);
 	}
@@ -147,10 +126,9 @@
 	 *
 	 * Returns the result set as an array
 	 *
-	 * @access	private
 	 * @return	array
 	 */
-	function _fetch_assoc()
+	protected function _fetch_assoc()
 	{
 		return sqlite_fetch_array($this->result_id);
 	}
@@ -162,30 +140,20 @@
 	 *
 	 * Returns the result set as an object
 	 *
-	 * @access	private
 	 * @return	object
 	 */
-	function _fetch_object()
+	protected function _fetch_object()
 	{
 		if (function_exists('sqlite_fetch_object'))
 		{
 			return sqlite_fetch_object($this->result_id);
 		}
-		else
-		{
-			$arr = sqlite_fetch_array($this->result_id, SQLITE_ASSOC);
-			if (is_array($arr))
-			{
-				$obj = (object) $arr;
-				return $obj;
-			} else {
-				return NULL;
-			}
-		}
+
+		$arr = sqlite_fetch_array($this->result_id, SQLITE_ASSOC);
+		return is_array($arr) ? (object) $arr : FALSE;
 	}
 
 }
 
-
 /* End of file sqlite_result.php */
 /* Location: ./system/database/drivers/sqlite/sqlite_result.php */
\ No newline at end of file
diff --git a/system/database/drivers/sqlite/sqlite_utility.php b/system/database/drivers/sqlite/sqlite_utility.php
index f00687e..1bcb42d 100644
--- a/system/database/drivers/sqlite/sqlite_utility.php
+++ b/system/database/drivers/sqlite/sqlite_utility.php
@@ -1,13 +1,13 @@
-<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
- * 
+ *
  * Licensed under the Open Software License version 3.0
- * 
+ *
  * This source file is subject to the Open Software License (OSL 3.0) that is
  * bundled with this package in the files license.txt / license.rst.  It is
  * also available through the world wide web at this URL:
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * SQLite Utility Class
  *
@@ -36,72 +34,20 @@
  */
 class CI_DB_sqlite_utility extends CI_DB_utility {
 
-	/**
-	 * List databases
-	 *
-	 * I don't believe you can do a database listing with SQLite
-	 * since each database is its own file.  I suppose we could
-	 * try reading a directory looking for SQLite files, but
-	 * that doesn't seem like a terribly good idea
-	 *
-	 * @access	private
-	 * @return	bool
-	 */
-	function _list_databases()
-	{
-		if ($this->db_debug)
-		{
-			return $this->db->display_error('db_unsuported_feature');
-		}
-		return array();
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Optimize table query
-	 *
-	 * Is optimization even supported in SQLite?
-	 *
-	 * @access	private
-	 * @param	string	the table name
-	 * @return	object
-	 */
-	function _optimize_table($table)
-	{
-		return FALSE;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Repair table query
-	 *
-	 * Are table repairs even supported in SQLite?
-	 *
-	 * @access	private
-	 * @param	string	the table name
-	 * @return	object
-	 */
-	function _repair_table($table)
-	{
-		return FALSE;
-	}
-
-	// --------------------------------------------------------------------
+	protected $_list_databases	= FALSE;
 
 	/**
 	 * SQLite Export
 	 *
-	 * @access	private
 	 * @param	array	Preferences
 	 * @return	mixed
 	 */
-	function _backup($params = array())
+	protected function _backup($params = array())
 	{
 		// Currently unsupported
 		return $this->db->display_error('db_unsuported_feature');
 	}
+
 }
 
 /* End of file sqlite_utility.php */
diff --git a/application/errors/index.html b/system/database/drivers/sqlite3/index.html
similarity index 100%
copy from application/errors/index.html
copy to system/database/drivers/sqlite3/index.html
diff --git a/system/database/drivers/sqlite3/sqlite3_driver.php b/system/database/drivers/sqlite3/sqlite3_driver.php
new file mode 100644
index 0000000..bed6189
--- /dev/null
+++ b/system/database/drivers/sqlite3/sqlite3_driver.php
@@ -0,0 +1,385 @@
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.2.4 or newer
+ *
+ * NOTICE OF LICENSE
+ *
+ * Licensed under the Open Software License version 3.0
+ *
+ * This source file is subject to the Open Software License (OSL 3.0) that is
+ * bundled with this package in the files license.txt / license.rst.  It is
+ * also available through the world wide web at this URL:
+ * http://opensource.org/licenses/OSL-3.0
+ * If you did not receive a copy of the license and are unable to obtain it
+ * through the world wide web, please send an email to
+ * licensing@ellislab.com so we can send you a copy immediately.
+ *
+ * @package		CodeIgniter
+ * @author		EllisLab Dev Team
+ * @copyright	Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/)
+ * @license		http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
+ * @link		http://codeigniter.com
+ * @since		Version 1.0
+ * @filesource
+ */
+
+/**
+ * SQLite3 Database Adapter Class
+ *
+ * Note: _DB is an extender class that the app controller
+ * creates dynamically based on whether the query builder
+ * class is being used or not.
+ *
+ * @package		CodeIgniter
+ * @subpackage	Drivers
+ * @category	Database
+ * @author		Andrey Andreev
+ * @link		http://codeigniter.com/user_guide/database/
+ * @since		Version 3.0
+ */
+class CI_DB_sqlite3_driver extends CI_DB {
+
+	public $dbdriver = 'sqlite3';
+
+	// The character used for escaping
+	protected $_escape_char = '"';
+
+	// clause and character used for LIKE escape sequences
+	protected $_like_escape_str = ' ESCAPE \'%s\' ';
+	protected $_like_escape_chr = '!';
+
+	/**
+	 * The syntax to count rows is slightly different across different
+	 * database engines, so this string appears in each driver and is
+	 * used for the count_all() and count_all_results() functions.
+	 */
+	protected $_count_string = 'SELECT COUNT(*) AS ';
+	protected $_random_keyword = ' RANDOM()';
+
+	/**
+	 * Non-persistent database connection
+	 *
+	 * @return	object	type SQLite3
+	 */
+	public function db_connect()
+	{
+		try
+		{
+			return ( ! $this->password)
+				? new SQLite3($this->database)
+				: new SQLite3($this->database, SQLITE3_OPEN_READWRITE | SQLITE3_OPEN_CREATE, $this->password);
+		}
+		catch (Exception $e)
+		{
+			return FALSE;
+		}
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Persistent database connection
+	 *
+	 * @return  object	type SQLite3
+	 */
+	public function db_pconnect()
+	{
+		log_message('debug', 'SQLite3 doesn\'t support persistent connections');
+		return $this->db_connect();
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Database version number
+	 *
+	 * @return	string
+	 */
+	public function version()
+	{
+		if (isset($this->data_cache['version']))
+		{
+			return $this->data_cache['version'];
+		}
+
+		$version = SQLite3::version();
+		return $this->data_cache['version'] = $version['versionString'];
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Execute the query
+	 *
+	 * @param	string	an SQL query
+	 * @return	mixed	SQLite3Result object or bool
+	 */
+	protected function _execute($sql)
+	{
+		// TODO: Implement use of SQLite3::querySingle(), if needed
+
+		return $this->is_write_type($sql)
+			? $this->conn_id->exec($sql)
+			: $this->conn_id->query($sql);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Begin Transaction
+	 *
+	 * @return	bool
+	 */
+	public function trans_begin($test_mode = FALSE)
+	{
+		// When transactions are nested we only begin/commit/rollback the outermost ones
+		if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
+		{
+			return TRUE;
+		}
+
+		// Reset the transaction failure flag.
+		// If the $test_mode flag is set to TRUE transactions will be rolled back
+		// even if the queries produce a successful result.
+		$this->_trans_failure = ($test_mode === TRUE);
+
+		return $this->conn_id->exec('BEGIN TRANSACTION');
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Commit Transaction
+	 *
+	 * @return	bool
+	 */
+	public function trans_commit()
+	{
+		// When transactions are nested we only begin/commit/rollback the outermost ones
+		if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
+		{
+			return TRUE;
+		}
+
+		return $this->conn_id->exec('END TRANSACTION');
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Rollback Transaction
+	 *
+	 * @return	bool
+	 */
+	public function trans_rollback()
+	{
+		// When transactions are nested we only begin/commit/rollback the outermost ones
+		if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
+		{
+			return TRUE;
+		}
+
+		return $this->conn_id->exec('ROLLBACK');
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Escape String
+	 *
+	 * @param	string
+	 * @param	bool	whether or not the string will be used in a LIKE condition
+	 * @return	string
+	 */
+	public function escape_str($str, $like = FALSE)
+	{
+		if (is_array($str))
+		{
+			foreach ($str as $key => $val)
+			{
+				$str[$key] = $this->escape_str($val, $like);
+			}
+
+			return $str;
+		}
+
+		$str = $this->conn_id->escapeString(remove_invisible_characters($str));
+
+		// escape LIKE condition wildcards
+		if ($like === TRUE)
+		{
+			return str_replace(array($this->_like_escape_chr, '%', '_'),
+						array($this->_like_escape_chr.$this->_like_escape_chr, $this->_like_escape_chr.'%', $this->_like_escape_chr.'_'),
+						$str);
+		}
+
+		return $str;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Affected Rows
+	 *
+	 * @return	int
+	 */
+	public function affected_rows()
+	{
+		return $this->conn_id->changes();
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Insert ID
+	 *
+	 * @return	int
+	 */
+	public function insert_id()
+	{
+		return $this->conn_id->lastInsertRowID();
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Show table query
+	 *
+	 * Generates a platform-specific query string so that the table names can be fetched
+	 *
+	 * @param	bool
+	 * @return	string
+	 */
+	protected function _list_tables($prefix_limit = FALSE)
+	{
+		return 'SELECT "NAME" FROM "SQLITE_MASTER" WHERE "TYPE" = \'table\''
+			.(($prefix_limit !== FALSE && $this->dbprefix != '')
+				? ' AND "NAME" LIKE \''.$this->escape_like_str($this->dbprefix).'%\' '.sprintf($this->_like_escape_str, $this->_like_escape_chr)
+				: '');
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Show column query
+	 *
+	 * Generates a platform-specific query string so that the column names can be fetched
+	 *
+	 * @param	string	the table name
+	 * @return	string
+	 */
+	protected function _list_columns($table = '')
+	{
+		// Not supported
+		return FALSE;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Field data query
+	 *
+	 * Generates a platform-specific query so that the column data can be retrieved
+	 *
+	 * @param	string	the table name
+	 * @return	string
+	 */
+	protected function _field_data($table)
+	{
+		return 'SELECT * FROM '.$table.' LIMIT 0,1';
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * The error message string
+	 *
+	 * @return	string
+	 */
+	protected function _error_message()
+	{
+		return $this->conn_id->lastErrorMsg();
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * The error message number
+	 *
+	 * @return	int
+	 */
+	protected function _error_number()
+	{
+		return $this->conn_id->lastErrorCode();
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Replace statement
+	 *
+	 * Generates a platform-specific replace string from the supplied data
+	 *
+	 * @param	string	the table name
+	 * @param	array	the insert keys
+	 * @param	array	the insert values
+	 * @return	string
+	 */
+	protected function _replace($table, $keys, $values)
+	{
+		return 'INSERT OR '.parent::_replace($table, $keys, $values);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Truncate statement
+	 *
+	 * Generates a platform-specific truncate string from the supplied data
+	 *
+	 * If the database does not support the truncate() command, then,
+	 * then this method maps to 'DELETE FROM table'
+	 *
+	 * @param	string	the table name
+	 * @return	string
+	 */
+	protected function _truncate($table)
+	{
+		return 'DELETE FROM '.$table;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Limit string
+	 *
+	 * Generates a platform-specific LIMIT clause
+	 *
+	 * @param	string	the sql query string
+	 * @param	int	the number of rows to limit the query to
+	 * @param	int	the offset value
+	 * @return	string
+	 */
+	protected function _limit($sql, $limit, $offset)
+	{
+		return $sql.' LIMIT '.($offset ? $offset.',' : '').$limit;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Close DB Connection
+	 *
+	 * @return	void
+	 */
+	protected function _close()
+	{
+		$this->conn_id->close();
+	}
+
+}
+
+/* End of file sqlite3_driver.php */
+/* Location: ./system/database/drivers/sqlite3/sqlite3_driver.php */
\ No newline at end of file
diff --git a/system/database/drivers/sqlite3/sqlite3_forge.php b/system/database/drivers/sqlite3/sqlite3_forge.php
new file mode 100644
index 0000000..6a76ba9
--- /dev/null
+++ b/system/database/drivers/sqlite3/sqlite3_forge.php
@@ -0,0 +1,211 @@
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.1.6 or newer
+ *
+ * NOTICE OF LICENSE
+ *
+ * Licensed under the Open Software License version 3.0
+ *
+ * This source file is subject to the Open Software License (OSL 3.0) that is
+ * bundled with this package in the files license.txt / license.rst.  It is
+ * also available through the world wide web at this URL:
+ * http://opensource.org/licenses/OSL-3.0
+ * If you did not receive a copy of the license and are unable to obtain it
+ * through the world wide web, please send an email to
+ * licensing@ellislab.com so we can send you a copy immediately.
+ *
+ * @package		CodeIgniter
+ * @author		EllisLab Dev Team
+ * @copyright	Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/)
+ * @license		http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
+ * @link		http://codeigniter.com
+ * @since		Version 1.0
+ * @filesource
+ */
+
+/**
+ * SQLite3 Forge Class
+ *
+ * @category	Database
+ * @author	Andrey Andreev
+ * @link	http://codeigniter.com/user_guide/database/
+ */
+class CI_DB_sqlite3_forge extends CI_DB_forge {
+
+	/**
+	 * Create database
+	 *
+	 * @param	string	the database name
+	 * @return	bool
+	 */
+	public function create_database($db_name = '')
+	{
+		// In SQLite, a database is created when you connect to the database.
+		// We'll return TRUE so that an error isn't generated
+		return TRUE;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Drop database
+	 *
+	 * @param	string	the database name (ignored)
+	 * @return	bool
+	 */
+	public function drop_database($db_name = '')
+	{
+		// In SQLite, a database is dropped when we delete a file
+		if (@file_exists($this->db->database))
+		{
+			// We need to close the pseudo-connection first
+			$this->db->close();
+			if ( ! @unlink($this->db->database))
+			{
+				return $this->db->db_debug ? $this->db->display_error('db_unable_to_drop') : FALSE;
+			}
+			elseif ( ! empty($this->db->data_cache['db_names']))
+			{
+				$key = array_search(strtolower($this->db->database), array_map('strtolower', $this->db->data_cache['db_names']), TRUE);
+				if ($key !== FALSE)
+				{
+					unset($this->db->data_cache['db_names'][$key]);
+				}
+			}
+
+			return TRUE;
+		}
+
+		return $this->db->db_debug ? $this->db->display_error('db_unable_to_drop') : FALSE;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Create Table
+	 *
+	 * @param	string	the table name
+	 * @param	array	the fields
+	 * @param	mixed	primary key(s)
+	 * @param	mixed	key(s)
+	 * @param	bool	should 'IF NOT EXISTS' be added to the SQL
+	 * @return	bool
+	 */
+	protected function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists)
+	{
+		$sql = 'CREATE TABLE ';
+
+		// IF NOT EXISTS added to SQLite in 3.3.0
+		if ($if_not_exists === TRUE && version_compare($this->db->version(), '3.3.0', '>=') === TRUE)
+		{
+			$sql .= 'IF NOT EXISTS ';
+		}
+
+		$sql .= $this->db->escape_identifiers($table).' (';
+		$current_field_count = 0;
+
+		foreach ($fields as $field => $attributes)
+		{
+			// Numeric field names aren't allowed in databases, so if the key is
+			// numeric, we know it was assigned by PHP and the developer manually
+			// entered the field information, so we'll simply add it to the list
+			if (is_numeric($field))
+			{
+				$sql .= "\n\t".$attributes;
+			}
+			else
+			{
+				$attributes = array_change_key_case($attributes, CASE_UPPER);
+
+				$sql .= "\n\t".$this->db->escape_identifiers($field).' '.$attributes['TYPE'];
+
+				empty($attributes['CONSTRAINT']) OR $sql .= '('.$attributes['CONSTRAINT'].')';
+
+				if ( ! empty($attributes['UNSIGNED']) && $attributes['UNSIGNED'] === TRUE)
+				{
+					$sql .= ' UNSIGNED';
+				}
+
+				if (isset($attributes['DEFAULT']))
+				{
+					$sql .= " DEFAULT '".$attributes['DEFAULT']."'";
+				}
+
+				$sql .= ( ! empty($attributes['NULL']) && $attributes['NULL'] === TRUE)
+					? ' NULL' : ' NOT NULL';
+
+				if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE)
+				{
+					$sql .= ' AUTO_INCREMENT';
+				}
+			}
+
+			// don't add a comma on the end of the last field
+			if (++$current_field_count < count($fields))
+			{
+				$sql .= ',';
+			}
+		}
+
+		if (count($primary_keys) > 0)
+		{
+			$sql .= ",\n\tPRIMARY KEY (".implode(', ', $this->db->escape_identifiers($primary_keys)).')';
+		}
+
+		if (is_array($keys) && count($keys) > 0)
+		{
+			foreach ($keys as $key)
+			{
+				$key = is_array($key)
+					? $this->db->escape_identifiers($key)
+					: array($this->db->escape_identifiers($key));
+
+				$sql .= ",\n\tUNIQUE (".implode(', ', $key).')';
+			}
+		}
+
+		return $sql."\n)";
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Alter table query
+	 *
+	 * Generates a platform-specific query so that a table can be altered
+	 * Called by add_column(), drop_column(), and column_alter(),
+	 *
+	 * @param	string	the ALTER type (ADD, DROP, CHANGE)
+	 * @param	string	the column name
+	 * @param	string	the table name
+	 * @param	string	the column definition
+	 * @param	string	the default value
+	 * @param	bool	should 'NOT NULL' be added
+	 * @param	string	the field after which we should add the new field
+	 * @return	string
+	 */
+	protected function _alter_table($alter_type, $table, $column_name, $column_definition = '', $default_value = '', $null = '', $after_field = '')
+	{
+		/* SQLite only supports adding new columns and it does
+		 * NOT support the AFTER statement. Each new column will
+		 * be added as the last one in the table.
+		 */
+		if ($alter_type !== 'ADD COLUMN')
+		{
+			// Not supported
+			return FALSE;
+		}
+
+		return 'ALTER TABLE '.$this->db->escape_identifiers($table).' '.$alter_type.' '.$this->db->escape_identifiers($column_name)
+			.' '.$column_definition
+			.($default_value !== '' ? ' DEFAULT '.$default_value : '')
+			// If NOT NULL is specified, the field must have a DEFAULT value other than NULL
+			.(($null !== NULL && $default_value !== 'NULL') ? ' NOT NULL' : ' NULL');
+	}
+
+}
+
+/* End of file sqlite3_forge.php */
+/* Location: ./system/database/drivers/sqlite3/sqlite3_forge.php */
\ No newline at end of file
diff --git a/system/database/drivers/sqlite3/sqlite3_result.php b/system/database/drivers/sqlite3/sqlite3_result.php
new file mode 100644
index 0000000..946b365
--- /dev/null
+++ b/system/database/drivers/sqlite3/sqlite3_result.php
@@ -0,0 +1,615 @@
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.1.6 or newer
+ *
+ * NOTICE OF LICENSE
+ *
+ * Licensed under the Open Software License version 3.0
+ *
+ * This source file is subject to the Open Software License (OSL 3.0) that is
+ * bundled with this package in the files license.txt / license.rst.  It is
+ * also available through the world wide web at this URL:
+ * http://opensource.org/licenses/OSL-3.0
+ * If you did not receive a copy of the license and are unable to obtain it
+ * through the world wide web, please send an email to
+ * licensing@ellislab.com so we can send you a copy immediately.
+ *
+ * @package		CodeIgniter
+ * @author		EllisLab Dev Team
+ * @copyright	Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/)
+ * @license		http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
+ * @link		http://codeigniter.com
+ * @since		Version 1.0
+ * @filesource
+ */
+
+/**
+ * SQLite Result Class
+ *
+ * This class extends the parent result class: CI_DB_result
+ *
+ * @category	Database
+ * @author	Andrey Andreev
+ * @link	http://codeigniter.com/user_guide/database/
+ */
+class CI_DB_sqlite3_result extends CI_DB_result {
+
+	// Overwriting the parent here, so we have a way to know if it's already set
+	public $num_rows;
+
+	// num_fields() might be called multiple times, so we'll use this one to cache it's result
+	protected $_num_fields;
+
+	/**
+	 * Number of rows in the result set
+	 *
+	 * @return	int
+	 */
+	public function num_rows()
+	{
+		/* The SQLite3 driver doesn't have a graceful way to do this,
+		 * so we'll have to do it on our own.
+		 */
+		return is_int($this->num_rows)
+			? $this->num_rows
+			: $this->num_rows = count($this->result_array());
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Number of fields in the result set
+	 *
+	 * @return	int
+	 */
+	public function num_fields()
+	{
+		return ( ! is_int($this->_num_fields))
+			? $this->_num_fields = $this->result_id->numColumns()
+			: $this->_num_fields;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Fetch Field Names
+	 *
+	 * Generates an array of column names
+	 *
+	 * @return	array
+	 */
+	public function list_fields()
+	{
+		$field_names = array();
+		for ($i = 0, $c = $this->num_fields(); $i < $c; $i++)
+		{
+			$field_names[] = $this->result_id->columnName($i);
+		}
+
+		return $field_names;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Field data
+	 *
+	 * Generates an array of objects containing field meta-data
+	 *
+	 * @return	array
+	 */
+	public function field_data()
+	{
+		$retval = array();
+		for ($i = 0, $c = $this->num_fields(); $i < $this->num_fields(); $i++)
+		{
+			$retval[$i]			= new stdClass();
+			$retval[$i]->name		= $this->result_id->columnName($i);
+			$retval[$i]->type		= 'varchar';
+			$retval[$i]->max_length		= 0;
+			$retval[$i]->primary_key	= 0;
+			$retval[$i]->default		= '';
+		}
+
+		return $retval;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Free the result
+	 *
+	 * @return	void
+	 */
+	public function free_result()
+	{
+		if (is_object($this->result_id))
+		{
+			$this->result_id->finalize();
+			$this->result_id = NULL;
+		}
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Result - associative array
+	 *
+	 * Returns the result set as an array
+	 *
+	 * @return	array
+	 */
+	protected function _fetch_assoc()
+	{
+		return $this->result_id->fetchArray(SQLITE3_ASSOC);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Result - object
+	 *
+	 * Returns the result set as an object
+	 *
+	 * @return	object
+	 */
+	protected function _fetch_object()
+	{
+		// No native support for fetching as an object
+		$row = $this->_fetch_assoc();
+		return ($row !== FALSE) ? (object) $row : FALSE;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Query result. "array" version.
+	 *
+	 * return	array
+	 */
+	public function result_array()
+	{
+		if (count($this->result_array) > 0)
+		{
+			return $this->result_array;
+		}
+		elseif (is_array($this->row_data))
+		{
+			if (count($this->row_data) === 0)
+			{
+				return $this->result_array;
+			}
+			else
+			{
+				$row_index = count($this->row_data);
+			}
+		}
+		else
+		{
+			$row_index = 0;
+			$this->row_data = array();
+		}
+
+		$row = NULL;
+		while ($row = $this->_fetch_assoc())
+		{
+			$this->row_data[$row_index++] = $row;
+		}
+
+		return $this->result_array = $this->row_data;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Query result. "object" version.
+	 *
+	 * @return	array
+	 */
+	public function result_object()
+	{
+		if (count($this->result_object) > 0)
+		{
+			return $this->result_object;
+		}
+		elseif (count($this->result_array) > 0)
+		{
+			for ($i = 0, $c = count($this->result_array); $i < $c; $i++)
+			{
+				$this->result_object[] = (object) $this->result_array[$i];
+			}
+
+			return $this->result_object;
+		}
+		elseif (is_array($this->row_data))
+		{
+			if (count($this->row_data) === 0)
+			{
+				return $this->result_object;
+			}
+			else
+			{
+				$row_index = count($this->row_data);
+				for ($i = 0; $i < $row_index; $i++)
+				{
+					$this->result_object[$i] = (object) $this->row_data[$i];
+				}
+			}
+		}
+		else
+		{
+			$row_index = 0;
+			$this->row_data = array();
+		}
+
+		$row = NULL;
+		while ($row = $this->_fetch_assoc())
+		{
+			$this->row_data[$row_index] = $row;
+			$this->result_object[$row_index++] = (object) $row;
+		}
+
+		$this->result_array = $this->row_data;
+
+		/* As described for the num_rows() method - there's no easy
+		 * way to get the number of rows selected. Our work-around
+		 * solution (as in here as well) first checks if result_array
+		 * exists and returns its count. It doesn't however check for
+		 * custom_object_result, so - do it here.
+		 */
+		if ( ! is_int($this->num_rows))
+		{
+			$this->num_rows = count($this->result_object);
+		}
+
+		return $this->result_object;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Query result. Custom object version.
+	 *
+	 * @param	string	class name used to instantiate rows to
+	 * @return	array
+	 */
+	public function custom_result_object($class_name)
+	{
+		if (array_key_exists($class_name, $this->custom_result_object))
+		{
+			return $this->custom_result_object[$class_name];
+		}
+
+		if ( ! class_exists($class_name) OR ! is_object($this->result_id) OR $this->num_rows() === 0)
+		{
+			return array();
+		}
+
+		/* Even if result_array hasn't been set prior to custom_result_object being called,
+		 * num_rows() has done it.
+		*/
+		$data = &$this->result_array;
+
+		$result_object = array();
+		for ($i = 0, $c = count($data); $i < $c; $i++)
+		{
+			$result_object[$i] = new $class_name();
+			foreach ($data[$i] as $key => $value)
+			{
+				$result_object[$i]->$key = $value;
+			}
+		}
+
+		/* As described for the num_rows() method - there's no easy
+		 * way to get the number of rows selected. Our work-around
+		 * solution (as in here as well) first checks if result_array
+		 * exists and returns its count. It doesn't however check for
+		 * custom_object_result, so - do it here.
+		 */
+		if ( ! is_int($this->num_rows))
+		{
+			$this->num_rows = count($result_object);
+		}
+
+		// Cache and return the array
+		return $this->custom_result_object[$class_name] = $result_object;
+        }
+
+	// --------------------------------------------------------------------
+
+	/* Single row result.
+	 *
+	 * Acts as a wrapper for row_object(), row_array()
+	 * and custom_row_object(). Also used by first_row(), next_row()
+	 * and previous_row().
+	 *
+	 * @param	int	row index
+	 * @param	string	('object', 'array' or a custom class name)
+	 * @return	mixed	whatever was passed to the second parameter
+	 */
+	public function row($n = 0, $type = 'object')
+	{
+		if ($type === 'object')
+		{
+			return $this->row_object($n);
+		}
+		elseif ($type === 'array')
+		{
+			return $this->row_array($n);
+		}
+
+		return $this->custom_row_object($n, $type);
+	}
+
+	// --------------------------------------------------------------------
+
+	/* Single row result. Array version.
+	 *
+	 * @param	int	row index
+	 * @return	array
+	 */
+	public function row_array($n = 0)
+	{
+		// Make sure $n is not a string
+		if ( ! is_int($n))
+		{
+			$n = (int) $n;
+		}
+
+		/* If row_data is initialized, it means that we've already tried
+		 * (at least) to fetch some data, so ... check if we already have
+		 * this row.
+		*/
+		if (is_array($this->row_data))
+		{
+			/* If we already have row_data[$n] - return it.
+			 *
+			 * If we enter the elseif, there's a number of reasons to
+			 * return an empty array:
+			 *
+			 *	- count($this->row_data) === 0 means there are no results
+			 *	- num_rows being set or result_array having count() > 0 means
+			 *	  that we've already fetched all data and $n is greater than
+			 *	  our highest row index available
+			 *	- $n < $this->current_row means that if such row existed,
+			 *	  we would've already returned it, therefore $n is an
+			 *	  invalid index
+			 */
+			if (isset($this->row_data[$n])) // We already have this row
+			{
+				$this->current_row = $n;
+				return $this->row_data[$n];
+			}
+			elseif (count($this->row_data) === 0 OR is_int($this->num_rows)
+				OR count($this->result_array) > 0 OR $n < $this->current_row)
+			{
+				// No such row exists
+				return NULL;
+			}
+
+			// Get the next row index that would actually need to be fetched
+			$current_row = ($this->current_row < count($this->row_data)) ? count($this->row_data) : $this->current_row + 1;
+		}
+		else
+		{
+			$current_row = $this->current_row = 0;
+			$this->row_data = array();
+		}
+
+		/* Fetch more data, if available
+		 *
+		 * NOTE: Operator precedence is important here, if you change
+		 *	 'AND' with '&&' - it WILL BREAK the results, as
+		 *	 $row will be assigned the scalar value of both
+		 *	 expressions!
+		 */
+		while ($row = $this->_fetch_assoc() AND $current_row <= $n)
+		{
+			$this->row_data[$current_row++] = $row;
+		}
+
+		// This would mean that there's no (more) data to fetch
+		if ( ! is_array($this->row_data) OR ! isset($this->row_data[$n]))
+		{
+			// Cache what we already have
+			if (is_array($this->row_data))
+			{
+				$this->num_rows = count($this->row_data);
+				/* Usually, row_data could have less elements than result_array,
+				 * but at this point - they should be exactly the same.
+				 */
+				$this->result_array = $this->row_data;
+			}
+			else
+			{
+				$this->num_rows = 0;
+			}
+
+			return NULL;
+		}
+
+		$this->current_row = $n;
+		return $this->row_data[$n];
+	}
+
+	// --------------------------------------------------------------------
+
+	/* Single row result. Object version.
+	 *
+	 * @param	int	row index
+	 * @return	mixed	object if row found; empty array if not
+	 */
+	public function row_object($n = 0)
+	{
+		// Make sure $n is not a string
+		if ( ! is_int($n))
+		{
+			$n = (int) $n;
+		}
+
+		/* Logic here is exactly the same as in row_array,
+		 * except we have to cast row_data[$n] to an object.
+		 *
+		 * If we already have result_object though - we can
+		 * directly return from it.
+		 */
+		if (isset($this->result_object[$n]))
+		{
+			$this->current_row = $n;
+			return $this->result_object[$n];
+		}
+
+		$row = $this->row_array($n);
+		// Cast only if the row exists
+		if (count($row) > 0)
+		{
+			$this->current_row = $n;
+			return (object) $row;
+		}
+
+		return NULL;
+	}
+
+	// --------------------------------------------------------------------
+
+	/* Single row result. Custom object version.
+	 *
+	 * @param	int	row index
+	 * @param	string	custom class name
+	 * @return	mixed	custom object if row found; empty array otherwise
+	 */
+	public function custom_row_object($n = 0, $class_name)
+	{
+		// Make sure $n is not a string
+		if ( ! is_int($n))
+		{
+			$n = (int) $n;
+		}
+
+		if (array_key_exists($class_name, $this->custom_result_object))
+		{
+			/* We already have a the whole result set with this class_name,
+			 * return the specified row if it exists, and an empty array if
+			 * it doesn't.
+			 */
+			if (isset($this->custom_result_object[$class_name][$n]))
+			{
+				$this->current_row = $n;
+				return $this->custom_result_object[$class_name][$n];
+			}
+			else
+			{
+				return NULL;
+			}
+		}
+		elseif ( ! class_exists($class_name)) // No such class exists
+		{
+			return NULL;
+		}
+
+		$row = $this->row_array($n);
+		// A non-array would mean that the row doesn't exist
+		if ( ! is_array($row))
+		{
+			return NULL;
+		}
+
+		// Convert to the desired class and return
+		$row_object = new $class_name();
+		foreach ($row as $key => $value)
+		{
+			$row_object->$key = $value;
+		}
+
+		$this->current_row = $n;
+		return $row_object;
+	}
+
+	// --------------------------------------------------------------------
+
+	/* First row result.
+	 *
+	 * @param	string	('object', 'array' or a custom class name)
+	 * @return	mixed	whatever was passed to the second parameter
+	 */
+	public function first_row($type = 'object')
+	{
+		return $this->row(0, $type);
+	}
+
+	// --------------------------------------------------------------------
+
+	/* Last row result.
+	 *
+	 * @param	string	('object', 'array' or a custom class name)
+	 * @return	mixed	whatever was passed to the second parameter
+	 */
+	public function last_row($type = 'object')
+	{
+		$result = &$this->result($type);
+		if ( ! isset($this->num_rows))
+		{
+			$this->num_rows = count($result);
+		}
+		$this->current_row = $this->num_rows - 1;
+		return $result[$this->current_row];
+	}
+
+	// --------------------------------------------------------------------
+
+	/* Next row result.
+	 *
+	 * @param	string	('object', 'array' or a custom class name)
+	 * @return	mixed	whatever was passed to the second parameter
+	 */
+	public function next_row($type = 'object')
+	{
+		if (is_array($this->row_data))
+		{
+			$count = count($this->row_data);
+			$n = ($this->current_row > $count OR ($this->current_row === 0 && $count === 0)) ? $count : $this->current_row + 1;
+		}
+		else
+		{
+			$n = 0;
+		}
+
+		return $this->row($n, $type);
+	}
+
+	// --------------------------------------------------------------------
+
+	/* Previous row result.
+	 *
+	 * @param	string	('object', 'array' or a custom class name)
+	 * @return	mixed	whatever was passed to the second parameter
+	 */
+	public function previous_row($type = 'object')
+	{
+		$n = ($this->current_row !== 0) ? $this->current_row - 1 : 0;
+		return $this->row($n, $type);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Data Seek
+	 *
+	 * Moves the internal pointer to the desired offset. We call
+	 * this internally before fetching results to make sure the
+	 * result set starts at zero
+	 *
+	 * @return	array
+	 */
+	protected function _data_seek($n = 0)
+	{
+		// Only resetting to the start of the result set is supported
+		return $this->result_id->reset();
+	}
+
+}
+
+/* End of file sqlite3_result.php */
+/* Location: ./system/database/drivers/sqlite3/sqlite3_result.php */
\ No newline at end of file
diff --git a/system/database/drivers/sqlite3/sqlite3_utility.php b/system/database/drivers/sqlite3/sqlite3_utility.php
new file mode 100644
index 0000000..965c838
--- /dev/null
+++ b/system/database/drivers/sqlite3/sqlite3_utility.php
@@ -0,0 +1,54 @@
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.1.6 or newer
+ *
+ * NOTICE OF LICENSE
+ *
+ * Licensed under the Open Software License version 3.0
+ *
+ * This source file is subject to the Open Software License (OSL 3.0) that is
+ * bundled with this package in the files license.txt / license.rst.  It is
+ * also available through the world wide web at this URL:
+ * http://opensource.org/licenses/OSL-3.0
+ * If you did not receive a copy of the license and are unable to obtain it
+ * through the world wide web, please send an email to
+ * licensing@ellislab.com so we can send you a copy immediately.
+ *
+ * @package		CodeIgniter
+ * @author		EllisLab Dev Team
+ * @copyright	Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/)
+ * @license		http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
+ * @link		http://codeigniter.com
+ * @since		Version 1.0
+ * @filesource
+ */
+
+/**
+ * SQLite3 Utility Class
+ *
+ * @category	Database
+ * @author	Andrey Andreev
+ * @link	http://codeigniter.com/user_guide/database/
+ */
+class CI_DB_sqlite3_utility extends CI_DB_utility {
+
+	protected $_list_databases	= FALSE;
+
+	/**
+	 * SQLite Export
+	 *
+	 * @param	array	Preferences
+	 * @return	mixed
+	 */
+	protected function _backup($params = array())
+	{
+		// Not supported
+		return $this->db->display_error('db_unsuported_feature');
+	}
+
+}
+
+/* End of file sqlite3_utility.php */
+/* Location: ./system/database/drivers/sqlite3/sqlite3_utility.php */
\ No newline at end of file
diff --git a/system/database/drivers/sqlsrv/sqlsrv_driver.php b/system/database/drivers/sqlsrv/sqlsrv_driver.php
index 6fd52ef..825c024 100644
--- a/system/database/drivers/sqlsrv/sqlsrv_driver.php
+++ b/system/database/drivers/sqlsrv/sqlsrv_driver.php
@@ -1,13 +1,13 @@
-<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
- * 
+ *
  * Licensed under the Open Software License version 3.0
- * 
+ *
  * This source file is subject to the Open Software License (OSL 3.0) that is
  * bundled with this package in the files license.txt / license.rst.  It is
  * also available through the world wide web at this URL:
@@ -21,17 +21,15 @@
  * @copyright	Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/)
  * @license		http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
  * @link		http://codeigniter.com
- * @since		Version 1.0
+ * @since		Version 2.0.3
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * SQLSRV Database Adapter Class
  *
  * Note: _DB is an extender class that the app controller
- * creates dynamically based on whether the active record
+ * creates dynamically based on whether the query builder
  * class is being used or not.
  *
  * @package		CodeIgniter
@@ -42,50 +40,61 @@
  */
 class CI_DB_sqlsrv_driver extends CI_DB {
 
-	var $dbdriver = 'sqlsrv';
+	public $dbdriver = 'sqlsrv';
 
 	// The character used for escaping
-	var $_escape_char = '';
+	protected $_escape_char = '"';
 
 	// clause and character used for LIKE escape sequences
-	var $_like_escape_str = " ESCAPE '%s' ";
-	var $_like_escape_chr = '!';
+	protected $_like_escape_str = " ESCAPE '%s' ";
+	protected $_like_escape_chr = '!';
 
 	/**
 	 * The syntax to count rows is slightly different across different
 	 * database engines, so this string appears in each driver and is
 	 * used for the count_all() and count_all_results() functions.
 	 */
-	var $_count_string = "SELECT COUNT(*) AS ";
-	var $_random_keyword = ' ASC'; // not currently supported
+	protected $_count_string = 'SELECT COUNT(*) AS ';
+	protected $_random_keyword = ' NEWID()';
+
+	// SQLSRV-specific properties
+	protected $_quoted_identifier = TRUE;
 
 	/**
 	 * Non-persistent database connection
 	 *
-	 * @access	private called by the base class
 	 * @return	resource
 	 */
-	function db_connect($pooling = false)
+	public function db_connect($pooling = FALSE)
 	{
 		// Check for a UTF-8 charset being passed as CI's default 'utf8'.
 		$character_set = (0 === strcasecmp('utf8', $this->char_set)) ? 'UTF-8' : $this->char_set;
 
 		$connection = array(
-			'UID'				=> empty($this->username) ? '' : $this->username,
-			'PWD'				=> empty($this->password) ? '' : $this->password,
-			'Database'			=> $this->database,
-			'ConnectionPooling' => $pooling ? 1 : 0,
+			'UID'			=> empty($this->username) ? '' : $this->username,
+			'PWD'			=> empty($this->password) ? '' : $this->password,
+			'Database'		=> $this->database,
+			'ConnectionPooling'	=> $pooling ? 1 : 0,
 			'CharacterSet'		=> $character_set,
-			'ReturnDatesAsStrings' => 1
+			'ReturnDatesAsStrings'	=> 1
 		);
-		
-		// If the username and password are both empty, assume this is a 
+
+		// If the username and password are both empty, assume this is a
 		// 'Windows Authentication Mode' connection.
-		if(empty($connection['UID']) && empty($connection['PWD'])) {
+		if (empty($connection['UID']) && empty($connection['PWD']))
+		{
 			unset($connection['UID'], $connection['PWD']);
 		}
 
-		return sqlsrv_connect($this->hostname, $connection);
+		$conn_id = sqlsrv_connect($this->hostname, $connection);
+
+		// Determine how identifiers are escaped
+		$query = $this->query('SELECT CASE WHEN (@@OPTIONS | 256) = @@OPTIONS THEN 1 ELSE 0 END AS qi');
+		$query = $query->row_array();
+		$this->_quoted_identifier = empty($query) ? FALSE : (bool) $query->qi;
+		$this->_escape_char = ($this->_quoted_identifier) ? '"' : array('[', ']');
+
+		return $conn_id;
 	}
 
 	// --------------------------------------------------------------------
@@ -93,10 +102,9 @@
 	/**
 	 * Persistent database connection
 	 *
-	 * @access	private called by the base class
 	 * @return	resource
 	 */
-	function db_pconnect()
+	public function db_pconnect()
 	{
 		return $this->db_connect(TRUE);
 	}
@@ -104,46 +112,25 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 * Reconnect
-	 *
-	 * Keep / reestablish the db connection if no queries have been
-	 * sent for a length of time exceeding the server's idle timeout
-	 *
-	 * @access	public
-	 * @return	void
-	 */
-	function reconnect()
-	{
-		// not implemented in MSSQL
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
 	 * Select the database
 	 *
-	 * @access	private called by the base class
-	 * @return	resource
+	 * @param	string	database name
+	 * @return	bool
 	 */
-	function db_select()
+	public function db_select($database = '')
 	{
-		return $this->_execute('USE ' . $this->database);
-	}
+		if ($database === '')
+		{
+			$database = $this->database;
+		}
 
-	// --------------------------------------------------------------------
+		if ($this->_execute('USE '.$database))
+		{
+			$this->database = $database;
+			return TRUE;
+		}
 
-	/**
-	 * Set client character set
-	 *
-	 * @access	public
-	 * @param	string
-	 * @param	string
-	 * @return	resource
-	 */
-	function db_set_charset($charset, $collation)
-	{
-		// @todo - add support if needed
-		return TRUE;
+		return FALSE;
 	}
 
 	// --------------------------------------------------------------------
@@ -151,33 +138,14 @@
 	/**
 	 * Execute the query
 	 *
-	 * @access	private called by the base class
 	 * @param	string	an SQL query
 	 * @return	resource
 	 */
-	function _execute($sql)
+	protected function _execute($sql)
 	{
-		$sql = $this->_prep_query($sql);
-		return sqlsrv_query($this->conn_id, $sql, null, array(
-			'Scrollable'				=> SQLSRV_CURSOR_STATIC,
-			'SendStreamParamsAtExec'	=> true
-		));
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Prep the query
-	 *
-	 * If needed, each database adapter can prep the query string
-	 *
-	 * @access	private called by execute()
-	 * @param	string	an SQL query
-	 * @return	string
-	 */
-	function _prep_query($sql)
-	{
-		return $sql;
+		return (is_write_type($sql) && stripos($sql, 'INSERT') === FALSE)
+			? sqlsrv_query($this->conn_id, $sql)
+			: sqlsrv_query($this->conn_id, $sql, NULL, array('Scrollable' => SQLSRV_CURSOR_STATIC));
 	}
 
 	// --------------------------------------------------------------------
@@ -185,18 +153,12 @@
 	/**
 	 * Begin Transaction
 	 *
-	 * @access	public
 	 * @return	bool
 	 */
-	function trans_begin($test_mode = FALSE)
+	public function trans_begin($test_mode = FALSE)
 	{
-		if ( ! $this->trans_enabled)
-		{
-			return TRUE;
-		}
-
 		// When transactions are nested we only begin/commit/rollback the outermost ones
-		if ($this->_trans_depth > 0)
+		if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
 		{
 			return TRUE;
 		}
@@ -204,7 +166,7 @@
 		// Reset the transaction failure flag.
 		// If the $test_mode flag is set to TRUE transactions will be rolled back
 		// even if the queries produce a successful result.
-		$this->_trans_failure = ($test_mode === TRUE) ? TRUE : FALSE;
+		$this->_trans_failure = ($test_mode === TRUE);
 
 		return sqlsrv_begin_transaction($this->conn_id);
 	}
@@ -214,18 +176,12 @@
 	/**
 	 * Commit Transaction
 	 *
-	 * @access	public
 	 * @return	bool
 	 */
-	function trans_commit()
+	public function trans_commit()
 	{
-		if ( ! $this->trans_enabled)
-		{
-			return TRUE;
-		}
-
 		// When transactions are nested we only begin/commit/rollback the outermost ones
-		if ($this->_trans_depth > 0)
+		if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
 		{
 			return TRUE;
 		}
@@ -238,18 +194,12 @@
 	/**
 	 * Rollback Transaction
 	 *
-	 * @access	public
 	 * @return	bool
 	 */
-	function trans_rollback()
+	public function trans_rollback()
 	{
-		if ( ! $this->trans_enabled)
-		{
-			return TRUE;
-		}
-
 		// When transactions are nested we only begin/commit/rollback the outermost ones
-		if ($this->_trans_depth > 0)
+		if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
 		{
 			return TRUE;
 		}
@@ -262,12 +212,11 @@
 	/**
 	 * Escape String
 	 *
-	 * @access	public
 	 * @param	string
 	 * @param	bool	whether or not the string will be used in a LIKE condition
 	 * @return	string
 	 */
-	function escape_str($str, $like = FALSE)
+	public function escape_str($str, $like = FALSE)
 	{
 		// Escape single quotes
 		return str_replace("'", "''", $str);
@@ -278,86 +227,49 @@
 	/**
 	 * Affected Rows
 	 *
-	 * @access	public
-	 * @return	integer
+	 * @return	int
 	 */
-	function affected_rows()
+	public function affected_rows()
 	{
-		return @sqlrv_rows_affected($this->conn_id);
+		return sqlrv_rows_affected($this->result_id);
 	}
 
 	// --------------------------------------------------------------------
 
 	/**
-	* Insert ID
-	*
-	* Returns the last id created in the Identity column.
-	*
-	* @access public
-	* @return integer
-	*/
-	function insert_id()
-	{
-		return $this->query('select @@IDENTITY as insert_id')->row('insert_id');
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	* Parse major version
-	*
-	* Grabs the major version number from the
-	* database server version string passed in.
-	*
-	* @access private
-	* @param string $version
-	* @return int16 major version number
-	*/
-	function _parse_major_version($version)
-	{
-		preg_match('/([0-9]+)\.([0-9]+)\.([0-9]+)/', $version, $ver_info);
-		return $ver_info[1]; // return the major version b/c that's all we're interested in.
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	* Version number query string
-	*
-	* @access public
-	* @return string
-	*/
-	function _version()
-	{
-		$info = sqlsrv_server_info($this->conn_id);
-		return sprintf("select '%s' as ver", $info['SQLServerVersion']);
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * "Count All" query
+	 * Insert ID
 	 *
-	 * Generates a platform-specific query string that counts all records in
-	 * the specified database
+	 * Returns the last id created in the Identity column.
 	 *
-	 * @access	public
-	 * @param	string
 	 * @return	string
 	 */
-	function count_all($table = '')
+	public function insert_id()
 	{
-		if ($table == '')
-			return '0';
-	
-		$query = $this->query("SELECT COUNT(*) AS numrows FROM " . $this->dbprefix . $table);
-		
-		if ($query->num_rows() == 0)
-			return '0';
+		$query = $this->query('SELECT @@IDENTITY AS insert_id');
+		$query = $query->row();
+		return $query->insert_id;
+	}
 
-		$row = $query->row();
-		$this->_reset_select();
-		return $row->numrows;
+	// --------------------------------------------------------------------
+
+	/**
+	 * Database version number
+	 *
+	 * @return	string
+	 */
+	public function version()
+	{
+		if (isset($this->data_cache['version']))
+		{
+			return $this->data_cache['version'];
+		}
+
+		if (($info = sqlsrv_server_info($this->conn_id)) === FALSE)
+		{
+			return FALSE;
+		}
+
+		return $this->data_cache['version'] = $info['SQLServerVersion'];
 	}
 
 	// --------------------------------------------------------------------
@@ -367,11 +279,10 @@
 	 *
 	 * Generates a platform-specific query string so that the table names can be fetched
 	 *
-	 * @access	private
-	 * @param	boolean
+	 * @param	bool
 	 * @return	string
 	 */
-	function _list_tables($prefix_limit = FALSE)
+	protected function _list_tables($prefix_limit = FALSE)
 	{
 		return "SELECT name FROM sysobjects WHERE type = 'U' ORDER BY name";
 	}
@@ -383,13 +294,12 @@
 	 *
 	 * Generates a platform-specific query string so that the column names can be fetched
 	 *
-	 * @access	private
 	 * @param	string	the table name
 	 * @return	string
 	 */
-	function _list_columns($table = '')
+	protected function _list_columns($table = '')
 	{
-		return "SELECT * FROM INFORMATION_SCHEMA.Columns WHERE TABLE_NAME = '".$this->_escape_table($table)."'";
+		return "SELECT * FROM INFORMATION_SCHEMA.Columns WHERE TABLE_NAME = '".$table."'";
 	}
 
 	// --------------------------------------------------------------------
@@ -399,73 +309,50 @@
 	 *
 	 * Generates a platform-specific query so that the column data can be retrieved
 	 *
-	 * @access	public
-	 * @param	string	the table name
-	 * @return	object
-	 */
-	function _field_data($table)
-	{
-		return "SELECT TOP 1 * FROM " . $this->_escape_table($table);	
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * The error message string
-	 *
-	 * @access	private
-	 * @return	string
-	 */
-	function _error_message()
-	{
-		$error = array_shift(sqlsrv_errors());
-		return !empty($error['message']) ? $error['message'] : null;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * The error message number
-	 *
-	 * @access	private
-	 * @return	integer
-	 */
-	function _error_number()
-	{
-		$error = array_shift(sqlsrv_errors());
-		return isset($error['SQLSTATE']) ? $error['SQLSTATE'] : null;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Escape Table Name
-	 *
-	 * This function adds backticks if the table name has a period
-	 * in it. Some DBs will get cranky unless periods are escaped
-	 *
-	 * @access	private
 	 * @param	string	the table name
 	 * @return	string
 	 */
-	function _escape_table($table)
+	protected function _field_data($table)
 	{
-		return $table;
-	}	
+		return 'SELECT TOP 1 * FROM '.$table;
+	}
 
+	// --------------------------------------------------------------------
 
 	/**
-	 * Escape the SQL Identifiers
+	 * Error
 	 *
-	 * This function escapes column and table names
+	 * Returns an array containing code and message of the last
+	 * database error that has occured.
 	 *
-	 * @access	private
-	 * @param	string
-	 * @return	string
+	 * @return	array
 	 */
-	function _escape_identifiers($item)
+	public function error()
 	{
-		return $item;
+		$error = array('code' => '00000', 'message' => '');
+		$sqlsrv_errors = sqlsrv_errors(SQLSRV_ERR_ERRORS);
+
+		if ( ! is_array($sqlsrv_errors))
+		{
+			return $error;
+		}
+
+		$sqlsrv_error = array_shift($sqlsrv_errors);
+		if (isset($sqlsrv_error['SQLSTATE']))
+		{
+			$error['code'] = isset($sqlsrv_error['code']) ? $sqlsrv_error['SQLSTATE'].'/'.$sqlsrv_error['code'] : $sqlsrv_error['SQLSTATE'];
+		}
+		elseif (isset($sqlsrv_error['code']))
+		{
+			$error['code'] = $sqlsrv_error['code'];
+		}
+
+		if (isset($sqlsrv_error['message']))
+		{
+			$error['message'] = $sqlsrv_error['message'];
+		}
+
+		return $error;
 	}
 
 	// --------------------------------------------------------------------
@@ -476,36 +363,12 @@
 	 * This function implicitly groups FROM tables so there is no confusion
 	 * about operator precedence in harmony with SQL standards
 	 *
-	 * @access	public
-	 * @param	type
-	 * @return	type
-	 */
-	function _from_tables($tables)
-	{
-		if ( ! is_array($tables))
-		{
-			$tables = array($tables);
-		}
-
-		return implode(', ', $tables);
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Insert statement
-	 *
-	 * Generates a platform-specific insert string from the supplied data
-	 *
-	 * @access	public
-	 * @param	string	the table name
-	 * @param	array	the insert keys
-	 * @param	array	the insert values
+	 * @param	array
 	 * @return	string
 	 */
-	function _insert($table, $keys, $values)
-	{	
-		return "INSERT INTO ".$this->_escape_table($table)." (".implode(', ', $keys).") VALUES (".implode(', ', $values).")";
+	protected function _from_tables($tables)
+	{
+		return is_array($tables) ? implode(', ', $tables) : $tables;
 	}
 
 	// --------------------------------------------------------------------
@@ -515,40 +378,47 @@
 	 *
 	 * Generates a platform-specific update string from the supplied data
 	 *
-	 * @access	public
 	 * @param	string	the table name
 	 * @param	array	the update data
 	 * @param	array	the where clause
-	 * @param	array	the orderby clause
-	 * @param	array	the limit clause
+	 * @param	array	the orderby clause (ignored)
+	 * @param	array	the limit clause (ignored)
+	 * @param	array	the like clause
 	 * @return	string
 	 */
-	function _update($table, $values, $where)
+	protected function _update($table, $values, $where, $orderby = array(), $limit = FALSE, $like = array())
 	{
-		foreach($values as $key => $val)
+		foreach ($values as $key => $val)
 		{
-			$valstr[] = $key." = ".$val;
+			$valstr[] = $key.' = '.$val;
 		}
-	
-		return "UPDATE ".$this->_escape_table($table)." SET ".implode(', ', $valstr)." WHERE ".implode(" ", $where);
+
+		$where = empty($where) ? '' : ' WHERE '.implode(' ', $where);
+
+		if ( ! empty($like))
+		{
+			$where .= ($where === '' ? ' WHERE ' : ' AND ').implode(' ', $like);
+		}
+
+		return 'UPDATE '.$table.' SET '.implode(', ', $valstr).$where;
 	}
-	
+
 	// --------------------------------------------------------------------
 
 	/**
 	 * Truncate statement
 	 *
 	 * Generates a platform-specific truncate string from the supplied data
-	 * If the database does not support the truncate() command
-	 * This function maps to "DELETE FROM table"
 	 *
-	 * @access	public
+	 * If the database does not support the truncate() command,
+	 * then this method maps to 'DELETE FROM table'
+	 *
 	 * @param	string	the table name
 	 * @return	string
 	 */
-	function _truncate($table)
+	protected function _truncate($table)
 	{
-		return "TRUNCATE ".$table;
+		return 'TRUNCATE TABLE '.$table;
 	}
 
 	// --------------------------------------------------------------------
@@ -558,15 +428,24 @@
 	 *
 	 * Generates a platform-specific delete string from the supplied data
 	 *
-	 * @access	public
 	 * @param	string	the table name
 	 * @param	array	the where clause
+	 * @param	array	the like clause
 	 * @param	string	the limit clause
 	 * @return	string
 	 */
-	function _delete($table, $where)
+	protected function _delete($table, $where = array(), $like = array(), $limit = FALSE)
 	{
-		return "DELETE FROM ".$this->_escape_table($table)." WHERE ".implode(" ", $where);
+		$conditions = array();
+
+		empty($where) OR $conditions[] = implode(' ', $where);
+		empty($like) OR $conditions[] = implode(' ', $like);
+
+		$conditions = (count($conditions) > 0) ? ' WHERE '.implode(' AND ', $conditions) : '';
+
+		return ($limit)
+			? 'WITH ci_delete AS (SELECT TOP '.$limit.' * FROM '.$table.$conditions.') DELETE FROM ci_delete'
+			: 'DELETE FROM '.$table.$conditions;
 	}
 
 	// --------------------------------------------------------------------
@@ -576,17 +455,36 @@
 	 *
 	 * Generates a platform-specific LIMIT clause
 	 *
-	 * @access	public
 	 * @param	string	the sql query string
-	 * @param	integer	the number of rows to limit the query to
-	 * @param	integer	the offset value
+	 * @param	int	the number of rows to limit the query to
+	 * @param	int	the offset value
 	 * @return	string
 	 */
-	function _limit($sql, $limit, $offset)
+	protected function _limit($sql, $limit, $offset)
 	{
-		$i = $limit + $offset;
-	
-		return preg_replace('/(^\SELECT (DISTINCT)?)/i','\\1 TOP '.$i.' ', $sql);		
+		// As of SQL Server 2012 (11.0.*) OFFSET is supported
+		if (version_compare($this->version(), '11', '>='))
+		{
+			return $sql.' OFFSET '.(int) $offset.' ROWS FETCH NEXT '.(int) $limit.' ROWS ONLY';
+		}
+
+		$limit = $offset + $limit;
+
+		// An ORDER BY clause is required for ROW_NUMBER() to work
+		if ($offset && ! empty($this->qb_orderby))
+		{
+			$orderby = 'ORDER BY '.implode(', ', $this->qb_orderby);
+
+			// We have to strip the ORDER BY clause
+			$sql = trim(substr($sql, 0, strrpos($sql, 'ORDER BY '.$orderby)));
+
+			return 'SELECT '.(count($this->qb_select) === 0 ? '*' : implode(', ', $this->qb_select))." FROM (\n"
+				.preg_replace('/^(SELECT( DISTINCT)?)/i', '\\1 ROW_NUMBER() OVER('.$orderby.') AS '.$this->escape_identifiers('CI_rownum').', ', $sql)
+				."\n) ".$this->escape_identifiers('CI_subquery')
+				."\nWHERE ".$this->escape_identifiers('CI_rownum').' BETWEEN '.((int) $offset + 1).' AND '.$limit;
+		}
+
+		return preg_replace('/(^\SELECT (DISTINCT)?)/i','\\1 TOP '.$limit.' ', $sql);
 	}
 
 	// --------------------------------------------------------------------
@@ -594,18 +492,14 @@
 	/**
 	 * Close DB Connection
 	 *
-	 * @access	public
-	 * @param	resource
 	 * @return	void
 	 */
-	function _close($conn_id)
+	protected function _close()
 	{
-		@sqlsrv_close($conn_id);
+		@sqlsrv_close($this->conn_id);
 	}
 
 }
 
-
-
-/* End of file mssql_driver.php */
-/* Location: ./system/database/drivers/mssql/mssql_driver.php */
\ No newline at end of file
+/* End of file sqlsrv_driver.php */
+/* Location: ./system/database/drivers/sqlsrv/sqlsrv_driver.php */
\ No newline at end of file
diff --git a/system/database/drivers/sqlsrv/sqlsrv_forge.php b/system/database/drivers/sqlsrv/sqlsrv_forge.php
index 2a77669..ccdb369 100644
--- a/system/database/drivers/sqlsrv/sqlsrv_forge.php
+++ b/system/database/drivers/sqlsrv/sqlsrv_forge.php
@@ -1,13 +1,13 @@
-<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
- * 
+ *
  * Licensed under the Open Software License version 3.0
- * 
+ *
  * This source file is subject to the Open Software License (OSL 3.0) that is
  * bundled with this package in the files license.txt / license.rst.  It is
  * also available through the world wide web at this URL:
@@ -21,12 +21,10 @@
  * @copyright	Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/)
  * @license		http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
  * @link		http://codeigniter.com
- * @since		Version 1.0
+ * @since		Version 2.0.3
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * SQLSRV Forge Class
  *
@@ -36,112 +34,61 @@
  */
 class CI_DB_sqlsrv_forge extends CI_DB_forge {
 
-	/**
-	 * Create database
-	 *
-	 * @access	private
-	 * @param	string	the database name
-	 * @return	bool
-	 */
-	function _create_database($name)
-	{
-		return "CREATE DATABASE ".$name;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Drop database
-	 *
-	 * @access	private
-	 * @param	string	the database name
-	 * @return	bool
-	 */
-	function _drop_database($name)
-	{
-		return "DROP DATABASE ".$name;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Drop Table
-	 *
-	 * @access	private
-	 * @return	bool
-	 */
-	function _drop_table($table)
-	{
-		return "DROP TABLE ".$this->db->_escape_identifiers($table);
-	}
-
-	// --------------------------------------------------------------------
+	protected $_drop_table	= 'DROP TABLE %s';
 
 	/**
 	 * Create Table
 	 *
-	 * @access	private
 	 * @param	string	the table name
 	 * @param	array	the fields
 	 * @param	mixed	primary key(s)
 	 * @param	mixed	key(s)
-	 * @param	boolean	should 'IF NOT EXISTS' be added to the SQL
-	 * @return	bool
+	 * @param	bool	should 'IF NOT EXISTS' be added to the SQL
+	 * @return	string
 	 */
-	function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists)
+	protected function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists)
 	{
-		$sql = 'CREATE TABLE ';
+		$sql = ($if_not_exists === TRUE)
+			? "IF NOT EXISTS (SELECT * FROM sysobjects WHERE ID = object_id(N'".$table."') AND OBJECTPROPERTY(id, N'IsUserTable') = 1)\n"
+			: '';
 
-		if ($if_not_exists === TRUE)
-		{
-			$sql .= 'IF NOT EXISTS ';
-		}
+		$sql .= 'CREATE TABLE '.$this->db->escape_identifiers($table).' (';
 
-		$sql .= $this->db->_escape_identifiers($table)." (";
 		$current_field_count = 0;
-
-		foreach ($fields as $field=>$attributes)
+		foreach ($fields as $field => $attributes)
 		{
 			// Numeric field names aren't allowed in databases, so if the key is
 			// numeric, we know it was assigned by PHP and the developer manually
 			// entered the field information, so we'll simply add it to the list
 			if (is_numeric($field))
 			{
-				$sql .= "\n\t$attributes";
+				$sql .= "\n\t".$attributes;
 			}
 			else
 			{
 				$attributes = array_change_key_case($attributes, CASE_UPPER);
 
-				$sql .= "\n\t".$this->db->_protect_identifiers($field);
+				$sql .= "\n\t".$this->db->escape_identifiers($field).' '.$attributes['TYPE'];
 
-				$sql .=  ' '.$attributes['TYPE'];
-
-				if (array_key_exists('CONSTRAINT', $attributes))
+				if (stripos($attributes['TYPE'], 'INT') === FALSE && ! empty($attributes['CONSTRAINT']))
 				{
 					$sql .= '('.$attributes['CONSTRAINT'].')';
 				}
 
-				if (array_key_exists('UNSIGNED', $attributes) && $attributes['UNSIGNED'] === TRUE)
+				if ( ! empty($attributes['UNSIGNED']) && $attributes['UNSIGNED'] === TRUE)
 				{
 					$sql .= ' UNSIGNED';
 				}
 
-				if (array_key_exists('DEFAULT', $attributes))
+				if (isset($attributes['DEFAULT']))
 				{
-					$sql .= ' DEFAULT \''.$attributes['DEFAULT'].'\'';
+					$sql .= " DEFAULT '".$attributes['DEFAULT']."'";
 				}
 
-				if (array_key_exists('NULL', $attributes) && $attributes['NULL'] === TRUE)
-				{
-					$sql .= ' NULL';
-				}
-				else
-				{
-					$sql .= ' NOT NULL';
-				}
+				$sql .= ( ! empty($attributes['NULL']) && $attribues['NULL'] === TRUE)
+					? ' NULL' : ' NOT NULL';
 
-				if (array_key_exists('AUTO_INCREMENT', $attributes) && $attributes['AUTO_INCREMENT'] === TRUE)
+				if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE)
 				{
 					$sql .= ' AUTO_INCREMENT';
 				}
@@ -156,30 +103,22 @@
 
 		if (count($primary_keys) > 0)
 		{
-			$primary_keys = $this->db->_protect_identifiers($primary_keys);
-			$sql .= ",\n\tPRIMARY KEY (" . implode(', ', $primary_keys) . ")";
+			$sql .= ",\n\tPRIMARY KEY (".implode(', ', $this->db->escape_identifiers($primary_keys)).')';
 		}
 
 		if (is_array($keys) && count($keys) > 0)
 		{
 			foreach ($keys as $key)
 			{
-				if (is_array($key))
-				{
-					$key = $this->db->_protect_identifiers($key);
-				}
-				else
-				{
-					$key = array($this->db->_protect_identifiers($key));
-				}
+				$key = is_array($key)
+					? $this->db->escape_identifiers($key)
+					: array($this->escape_identifiers($key));
 
-				$sql .= ",\n\tFOREIGN KEY (" . implode(', ', $key) . ")";
+				$sql .= ",\n\tFOREIGN KEY (".implode(', ', $key).')';
 			}
 		}
 
-		$sql .= "\n)";
-
-		return $sql;
+		return $sql."\n)";
 	}
 
 	// --------------------------------------------------------------------
@@ -190,71 +129,32 @@
 	 * Generates a platform-specific query so that a table can be altered
 	 * Called by add_column(), drop_column(), and column_alter(),
 	 *
-	 * @access	private
 	 * @param	string	the ALTER type (ADD, DROP, CHANGE)
 	 * @param	string	the column name
 	 * @param	string	the table name
 	 * @param	string	the column definition
 	 * @param	string	the default value
-	 * @param	boolean	should 'NOT NULL' be added
+	 * @param	bool	should 'NOT NULL' be added
 	 * @param	string	the field after which we should add the new field
-	 * @return	object
+	 * @return	string
 	 */
-	function _alter_table($alter_type, $table, $column_name, $column_definition = '', $default_value = '', $null = '', $after_field = '')
+	protected function _alter_table($alter_type, $table, $column_name, $column_definition = '', $default_value = '', $null = '', $after_field = '')
 	{
-		$sql = 'ALTER TABLE '.$this->db->_protect_identifiers($table)." $alter_type ".$this->db->_protect_identifiers($column_name);
+		$sql = 'ALTER TABLE '.$this->db->escape_identifiers($table).' '.$alter_type.' '.$this->db->escape_identifiers($column_name);
 
 		// DROP has everything it needs now.
-		if ($alter_type == 'DROP')
+		if ($alter_type === 'DROP')
 		{
 			return $sql;
 		}
 
-		$sql .= " $column_definition";
-
-		if ($default_value != '')
-		{
-			$sql .= " DEFAULT \"$default_value\"";
-		}
-
-		if ($null === NULL)
-		{
-			$sql .= ' NULL';
-		}
-		else
-		{
-			$sql .= ' NOT NULL';
-		}
-
-		if ($after_field != '')
-		{
-			$sql .= ' AFTER ' . $this->db->_protect_identifiers($after_field);
-		}
-
-		return $sql;
-
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Rename a table
-	 *
-	 * Generates a platform-specific query so that a table can be renamed
-	 *
-	 * @access	private
-	 * @param	string	the old table name
-	 * @param	string	the new table name
-	 * @return	string
-	 */
-	function _rename_table($table_name, $new_table_name)
-	{
-		// I think this syntax will work, but can find little documentation on renaming tables in MSSQL
-		$sql = 'ALTER TABLE '.$this->db->_protect_identifiers($table_name)." RENAME TO ".$this->db->_protect_identifiers($new_table_name);
-		return $sql;
+		return $sql.' '.$column_definition
+			.($default_value != '' ? ' DEFAULT "'.$default_value.'"' : '')
+			.($null === NULL ? ' NULL' : ' NOT NULL')
+			.($after_field != '' ? ' AFTER '.$this->db->escape_identifiers($after_field) : '');
 	}
 
 }
 
-/* End of file mssql_forge.php */
-/* Location: ./system/database/drivers/mssql/mssql_forge.php */
\ No newline at end of file
+/* End of file sqlsrv_forge.php */
+/* Location: ./system/database/drivers/sqlsrv/sqlsrv_forge.php */
\ No newline at end of file
diff --git a/system/database/drivers/sqlsrv/sqlsrv_result.php b/system/database/drivers/sqlsrv/sqlsrv_result.php
index 1ee19c2..f9d5a0d 100644
--- a/system/database/drivers/sqlsrv/sqlsrv_result.php
+++ b/system/database/drivers/sqlsrv/sqlsrv_result.php
@@ -1,13 +1,13 @@
-<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
- * 
+ *
  * Licensed under the Open Software License version 3.0
- * 
+ *
  * This source file is subject to the Open Software License (OSL 3.0) that is
  * bundled with this package in the files license.txt / license.rst.  It is
  * also available through the world wide web at this URL:
@@ -21,12 +21,10 @@
  * @copyright	Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/)
  * @license		http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
  * @link		http://codeigniter.com
- * @since		Version 1.0
+ * @since		Version 2.0.3
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * SQLSRV Result Class
  *
@@ -41,10 +39,9 @@
 	/**
 	 * Number of rows in the result set
 	 *
-	 * @access	public
-	 * @return	integer
+	 * @return	int
 	 */
-	function num_rows()
+	public function num_rows()
 	{
 		return @sqlsrv_num_rows($this->result_id);
 	}
@@ -54,10 +51,9 @@
 	/**
 	 * Number of fields in the result set
 	 *
-	 * @access	public
-	 * @return	integer
+	 * @return	int
 	 */
-	function num_fields()
+	public function num_fields()
 	{
 		return @sqlsrv_num_fields($this->result_id);
 	}
@@ -69,17 +65,16 @@
 	 *
 	 * Generates an array of column names
 	 *
-	 * @access	public
 	 * @return	array
 	 */
-	function list_fields()
+	public function list_fields()
 	{
 		$field_names = array();
-		foreach(sqlsrv_field_metadata($this->result_id) as $offset => $field)
+		foreach (sqlsrv_field_metadata($this->result_id) as $offset => $field)
 		{
 			$field_names[] = $field['Name'];
 		}
-		
+
 		return $field_names;
 	}
 
@@ -90,24 +85,23 @@
 	 *
 	 * Generates an array of objects containing field meta-data
 	 *
-	 * @access	public
 	 * @return	array
 	 */
-	function field_data()
+	public function field_data()
 	{
 		$retval = array();
-		foreach(sqlsrv_field_metadata($this->result_id) as $offset => $field)
+		foreach (sqlsrv_field_metadata($this->result_id) as $offset => $field)
 		{
-			$F 				= new stdClass();
-			$F->name 		= $field['Name'];
-			$F->type 		= $field['Type'];
+			$F 		= new stdClass();
+			$F->name 	= $field['Name'];
+			$F->type 	= $field['Type'];
 			$F->max_length	= $field['Size'];
 			$F->primary_key = 0;
-			$F->default		= '';
-			
+			$F->default	= '';
+
 			$retval[] = $F;
 		}
-		
+
 		return $retval;
 	}
 
@@ -116,9 +110,9 @@
 	/**
 	 * Free the result
 	 *
-	 * @return	null
+	 * @return	void
 	 */
-	function free_result()
+	public function free_result()
 	{
 		if (is_resource($this->result_id))
 		{
@@ -130,31 +124,13 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 * Data Seek
-	 *
-	 * Moves the internal pointer to the desired offset.  We call
-	 * this internally before fetching results to make sure the
-	 * result set starts at zero
-	 *
-	 * @access	private
-	 * @return	array
-	 */
-	function _data_seek($n = 0)
-	{
-		// Not implemented
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
 	 * Result - associative array
 	 *
 	 * Returns the result set as an array
 	 *
-	 * @access	private
 	 * @return	array
 	 */
-	function _fetch_assoc()
+	protected function _fetch_assoc()
 	{
 		return sqlsrv_fetch_array($this->result_id, SQLSRV_FETCH_ASSOC);
 	}
@@ -166,16 +142,14 @@
 	 *
 	 * Returns the result set as an object
 	 *
-	 * @access	private
 	 * @return	object
 	 */
-	function _fetch_object()
+	protected function _fetch_object()
 	{
 		return sqlsrv_fetch_object($this->result_id);
 	}
 
 }
 
-
-/* End of file mssql_result.php */
-/* Location: ./system/database/drivers/mssql/mssql_result.php */
\ No newline at end of file
+/* End of file sqlsrv_result.php */
+/* Location: ./system/database/drivers/sqlsrv/sqlsrv_result.php */
\ No newline at end of file
diff --git a/system/database/drivers/sqlsrv/sqlsrv_utility.php b/system/database/drivers/sqlsrv/sqlsrv_utility.php
index e96df96..d518cc1 100644
--- a/system/database/drivers/sqlsrv/sqlsrv_utility.php
+++ b/system/database/drivers/sqlsrv/sqlsrv_utility.php
@@ -1,13 +1,13 @@
-<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
- * 
+ *
  * Licensed under the Open Software License version 3.0
- * 
+ *
  * This source file is subject to the Open Software License (OSL 3.0) that is
  * bundled with this package in the files license.txt / license.rst.  It is
  * also available through the world wide web at this URL:
@@ -21,12 +21,10 @@
  * @copyright	Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/)
  * @license		http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
  * @link		http://codeigniter.com
- * @since		Version 1.0
+ * @since		Version 2.0.3
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * SQLSRV Utility Class
  *
@@ -36,59 +34,16 @@
  */
 class CI_DB_sqlsrv_utility extends CI_DB_utility {
 
+	protected $_list_databases	= 'EXEC sp_helpdb'; // Can also be: EXEC sp_databases
+	protected $_optimize_table	= 'ALTER INDEX all ON %s REORGANIZE';
+
 	/**
-	 * List databases
+	 * SQLSRV Export
 	 *
-	 * @access	private
+	 * @param	array	Preferences
 	 * @return	bool
 	 */
-	function _list_databases()
-	{
-		return "EXEC sp_helpdb"; // Can also be: EXEC sp_databases
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Optimize table query
-	 *
-	 * Generates a platform-specific query so that a table can be optimized
-	 *
-	 * @access	private
-	 * @param	string	the table name
-	 * @return	object
-	 */
-	function _optimize_table($table)
-	{
-		return FALSE; // Is this supported in MS SQL?
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * Repair table query
-	 *
-	 * Generates a platform-specific query so that a table can be repaired
-	 *
-	 * @access	private
-	 * @param	string	the table name
-	 * @return	object
-	 */
-	function _repair_table($table)
-	{
-		return FALSE; // Is this supported in MS SQL?
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
-	 * MSSQL Export
-	 *
-	 * @access	private
-	 * @param	array	Preferences
-	 * @return	mixed
-	 */
-	function _backup($params = array())
+	protected function _backup($params = array())
 	{
 		// Currently unsupported
 		return $this->db->display_error('db_unsuported_feature');
@@ -96,5 +51,5 @@
 
 }
 
-/* End of file mssql_utility.php */
-/* Location: ./system/database/drivers/mssql/mssql_utility.php */
\ No newline at end of file
+/* End of file sqlsrv_utility.php */
+/* Location: ./system/database/drivers/sqlsrv/sqlsrv_utility.php */
\ No newline at end of file
diff --git a/system/helpers/array_helper.php b/system/helpers/array_helper.php
index c46c4d1..6a7c8e3 100644
--- a/system/helpers/array_helper.php
+++ b/system/helpers/array_helper.php
@@ -1,13 +1,13 @@
-<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
- * 
+ *
  * Licensed under the Open Software License version 3.0
- * 
+ *
  * This source file is subject to the Open Software License (OSL 3.0) that is
  * bundled with this package in the files license.txt / license.rst.  It is
  * also available through the world wide web at this URL:
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * CodeIgniter Array Helpers
  *
@@ -39,88 +37,65 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Element
- *
- * Lets you determine whether an array index is set and whether it has a value.
- * If the element is empty it returns FALSE (or whatever you specify as the default value.)
- *
- * @access	public
- * @param	string
- * @param	array
- * @param	mixed
- * @return	mixed	depends on what the array contains
- */
 if ( ! function_exists('element'))
 {
+	/**
+	 * Element
+	 *
+	 * Lets you determine whether an array index is set and whether it has a value.
+	 * If the element is empty it returns FALSE (or whatever you specify as the default value.)
+	 *
+	 * @param	string
+	 * @param	array
+	 * @param	mixed
+	 * @return	mixed	depends on what the array contains
+	 */
 	function element($item, $array, $default = FALSE)
 	{
-		if ( ! isset($array[$item]) OR $array[$item] == "")
-		{
-			return $default;
-		}
-
-		return $array[$item];
+		return empty($array[$item]) ? $default : $array[$item];
 	}
 }
 
 // ------------------------------------------------------------------------
 
-/**
- * Random Element - Takes an array as input and returns a random element
- *
- * @access	public
- * @param	array
- * @return	mixed	depends on what the array contains
- */
 if ( ! function_exists('random_element'))
 {
+	/**
+	 * Random Element - Takes an array as input and returns a random element
+	 *
+	 * @param	array
+	 * @return	mixed	depends on what the array contains
+	 */
 	function random_element($array)
 	{
-		if ( ! is_array($array))
-		{
-			return $array;
-		}
-
-		return $array[array_rand($array)];
+		return is_array($array) ? $array[array_rand($array)] : $array;
 	}
 }
 
 // --------------------------------------------------------------------
 
-/**
- * Elements
- *
- * Returns only the array items specified.  Will return a default value if
- * it is not set.
- *
- * @access	public
- * @param	array
- * @param	array
- * @param	mixed
- * @return	mixed	depends on what the array contains
- */
 if ( ! function_exists('elements'))
 {
+	/**
+	 * Elements
+	 *
+	 * Returns only the array items specified. Will return a default value if
+	 * it is not set.
+	 *
+	 * @param	array
+	 * @param	array
+	 * @param	mixed
+	 * @return	mixed	depends on what the array contains
+	 */
 	function elements($items, $array, $default = FALSE)
 	{
 		$return = array();
-		
-		if ( ! is_array($items))
-		{
-			$items = array($items);
-		}
-		
+
+		is_array($items) OR $items = array($items);
+
 		foreach ($items as $item)
 		{
-			if (isset($array[$item]))
-			{
-				$return[$item] = $array[$item];
-			}
-			else
-			{
-				$return[$item] = $default;
-			}
+			$return[$item] = isset($array[$item]) ? $array[$item] : $default;
 		}
 
 		return $return;
diff --git a/system/helpers/captcha_helper.php b/system/helpers/captcha_helper.php
index 668b034..4676b2a 100644
--- a/system/helpers/captcha_helper.php
+++ b/system/helpers/captcha_helper.php
@@ -1,13 +1,13 @@
-<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
- * 
+ *
  * Licensed under the Open Software License version 3.0
- * 
+ *
  * This source file is subject to the Open Software License (OSL 3.0) that is
  * bundled with this package in the files license.txt / license.rst.  It is
  * also available through the world wide web at this URL:
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * CodeIgniter CAPTCHA Helper
  *
@@ -39,53 +37,36 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Create CAPTCHA
- *
- * @access	public
- * @param	array	array of data for the CAPTCHA
- * @param	string	path to create the image in
- * @param	string	URL to the CAPTCHA image folder
- * @param	string	server path to font
- * @return	string
- */
 if ( ! function_exists('create_captcha'))
 {
+	/**
+	 * Create CAPTCHA
+	 *
+	 * @param	array	array of data for the CAPTCHA
+	 * @param	string	path to create the image in
+	 * @param	string	URL to the CAPTCHA image folder
+	 * @param	string	server path to font
+	 * @return	string
+	 */
 	function create_captcha($data = '', $img_path = '', $img_url = '', $font_path = '')
 	{
 		$defaults = array('word' => '', 'img_path' => '', 'img_url' => '', 'img_width' => '150', 'img_height' => '30', 'font_path' => '', 'expiration' => 7200);
 
 		foreach ($defaults as $key => $val)
 		{
-			if ( ! is_array($data))
+			if ( ! is_array($data) && empty($$key))
 			{
-				if ( ! isset($$key) OR $$key == '')
-				{
-					$$key = $val;
-				}
+				$$key = $val;
 			}
 			else
 			{
-				$$key = ( ! isset($data[$key])) ? $val : $data[$key];
+				$$key = isset($data[$key]) ? $data[$key] : $val;
 			}
 		}
 
-		if ($img_path == '' OR $img_url == '')
-		{
-			return FALSE;
-		}
-
-		if ( ! @is_dir($img_path))
-		{
-			return FALSE;
-		}
-
-		if ( ! is_writable($img_path))
-		{
-			return FALSE;
-		}
-
-		if ( ! extension_loaded('gd'))
+		if ($img_path === '' OR $img_url === ''
+			OR ! @is_dir($img_path) OR ! is_writeable($img_path)
+			OR ! extension_loaded('gd'))
 		{
 			return FALSE;
 		}
@@ -94,21 +75,15 @@
 		// Remove old images
 		// -----------------------------------
 
-		list($usec, $sec) = explode(" ", microtime());
-		$now = ((float)$usec + (float)$sec);
+		$now = microtime(TRUE);
 
 		$current_dir = @opendir($img_path);
-
 		while ($filename = @readdir($current_dir))
 		{
-			if ($filename != "." and $filename != ".." and $filename != "index.html")
+			if ($filename !== '.' && $filename !== '..' && $filename !== 'index.html'
+				&& (str_replace('.jpg', '', $filename) + $expiration) < $now)
 			{
-				$name = str_replace(".jpg", "", $filename);
-
-				if (($name + $expiration) < $now)
-				{
-					@unlink($img_path.$filename);
-				}
+				@unlink($img_path.$filename);
 			}
 		}
 
@@ -118,141 +93,114 @@
 		// Do we have a "word" yet?
 		// -----------------------------------
 
-	   if ($word == '')
-	   {
+		if ($word === '')
+		{
 			$pool = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
-
-			$str = '';
-			for ($i = 0; $i < 8; $i++)
+			$word = '';
+			for ($i = 0, $mt_rand_max = strlen($pool) - 1; $i < 8; $i++)
 			{
-				$str .= substr($pool, mt_rand(0, strlen($pool) -1), 1);
+				$word .= $pool[mt_rand(0, $mt_rand_max)];
 			}
-
-			$word = $str;
-	   }
+		}
 
 		// -----------------------------------
 		// 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);
+		$y_axis = ($angle >= 0) ? rand($img_height, $img_width) : rand(6, $img_height);
 
-		// -----------------------------------
 		// Create image
-		// -----------------------------------
-
 		// PHP.net recommends imagecreatetruecolor(), but it isn't always available
-		if (function_exists('imagecreatetruecolor'))
-		{
-			$im = imagecreatetruecolor($img_width, $img_height);
-		}
-		else
-		{
-			$im = imagecreate($img_width, $img_height);
-		}
+		$im = function_exists('imagecreatetruecolor')
+			? imagecreatetruecolor($img_width, $img_height)
+			: imagecreate($img_width, $img_height);
 
 		// -----------------------------------
 		//  Assign colors
 		// -----------------------------------
-
-		$bg_color		= imagecolorallocate ($im, 255, 255, 255);
-		$border_color	= imagecolorallocate ($im, 153, 102, 102);
-		$text_color		= imagecolorallocate ($im, 204, 153, 153);
-		$grid_color		= imagecolorallocate($im, 255, 182, 182);
+		$bg_color	= imagecolorallocate($im, 255, 255, 255);
+		$border_color	= imagecolorallocate($im, 153, 102, 102);
+		$text_color	= imagecolorallocate($im, 204, 153, 153);
+		$grid_color	= imagecolorallocate($im, 255, 182, 182);
 		$shadow_color	= imagecolorallocate($im, 255, 240, 240);
 
-		// -----------------------------------
 		//  Create the rectangle
-		// -----------------------------------
-
 		ImageFilledRectangle($im, 0, 0, $img_width, $img_height, $bg_color);
 
 		// -----------------------------------
 		//  Create the spiral pattern
 		// -----------------------------------
-
 		$theta		= 1;
 		$thetac		= 7;
 		$radius		= 16;
 		$circles	= 20;
 		$points		= 32;
 
-		for ($i = 0; $i < ($circles * $points) - 1; $i++)
+		for ($i = 0, $cp = ($circles * $points) - 1; $i < $cp; $i++)
 		{
-			$theta = $theta + $thetac;
-			$rad = $radius * ($i / $points );
+			$theta += $thetac;
+			$rad = $radius * ($i / $points);
 			$x = ($rad * cos($theta)) + $x_axis;
 			$y = ($rad * sin($theta)) + $y_axis;
-			$theta = $theta + $thetac;
+			$theta += $thetac;
 			$rad1 = $radius * (($i + 1) / $points);
 			$x1 = ($rad1 * cos($theta)) + $x_axis;
-			$y1 = ($rad1 * sin($theta )) + $y_axis;
+			$y1 = ($rad1 * sin($theta)) + $y_axis;
 			imageline($im, $x, $y, $x1, $y1, $grid_color);
-			$theta = $theta - $thetac;
+			$theta -= $thetac;
 		}
 
 		// -----------------------------------
 		//  Write the text
 		// -----------------------------------
 
-		$use_font = ($font_path != '' AND file_exists($font_path) AND function_exists('imagettftext')) ? TRUE : FALSE;
-
-		if ($use_font == FALSE)
+		$use_font = ($font_path !== '' && file_exists($font_path) && function_exists('imagettftext'));
+		if ($use_font === FALSE)
 		{
 			$font_size = 5;
-			$x = rand(0, $img_width/($length/3));
+			$x = rand(0, $img_width / ($length / 3));
 			$y = 0;
 		}
 		else
 		{
-			$font_size	= 16;
-			$x = rand(0, $img_width/($length/1.5));
-			$y = $font_size+2;
+			$font_size = 16;
+			$x = rand(0, $img_width / ($length / 1.5));
+			$y = $font_size + 2;
 		}
 
-		for ($i = 0; $i < strlen($word); $i++)
+		for ($i = 0; $i < $length; $i++)
 		{
-			if ($use_font == FALSE)
+			if ($use_font === FALSE)
 			{
-				$y = rand(0 , $img_height/2);
-				imagestring($im, $font_size, $x, $y, substr($word, $i, 1), $text_color);
-				$x += ($font_size*2);
+				$y = rand(0 , $img_height / 2);
+				imagestring($im, $font_size, $x, $y, $word[$i], $text_color);
+				$x += ($font_size * 2);
 			}
 			else
 			{
-				$y = rand($img_height/2, $img_height-3);
-				imagettftext($im, $font_size, $angle, $x, $y, $text_color, $font_path, substr($word, $i, 1));
+				$y = rand($img_height / 2, $img_height - 3);
+				imagettftext($im, $font_size, $angle, $x, $y, $text_color, $font_path, $word[$i]);
 				$x += $font_size;
 			}
 		}
 
 
-		// -----------------------------------
-		//  Create the border
-		// -----------------------------------
-
-		imagerectangle($im, 0, 0, $img_width-1, $img_height-1, $border_color);
+		// Create the border
+		imagerectangle($im, 0, 0, $img_width - 1, $img_height - 1, $border_color);
 
 		// -----------------------------------
 		//  Generate the image
 		// -----------------------------------
-
 		$img_name = $now.'.jpg';
-
 		ImageJPEG($im, $img_path.$img_name);
-
-		$img = "<img src=\"$img_url$img_name\" width=\"$img_width\" height=\"$img_height\" style=\"border:0;\" alt=\" \" />";
-
+		$img = '<img src="'.$img_url.$img_name.'" style="width: '.$img_width.'; height: '.$img_height .'; border: 0;" alt=" " />';
 		ImageDestroy($im);
 
 		return array('word' => $word, 'time' => $now, 'image' => $img);
 	}
 }
 
-// ------------------------------------------------------------------------
-
 /* End of file captcha_helper.php */
 /* Location: ./system/helpers/captcha_helper.php */
\ No newline at end of file
diff --git a/system/helpers/cookie_helper.php b/system/helpers/cookie_helper.php
index 7b439c4..f396c76 100644
--- a/system/helpers/cookie_helper.php
+++ b/system/helpers/cookie_helper.php
@@ -1,13 +1,13 @@
-<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
- * 
+ *
  * Licensed under the Open Software License version 3.0
- * 
+ *
  * This source file is subject to the Open Software License (OSL 3.0) that is
  * bundled with this package in the files license.txt / license.rst.  It is
  * also available through the world wide web at this URL:
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * CodeIgniter Cookie Helpers
  *
@@ -39,77 +37,69 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Set cookie
- *
- * Accepts six parameter, or you can submit an associative
- * array in the first parameter containing all the values.
- *
- * @access	public
- * @param	mixed
- * @param	string	the value of the cookie
- * @param	string	the number of seconds until expiration
- * @param	string	the cookie domain.  Usually:  .yourdomain.com
- * @param	string	the cookie path
- * @param	string	the cookie prefix
- * @return	void
- */
 if ( ! function_exists('set_cookie'))
 {
-	function set_cookie($name = '', $value = '', $expire = '', $domain = '', $path = '/', $prefix = '', $secure = FALSE)
+	/**
+	 * Set cookie
+	 *
+	 * Accepts seven parameters, or you can submit an associative
+	 * array in the first parameter containing all the values.
+	 *
+	 * @param	mixed
+	 * @param	string	the value of the cookie
+	 * @param	string	the number of seconds until expiration
+	 * @param	string	the cookie domain.  Usually:  .yourdomain.com
+	 * @param	string	the cookie path
+	 * @param	string	the cookie prefix
+	 * @param	bool	true makes the cookie secure
+	 * @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)
 	{
 		// Set the config file options
 		$CI =& get_instance();
-		$CI->input->set_cookie($name, $value, $expire, $domain, $path, $prefix, $secure);
+		$CI->input->set_cookie($name, $value, $expire, $domain, $path, $prefix, $secure, $httponly);
 	}
 }
 
 // --------------------------------------------------------------------
 
-/**
- * Fetch an item from the COOKIE array
- *
- * @access	public
- * @param	string
- * @param	bool
- * @return	mixed
- */
 if ( ! function_exists('get_cookie'))
 {
+	/**
+	 * Fetch an item from the COOKIE array
+	 *
+	 * @param	string
+	 * @param	bool
+	 * @return	mixed
+	 */
 	function get_cookie($index = '', $xss_clean = FALSE)
 	{
 		$CI =& get_instance();
-
-		$prefix = '';
-
-		if ( ! isset($_COOKIE[$index]) && config_item('cookie_prefix') != '')
-		{
-			$prefix = config_item('cookie_prefix');
-		}
-
+		$prefix = isset($_COOKIE[$index]) ? '' : config_item('cookie_prefix');
 		return $CI->input->cookie($prefix.$index, $xss_clean);
 	}
 }
 
 // --------------------------------------------------------------------
 
-/**
- * Delete a COOKIE
- *
- * @param	mixed
- * @param	string	the cookie domain.  Usually:  .yourdomain.com
- * @param	string	the cookie path
- * @param	string	the cookie prefix
- * @return	void
- */
 if ( ! function_exists('delete_cookie'))
 {
+	/**
+	 * Delete a COOKIE
+	 *
+	 * @param	mixed
+	 * @param	string	the cookie domain. Usually: .yourdomain.com
+	 * @param	string	the cookie path
+	 * @param	string	the cookie prefix
+	 * @return	void
+	 */
 	function delete_cookie($name = '', $domain = '', $path = '/', $prefix = '')
 	{
 		set_cookie($name, '', '', $domain, $path, $prefix);
 	}
 }
 
-
 /* End of file cookie_helper.php */
 /* Location: ./system/helpers/cookie_helper.php */
\ No newline at end of file
diff --git a/system/helpers/date_helper.php b/system/helpers/date_helper.php
index 9e58d86..c601dc9 100644
--- a/system/helpers/date_helper.php
+++ b/system/helpers/date_helper.php
@@ -1,8 +1,8 @@
-<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * CodeIgniter Date Helpers
  *
@@ -39,21 +37,20 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Get "now" time
- *
- * Returns time() or its GMT equivalent based on the config file preference
- *
- * @access	public
- * @return	integer
- */
 if ( ! function_exists('now'))
 {
+	/**
+	 * Get "now" time
+	 *
+	 * Returns time() or its GMT equivalent based on the config file preference
+	 *
+	 * @return	int
+	 */
 	function now()
 	{
 		$CI =& get_instance();
 
-		if (strtolower($CI->config->item('time_reference')) == 'gmt')
+		if (strtolower($CI->config->item('time_reference')) === 'gmt')
 		{
 			$now = time();
 			$system_time = mktime(gmdate("H", $now), gmdate("i", $now), gmdate("s", $now), gmdate("m", $now), gmdate("d", $now), gmdate("Y", $now));
@@ -73,38 +70,37 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Convert MySQL Style Datecodes
- *
- * This function is identical to PHPs date() function,
- * except that it allows date codes to be formatted using
- * the MySQL style, where each code letter is preceded
- * with a percent sign:  %Y %m %d etc...
- *
- * The benefit of doing dates this way is that you don't
- * have to worry about escaping your text letters that
- * match the date codes.
- *
- * @access	public
- * @param	string
- * @param	integer
- * @return	integer
- */
 if ( ! function_exists('mdate'))
 {
+	/**
+	 * Convert MySQL Style Datecodes
+	 *
+	 * This function is identical to PHPs date() function,
+	 * except that it allows date codes to be formatted using
+	 * the MySQL style, where each code letter is preceded
+	 * with a percent sign:  %Y %m %d etc...
+	 *
+	 * The benefit of doing dates this way is that you don't
+	 * have to worry about escaping your text letters that
+	 * match the date codes.
+	 *
+	 * @param	string
+	 * @param	int
+	 * @return	int
+	 */
 	function mdate($datestr = '', $time = '')
 	{
-		if ($datestr == '')
+		if ($datestr === '')
 		{
 			return '';
 		}
 
-		$time = ($time == '') ? now() : $time;
+		$time = ($time === '') ? now() : $time;
 
 		$datestr = str_replace(
 			'%\\',
 			'',
-			preg_replace("/([a-z]+?){1}/i", "\\\\\\1", $datestr)
+			preg_replace('/([a-z]+?){1}/i', '\\\\\\1', $datestr)
 		);
 
 		return date($datestr, $time);
@@ -113,30 +109,30 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Standard Date
- *
- * Returns a date formatted according to the submitted standard.
- *
- * @access	public
- * @param	string	the chosen format
- * @param	integer	Unix timestamp
- * @return	string
- */
 if ( ! function_exists('standard_date'))
 {
+	/**
+	 * Standard Date
+	 *
+	 * Returns a date formatted according to the submitted standard.
+	 *
+	 * @param	string	the chosen format
+	 * @param	int	Unix timestamp
+	 * @return	string
+	 */
 	function standard_date($fmt = 'DATE_RFC822', $time = '')
 	{
 		$formats = array(
-						'DATE_ATOM'		=>	'%Y-%m-%dT%H:%i:%s%Q',
+						'DATE_ATOM'		=>	'%Y-%m-%dT%H:%i:%s%O',
 						'DATE_COOKIE'	=>	'%l, %d-%M-%y %H:%i:%s UTC',
-						'DATE_ISO8601'	=>	'%Y-%m-%dT%H:%i:%s%Q',
+						'DATE_ISO8601'	=>	'%Y-%m-%dT%H:%i:%s%O',
 						'DATE_RFC822'	=>	'%D, %d %M %y %H:%i:%s %O',
 						'DATE_RFC850'	=>	'%l, %d-%M-%y %H:%i:%s UTC',
 						'DATE_RFC1036'	=>	'%D, %d %M %y %H:%i:%s %O',
 						'DATE_RFC1123'	=>	'%D, %d %M %Y %H:%i:%s %O',
+						'DATE_RFC2822'	=>	'%D, %d %M %Y %H:%i:%s %O',
 						'DATE_RSS'		=>	'%D, %d %M %Y %H:%i:%s %O',
-						'DATE_W3C'		=>	'%Y-%m-%dT%H:%i:%s%Q'
+						'DATE_W3C'		=>	'%Y-%m-%dT%H:%i:%s%O'
 						);
 
 		if ( ! isset($formats[$fmt]))
@@ -150,20 +146,20 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Timespan
- *
- * Returns a span of seconds in this format:
- *	10 days 14 hours 36 minutes 47 seconds
- *
- * @access	public
- * @param	integer	a number of seconds
- * @param	integer	Unix timestamp
- * @return	integer
- */
 if ( ! function_exists('timespan'))
 {
-	function timespan($seconds = 1, $time = '')
+	/**
+	 * Timespan
+	 *
+	 * Returns a span of seconds in this format:
+	 *	10 days 14 hours 36 minutes 47 seconds
+	 *
+	 * @param	int	a number of seconds
+	 * @param	int	Unix timestamp
+	 * @param	int	a number of display units
+	 * @return	string
+	 */
+	function timespan($seconds = 1, $time = '', $units = 7)
 	{
 		$CI =& get_instance();
 		$CI->lang->load('date');
@@ -178,24 +174,29 @@
 			$time = time();
 		}
 
+		if ( ! is_numeric($units))
+		{
+			$units = 7;
+		}
+
 		$seconds = ($time <= $seconds) ? 1 : $time - $seconds;
 
-		$str = '';
+		$str = array();
 		$years = floor($seconds / 31557600);
 
 		if ($years > 0)
 		{
-			$str .= $years.' '.$CI->lang->line((($years	> 1) ? 'date_years' : 'date_year')).', ';
+			$str[] = $years.' '.$CI->lang->line((($years	> 1) ? 'date_years' : 'date_year'));
 		}
 
 		$seconds -= $years * 31557600;
 		$months = floor($seconds / 2629743);
 
-		if ($years > 0 OR $months > 0)
+		if (count($str) < $units && ($years > 0 OR $months > 0))
 		{
 			if ($months > 0)
 			{
-				$str .= $months.' '.$CI->lang->line((($months	> 1) ? 'date_months' : 'date_month')).', ';
+				$str[] = $months.' '.$CI->lang->line((($months	> 1) ? 'date_months' : 'date_month'));
 			}
 
 			$seconds -= $months * 2629743;
@@ -203,11 +204,11 @@
 
 		$weeks = floor($seconds / 604800);
 
-		if ($years > 0 OR $months > 0 OR $weeks > 0)
+		if (count($str) < $units && ($years > 0 OR $months > 0 OR $weeks > 0))
 		{
 			if ($weeks > 0)
 			{
-				$str .= $weeks.' '.$CI->lang->line((($weeks	> 1) ? 'date_weeks' : 'date_week')).', ';
+				$str[] = $weeks.' '.$CI->lang->line((($weeks	> 1) ? 'date_weeks' : 'date_week'));
 			}
 
 			$seconds -= $weeks * 604800;
@@ -215,11 +216,11 @@
 
 		$days = floor($seconds / 86400);
 
-		if ($months > 0 OR $weeks > 0 OR $days > 0)
+		if (count($str) < $units && ($months > 0 OR $weeks > 0 OR $days > 0))
 		{
 			if ($days > 0)
 			{
-				$str .= $days.' '.$CI->lang->line((($days	> 1) ? 'date_days' : 'date_day')).', ';
+				$str[] = $days.' '.$CI->lang->line((($days	> 1) ? 'date_days' : 'date_day'));
 			}
 
 			$seconds -= $days * 86400;
@@ -227,11 +228,11 @@
 
 		$hours = floor($seconds / 3600);
 
-		if ($days > 0 OR $hours > 0)
+		if (count($str) < $units && ($days > 0 OR $hours > 0))
 		{
 			if ($hours > 0)
 			{
-				$str .= $hours.' '.$CI->lang->line((($hours	> 1) ? 'date_hours' : 'date_hour')).', ';
+				$str[] = $hours.' '.$CI->lang->line((($hours	> 1) ? 'date_hours' : 'date_hour'));
 			}
 
 			$seconds -= $hours * 3600;
@@ -239,40 +240,39 @@
 
 		$minutes = floor($seconds / 60);
 
-		if ($days > 0 OR $hours > 0 OR $minutes > 0)
+		if (count($str) < $units && ($days > 0 OR $hours > 0 OR $minutes > 0))
 		{
 			if ($minutes > 0)
 			{
-				$str .= $minutes.' '.$CI->lang->line((($minutes	> 1) ? 'date_minutes' : 'date_minute')).', ';
+				$str[] = $minutes.' '.$CI->lang->line((($minutes	> 1) ? 'date_minutes' : 'date_minute'));
 			}
 
 			$seconds -= $minutes * 60;
 		}
 
-		if ($str == '')
+		if (count($str) === 0)
 		{
-			$str .= $seconds.' '.$CI->lang->line((($seconds	> 1) ? 'date_seconds' : 'date_second')).', ';
+			$str[] = $seconds.' '.$CI->lang->line((($seconds	> 1) ? 'date_seconds' : 'date_second'));
 		}
 
-		return substr(trim($str), 0, -1);
+		return implode(', ', $str);
 	}
 }
 
 // ------------------------------------------------------------------------
 
-/**
- * Number of days in a month
- *
- * Takes a month/year as input and returns the number of days
- * for the given month/year. Takes leap years into consideration.
- *
- * @access	public
- * @param	integer a numeric month
- * @param	integer	a numeric year
- * @return	integer
- */
 if ( ! function_exists('days_in_month'))
 {
+	/**
+	 * Number of days in a month
+	 *
+	 * Takes a month/year as input and returns the number of days
+	 * for the given month/year. Takes leap years into consideration.
+	 *
+	 * @param	int	a numeric month
+	 * @param	int	a numeric year
+	 * @return	int
+	 */
 	function days_in_month($month = 0, $year = '')
 	{
 		if ($month < 1 OR $month > 12)
@@ -280,14 +280,14 @@
 			return 0;
 		}
 
-		if ( ! is_numeric($year) OR strlen($year) != 4)
+		if ( ! is_numeric($year) OR strlen($year) !== 4)
 		{
 			$year = date('Y');
 		}
 
 		if ($month == 2)
 		{
-			if ($year % 400 == 0 OR ($year % 4 == 0 AND $year % 100 != 0))
+			if ($year % 400 === 0 OR ($year % 4 === 0 && $year % 100 !== 0))
 			{
 				return 29;
 			}
@@ -300,60 +300,58 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Converts a local Unix timestamp to GMT
- *
- * @access	public
- * @param	integer Unix timestamp
- * @return	integer
- */
 if ( ! function_exists('local_to_gmt'))
 {
+	/**
+	 * Converts a local Unix timestamp to GMT
+	 *
+	 * @param	int	Unix timestamp
+	 * @return	int
+	 */
 	function local_to_gmt($time = '')
 	{
-		if ($time == '')
+		if ($time === '')
 		{
 			$time = time();
 		}
 
 		return mktime(
-			gmdate("H", $time),
-			gmdate("i", $time),
-			gmdate("s", $time),
-			gmdate("m", $time),
-			gmdate("d", $time),
-			gmdate("Y", $time)
+			gmdate('H', $time),
+			gmdate('i', $time),
+			gmdate('s', $time),
+			gmdate('m', $time),
+			gmdate('d', $time),
+			gmdate('Y', $time)
 		);
 	}
 }
 
 // ------------------------------------------------------------------------
 
-/**
- * Converts GMT time to a localized value
- *
- * Takes a Unix timestamp (in GMT) as input, and returns
- * at the local value based on the timezone and DST setting
- * submitted
- *
- * @access	public
- * @param	integer Unix timestamp
- * @param	string	timezone
- * @param	bool	whether DST is active
- * @return	integer
- */
 if ( ! function_exists('gmt_to_local'))
 {
+	/**
+	 * Converts GMT time to a localized value
+	 *
+	 * Takes a Unix timestamp (in GMT) as input, and returns
+	 * at the local value based on the timezone and DST setting
+	 * submitted
+	 *
+	 * @param	int	Unix timestamp
+	 * @param	string	timezone
+	 * @param	bool	whether DST is active
+	 * @return	int
+	 */
 	function gmt_to_local($time = '', $timezone = 'UTC', $dst = FALSE)
 	{
-		if ($time == '')
+		if ($time === '')
 		{
 			return now();
 		}
 
 		$time += timezones($timezone) * 3600;
 
-		if ($dst == TRUE)
+		if ($dst === TRUE)
 		{
 			$time += 3600;
 		}
@@ -364,15 +362,14 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Converts a MySQL Timestamp to Unix
- *
- * @access	public
- * @param	integer Unix timestamp
- * @return	integer
- */
 if ( ! function_exists('mysql_to_unix'))
 {
+	/**
+	 * Converts a MySQL Timestamp to Unix
+	 *
+	 * @param	int	Unix timestamp
+	 * @return	int
+	 */
 	function mysql_to_unix($time = '')
 	{
 		// We'll remove certain characters for backward compatibility
@@ -397,24 +394,23 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Unix to "Human"
- *
- * Formats Unix timestamp to the following prototype: 2006-08-21 11:35 PM
- *
- * @access	public
- * @param	integer Unix timestamp
- * @param	bool	whether to show seconds
- * @param	string	format: us or euro
- * @return	string
- */
 if ( ! function_exists('unix_to_human'))
 {
+	/**
+	 * Unix to "Human"
+	 *
+	 * Formats Unix timestamp to the following prototype: 2006-08-21 11:35 PM
+	 *
+	 * @param	int	Unix timestamp
+	 * @param	bool	whether to show seconds
+	 * @param	string	format: us or euro
+	 * @return	string
+	 */
 	function unix_to_human($time = '', $seconds = FALSE, $fmt = 'us')
 	{
 		$r  = date('Y', $time).'-'.date('m', $time).'-'.date('d', $time).' ';
 
-		if ($fmt == 'us')
+		if ($fmt === 'us')
 		{
 			$r .= date('h', $time).':'.date('i', $time);
 		}
@@ -428,7 +424,7 @@
 			$r .= ':'.date('s', $time);
 		}
 
-		if ($fmt == 'us')
+		if ($fmt === 'us')
 		{
 			$r .= ' '.date('A', $time);
 		}
@@ -439,26 +435,24 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Convert "human" date to GMT
- *
- * Reverses the above process
- *
- * @access	public
- * @param	string	format: us or euro
- * @return	integer
- */
 if ( ! function_exists('human_to_unix'))
 {
+	/**
+	 * Convert "human" date to GMT
+	 *
+	 * Reverses the above process
+	 *
+	 * @param	string	format: us or euro
+	 * @return	int
+	 */
 	function human_to_unix($datestr = '')
 	{
-		if ($datestr == '')
+		if ($datestr === '')
 		{
 			return FALSE;
 		}
 
-		$datestr = trim($datestr);
-		$datestr = preg_replace("/\040+/", ' ', $datestr);
+		$datestr = preg_replace('/\040+/', ' ', trim($datestr));
 
 		if ( ! preg_match('/^[0-9]{2,4}\-[0-9]{1,2}\-[0-9]{1,2}\s[0-9]{1,2}:[0-9]{1,2}(?::[0-9]{1,2})?(?:\s[AP]M)?$/i', $datestr))
 		{
@@ -467,20 +461,20 @@
 
 		$split = explode(' ', $datestr);
 
-		$ex = explode("-", $split['0']);
+		$ex = explode('-', $split['0']);
 
-		$year  = (strlen($ex['0']) == 2) ? '20'.$ex['0'] : $ex['0'];
-		$month = (strlen($ex['1']) == 1) ? '0'.$ex['1']  : $ex['1'];
-		$day   = (strlen($ex['2']) == 1) ? '0'.$ex['2']  : $ex['2'];
+		$year  = (strlen($ex[0]) === 2) ? '20'.$ex[0] : $ex[0];
+		$month = (strlen($ex[1]) === 1) ? '0'.$ex[1]  : $ex[1];
+		$day   = (strlen($ex[2]) === 1) ? '0'.$ex[2]  : $ex[2];
 
-		$ex = explode(":", $split['1']);
+		$ex = explode(':', $split['1']);
 
-		$hour = (strlen($ex['0']) == 1) ? '0'.$ex['0'] : $ex['0'];
-		$min  = (strlen($ex['1']) == 1) ? '0'.$ex['1'] : $ex['1'];
+		$hour = (strlen($ex[0]) === 1) ? '0'.$ex[0] : $ex[0];
+		$min  = (strlen($ex[1]) === 1) ? '0'.$ex[1] : $ex[1];
 
-		if (isset($ex['2']) && preg_match('/[0-9]{1,2}/', $ex['2']))
+		if (isset($ex[2]) && preg_match('/[0-9]{1,2}/', $ex[2]))
 		{
-			$sec  = (strlen($ex['2']) == 1) ? '0'.$ex['2'] : $ex['2'];
+			$sec = (strlen($ex[2]) === 1) ? '0'.$ex[2] : $ex[2];
 		}
 		else
 		{
@@ -488,21 +482,21 @@
 			$sec = '00';
 		}
 
-		if (isset($split['2']))
+		if (isset($split[2]))
 		{
-			$ampm = strtolower($split['2']);
+			$ampm = strtolower($split[2]);
 
-			if (substr($ampm, 0, 1) == 'p' AND $hour < 12)
+			if (substr($ampm, 0, 1) === 'p' && $hour < 12)
 			{
-				$hour = $hour + 12;
+				$hour += 12;
 			}
 
-			if (substr($ampm, 0, 1) == 'a' AND $hour == 12)
+			if (substr($ampm, 0, 1) === 'a' && $hour == 12)
 			{
 				$hour =  '00';
 			}
 
-			if (strlen($hour) == 1)
+			if (strlen($hour) === 1)
 			{
 				$hour = '0'.$hour;
 			}
@@ -514,17 +508,16 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Turns many "reasonably-date-like" strings into something
- * that is actually useful. This only works for dates after unix epoch.
- *
- * @access  public
- * @param   string  The terribly formatted date-like string
- * @param   string  Date format to return (same as php date function)
- * @return  string
- */
 if ( ! function_exists('nice_date'))
 {
+	/**
+	 * Turns many "reasonably-date-like" strings into something
+	 * that is actually useful. This only works for dates after unix epoch.
+	 *
+	 * @param	string	The terribly formatted date-like string
+	 * @param	string	Date format to return (same as php date function)
+	 * @return	string
+	 */
 	function nice_date($bad_date = '', $format = FALSE)
 	{
 		if (empty($bad_date))
@@ -535,7 +528,7 @@
 		// Date like: YYYYMM
 		if (preg_match('/^\d{6}$/', $bad_date))
 		{
-			if (in_array(substr($bad_date, 0, 2),array('19', '20')))
+			if (in_array(substr($bad_date, 0, 2), array('19', '20')))
 			{
 				$year  = substr($bad_date, 0, 4);
 				$month = substr($bad_date, 4, 2);
@@ -546,32 +539,32 @@
 				$year   = substr($bad_date, 2, 4);
 			}
 
-			return date($format, strtotime($year . '-' . $month . '-01'));
+			return date($format, strtotime($year.'-'.$month.'-01'));
 		}
 
 		// Date Like: YYYYMMDD
-		if (preg_match('/^\d{8}$/',$bad_date))
+		if (preg_match('/^\d{8}$/', $bad_date))
 		{
 			$month = substr($bad_date, 0, 2);
 			$day   = substr($bad_date, 2, 2);
 			$year  = substr($bad_date, 4, 4);
 
-			return date($format, strtotime($month . '/01/' . $year));
+			return date($format, strtotime($month.'/01/'.$year));
 		}
 
 		// Date Like: MM-DD-YYYY __or__ M-D-YYYY (or anything in between)
-		if (preg_match('/^\d{1,2}-\d{1,2}-\d{4}$/',$bad_date))
+		if (preg_match('/^\d{1,2}-\d{1,2}-\d{4}$/', $bad_date))
 		{
 			list($m, $d, $y) = explode('-', $bad_date);
-			return date($format, strtotime("{$y}-{$m}-{$d}"));
+			return date($format, strtotime($y.'-'.$m.'-'.$d));
 		}
 
 		// Any other kind of string, when converted into UNIX time,
 		// produces "0 seconds after epoc..." is probably bad...
 		// return "Invalid Date".
-		if (date('U', strtotime($bad_date)) == '0')
+		if (date('U', strtotime($bad_date)) === '0')
 		{
-			return "Invalid Date";
+			return 'Invalid Date';
 		}
 
 		// It's probably a valid-ish date format already
@@ -581,29 +574,28 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Timezone Menu
- *
- * Generates a drop-down menu of timezones.
- *
- * @access	public
- * @param	string	timezone
- * @param	string	classname
- * @param	string	menu name
- * @return	string
- */
 if ( ! function_exists('timezone_menu'))
 {
-	function timezone_menu($default = 'UTC', $class = "", $name = 'timezones')
+	/**
+	 * Timezone Menu
+	 *
+	 * Generates a drop-down menu of timezones.
+	 *
+	 * @param	string	timezone
+	 * @param	string	classname
+	 * @param	string	menu name
+	 * @return	string
+	 */
+	function timezone_menu($default = 'UTC', $class = '', $name = 'timezones')
 	{
 		$CI =& get_instance();
 		$CI->lang->load('date');
 
-		$default = ($default == 'GMT') ? 'UTC' : $default;
+		$default = ($default === 'GMT') ? 'UTC' : $default;
 
 		$menu = '<select name="'.$name.'"';
 
-		if ($class != '')
+		if ($class !== '')
 		{
 			$menu .= ' class="'.$class.'"';
 		}
@@ -612,30 +604,27 @@
 
 		foreach (timezones() as $key => $val)
 		{
-			$selected = ($default == $key) ? " selected='selected'" : '';
-			$menu .= "<option value='{$key}'{$selected}>".$CI->lang->line($key)."</option>\n";
+			$selected = ($default === $key) ? ' selected="selected"' : '';
+			$menu .= '<option value="'.$key.'"'.$selected.'>'.$CI->lang->line($key)."</option>\n";
 		}
 
-		$menu .= "</select>";
-
-		return $menu;
+		return $menu.'</select>';
 	}
 }
 
 // ------------------------------------------------------------------------
 
-/**
- * Timezones
- *
- * Returns an array of timezones.  This is a helper function
- * for various other ones in this library
- *
- * @access	public
- * @param	string	timezone
- * @return	string
- */
 if ( ! function_exists('timezones'))
 {
+	/**
+	 * Timezones
+	 *
+	 * Returns an array of timezones. This is a helper function
+	 * for various other ones in this library
+	 *
+	 * @param	string	timezone
+	 * @return	string
+	 */
 	function timezones($tz = '')
 	{
 		// Note: Don't change the order of these even though
@@ -684,14 +673,14 @@
 			'UP14'		=> +14
 		);
 
-		if ($tz == '')
+		if ($tz === '')
 		{
 			return $zones;
 		}
 
-		$tz = ($tz == 'GMT') ? 'UTC' : $tz;
+		$tz = ($tz === 'GMT') ? 'UTC' : $tz;
 
-		return ( ! isset($zones[$tz])) ? 0 : $zones[$tz];
+		return isset($zones[$tz]) ? $zones[$tz] : 0;
 	}
 }
 
diff --git a/system/helpers/directory_helper.php b/system/helpers/directory_helper.php
index be65b38..e7d3b5e 100644
--- a/system/helpers/directory_helper.php
+++ b/system/helpers/directory_helper.php
@@ -1,13 +1,13 @@
-<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
- * 
+ *
  * Licensed under the Open Software License version 3.0
- * 
+ *
  * This source file is subject to the Open Software License (OSL 3.0) that is
  * bundled with this package in the files license.txt / license.rst.  It is
  * also available through the world wide web at this URL:
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * CodeIgniter Directory Helpers
  *
@@ -39,20 +37,20 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Create a Directory Map
- *
- * Reads the specified directory and builds an array
- * representation of it.  Sub-folders contained with the
- * directory will be mapped as well.
- *
- * @access	public
- * @param	string	path to source
- * @param	int		depth of directories to traverse (0 = fully recursive, 1 = current dir, etc)
- * @return	array
- */
 if ( ! function_exists('directory_map'))
 {
+	/**
+	 * Create a Directory Map
+	 *
+	 * Reads the specified directory and builds an array
+	 * representation of it. Sub-folders contained with the
+	 * directory will be mapped as well.
+	 *
+	 * @param	string	path to source
+	 * @param	int	depth of directories to traverse (0 = fully recursive, 1 = current dir, etc)
+	 * @param	bool	whether to show hidden files
+	 * @return	array
+	 */
 	function directory_map($source_dir, $directory_depth = 0, $hidden = FALSE)
 	{
 		if ($fp = @opendir($source_dir))
@@ -64,7 +62,7 @@
 			while (FALSE !== ($file = readdir($fp)))
 			{
 				// Remove '.', '..', and hidden files [optional]
-				if ( ! trim($file, '.') OR ($hidden == FALSE && $file[0] == '.'))
+				if ( ! trim($file, '.') OR ($hidden === FALSE && $file[0] === '.'))
 				{
 					continue;
 				}
@@ -87,6 +85,5 @@
 	}
 }
 
-
 /* End of file directory_helper.php */
 /* Location: ./system/helpers/directory_helper.php */
\ No newline at end of file
diff --git a/system/helpers/download_helper.php b/system/helpers/download_helper.php
index aea948d..5efbc49 100644
--- a/system/helpers/download_helper.php
+++ b/system/helpers/download_helper.php
@@ -1,13 +1,13 @@
-<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
- * 
+ *
  * Licensed under the Open Software License version 3.0
- * 
+ *
  * This source file is subject to the Open Software License (OSL 3.0) that is
  * bundled with this package in the files license.txt / license.rst.  It is
  * also available through the world wide web at this URL:
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * CodeIgniter Download Helpers
  *
@@ -39,75 +37,87 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Force Download
- *
- * Generates headers that force a download to happen
- *
- * @access	public
- * @param	string	filename
- * @param	mixed	the data to be downloaded
- * @return	void
- */
 if ( ! function_exists('force_download'))
 {
-	function force_download($filename = '', $data = '')
+	/**
+	 * Force Download
+	 *
+	 * Generates headers that force a download to happen
+	 *
+	 * @param	string	filename
+	 * @param	mixed	the data to be downloaded
+	 * @param	bool	wether to try and send the actual file MIME type
+	 * @return	void
+	 */
+	function force_download($filename = '', $data = '', $set_mime = FALSE)
 	{
-		if ($filename == '' OR $data == '')
+		if ($filename === '' OR $data === '')
 		{
 			return FALSE;
 		}
 
-		// Try to determine if the filename includes a file extension.
-		// We need it in order to set the MIME type
-		if (FALSE === strpos($filename, '.'))
-		{
-			return FALSE;
-		}
+		// Set the default MIME type to send
+		$mime = 'application/octet-stream';
 
-		// Grab the file extension
 		$x = explode('.', $filename);
 		$extension = end($x);
 
-		// Load the mime types
-		if (defined('ENVIRONMENT') AND is_file(APPPATH.'config/'.ENVIRONMENT.'/mimes.php'))
+		if ($set_mime === TRUE)
 		{
-			include(APPPATH.'config/'.ENVIRONMENT.'/mimes.php');
-		}
-		elseif (is_file(APPPATH.'config/mimes.php'))
-		{
-			include(APPPATH.'config/mimes.php');
+			if (count($x) === 1 OR $extension === '')
+			{
+				/* If we're going to detect the MIME type,
+				 * we'll need a file extension.
+				 */
+				return FALSE;
+			}
+
+			// Load the mime types
+			$mimes =& get_mimes();
+
+			// Only change the default MIME if we can find one
+			if (isset($mimes[$extension]))
+			{
+				$mime = is_array($mimes[$extension]) ? $mimes[$extension][0] : $mimes[$extension];
+			}
 		}
 
-		// Set a default mime if we can't find it
-		if ( ! isset($mimes[$extension]))
+		/* It was reported that browsers on Android 2.1 (and possibly older as well)
+		 * need to have the filename extension upper-cased in order to be able to
+		 * download it.
+		 *
+		 * Reference: http://digiblog.de/2011/04/19/android-and-the-download-file-headers/
+		 */
+		if (count($x) !== 1 && isset($_SERVER['HTTP_USER_AGENT']) && preg_match('/Android\s(1|2\.[01])/', $_SERVER['HTTP_USER_AGENT']))
 		{
-			$mime = 'application/octet-stream';
+			$x[count($x) - 1] = strtoupper($extension);
+			$filename = implode('.', $x);
 		}
-		else
-		{
-			$mime = (is_array($mimes[$extension])) ? $mimes[$extension][0] : $mimes[$extension];
-		}
-		
+
+		// Clean output buffer
+		ob_clean();
+
 		// Generate the server headers
-		header('Content-Type: "'.$mime.'"');
+		header('Content-Type: '.$mime);
 		header('Content-Disposition: attachment; filename="'.$filename.'"');
 		header('Expires: 0');
-		header("Content-Transfer-Encoding: binary");
-		header("Content-Length: ".strlen($data));
-		header('Pragma: no-cache');
+		header('Content-Transfer-Encoding: binary');
+		header('Content-Length: '.strlen($data));
 
-		// Internet Explorer-specific headers.
-		if (isset($_SERVER['HTTP_USER_AGENT']) && strpos($_SERVER['HTTP_USER_AGENT'], "MSIE") !== FALSE)
+		// Internet Explorer-specific headers
+		if (isset($_SERVER['HTTP_USER_AGENT']) && strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') !== FALSE)
 		{
 			header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
 			header('Pragma: public');
 		}
+		else
+		{
+			header('Pragma: no-cache');
+		}
 
 		exit($data);
 	}
 }
 
-
 /* End of file download_helper.php */
 /* Location: ./system/helpers/download_helper.php */
\ No newline at end of file
diff --git a/system/helpers/email_helper.php b/system/helpers/email_helper.php
index f184031..0516e93 100644
--- a/system/helpers/email_helper.php
+++ b/system/helpers/email_helper.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * CodeIgniter Email Helpers
  *
@@ -39,14 +37,14 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Validate email address
- *
- * @access	public
- * @return	bool
- */
 if ( ! function_exists('valid_email'))
 {
+	/**
+	 * Validate email address
+	 *
+	 * @param	string
+	 * @return	bool
+	 */
 	function valid_email($address)
 	{
 		return (bool) preg_match('/^([a-z0-9\+_\-]+)(\.[a-z0-9\+_\-]+)*@([a-z0-9\-]+\.)+[a-z]{2,6}$/ix', $address);
@@ -55,14 +53,16 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Send an email
- *
- * @access	public
- * @return	bool
- */
 if ( ! function_exists('send_email'))
 {
+	/**
+	 * Send an email
+	 *
+	 * @param	string
+	 * @param	string
+	 * @param	string
+	 * @return	bool
+	 */
 	function send_email($recipient, $subject = 'Test email', $message = 'Hello World')
 	{
 		return mail($recipient, $subject, $message);
@@ -70,4 +70,4 @@
 }
 
 /* End of file email_helper.php */
-/* Location: ./system/helpers/email_helper.php */
+/* Location: ./system/helpers/email_helper.php */
\ No newline at end of file
diff --git a/system/helpers/file_helper.php b/system/helpers/file_helper.php
index 2d4b10e..be616f6 100644
--- a/system/helpers/file_helper.php
+++ b/system/helpers/file_helper.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * CodeIgniter File Helpers
  *
@@ -39,64 +37,40 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Read File
- *
- * Opens the file specfied in the path and returns it as a string.
- *
- * @access	public
- * @param	string	path to file
- * @return	string
- */
 if ( ! function_exists('read_file'))
 {
+	/**
+	 * Read File
+	 *
+	 * Opens the file specfied in the path and returns it as a string.
+	 *
+	 * This function is DEPRECATED and should be removed in
+	 * CodeIgniter 3.1+. Use file_get_contents() instead.
+	 *
+	 * @param	string	path to file
+	 * @return	string
+	 */
 	function read_file($file)
 	{
-		if ( ! file_exists($file))
-		{
-			return FALSE;
-		}
-
-		if (function_exists('file_get_contents'))
-		{
-			return file_get_contents($file);
-		}
-
-		if ( ! $fp = @fopen($file, FOPEN_READ))
-		{
-			return FALSE;
-		}
-
-		flock($fp, LOCK_SH);
-
-		$data = '';
-		if (filesize($file) > 0)
-		{
-			$data =& fread($fp, filesize($file));
-		}
-
-		flock($fp, LOCK_UN);
-		fclose($fp);
-
-		return $data;
+		return @file_get_contents($file);
 	}
 }
 
 // ------------------------------------------------------------------------
 
-/**
- * Write File
- *
- * Writes data to the file specified in the path.
- * Creates a new file if non-existent.
- *
- * @access	public
- * @param	string	path to file
- * @param	string	file data
- * @return	bool
- */
 if ( ! function_exists('write_file'))
 {
+	/**
+	 * Write File
+	 *
+	 * Writes data to the file specified in the path.
+	 * Creates a new file if non-existent.
+	 *
+	 * @param	string	path to file
+	 * @param	string	file data
+	 * @param	int
+	 * @return	bool
+	 */
 	function write_file($path, $data, $mode = FOPEN_WRITE_CREATE_DESTRUCTIVE)
 	{
 		if ( ! $fp = @fopen($path, $mode))
@@ -115,22 +89,23 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Delete Files
- *
- * Deletes all files contained in the supplied directory path.
- * Files must be writable or owned by the system in order to be deleted.
- * If the second parameter is set to TRUE, any directories contained
- * within the supplied base directory will be nuked as well.
- *
- * @access	public
- * @param	string	path to file
- * @param	bool	whether to delete any directories found in the path
- * @return	bool
- */
 if ( ! function_exists('delete_files'))
 {
-	function delete_files($path, $del_dir = FALSE, $level = 0)
+	/**
+	 * Delete Files
+	 *
+	 * Deletes all files contained in the supplied directory path.
+	 * Files must be writable or owned by the system in order to be deleted.
+	 * If the second parameter is set to TRUE, any directories contained
+	 * within the supplied base directory will be nuked as well.
+	 *
+	 * @param	string	path to file
+	 * @param	bool	whether to delete any directories found in the path
+	 * @param	int
+	 * @param	bool	whether to skip deleting .htaccess and index page files
+	 * @return	bool
+	 */
+	function delete_files($path, $del_dir = FALSE, $level = 0, $htdocs = FALSE)
 	{
 		// Trim the trailing slash
 		$path = rtrim($path, DIRECTORY_SEPARATOR);
@@ -142,21 +117,21 @@
 
 		while (FALSE !== ($filename = @readdir($current_dir)))
 		{
-			if ($filename !== '.' and $filename !== '..')
+			if ($filename !== '.' && $filename !== '..')
 			{
 				if (is_dir($path.DIRECTORY_SEPARATOR.$filename) && $filename[0] !== '.')
 				{
-					delete_files($path.DIRECTORY_SEPARATOR.$filename, $del_dir, $level + 1);
+					delete_files($path.DIRECTORY_SEPARATOR.$filename, $del_dir, $level + 1, $htdocs);
 				}
-				else
+				elseif ($htdocs === TRUE && ! preg_match('/^(\.htaccess|index\.(html|htm|php)|web\.config)$/i', $filename))
 				{
-					unlink($path.DIRECTORY_SEPARATOR.$filename);
+					@unlink($path.DIRECTORY_SEPARATOR.$filename);
 				}
 			}
 		}
 		@closedir($current_dir);
 
-		if ($del_dir == TRUE AND $level > 0)
+		if ($del_dir === TRUE && $level > 0)
 		{
 			return @rmdir($path);
 		}
@@ -167,20 +142,19 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Get Filenames
- *
- * Reads the specified directory and builds an array containing the filenames.
- * Any sub-folders contained within the specified path are read as well.
- *
- * @access	public
- * @param	string	path to source
- * @param	bool	whether to include the path as part of the filename
- * @param	bool	internal variable to determine recursion status - do not use in calls
- * @return	array
- */
 if ( ! function_exists('get_filenames'))
 {
+	/**
+	 * Get Filenames
+	 *
+	 * Reads the specified directory and builds an array containing the filenames.
+	 * Any sub-folders contained within the specified path are read as well.
+	 *
+	 * @param	string	path to source
+	 * @param	bool	whether to include the path as part of the filename
+	 * @param	bool	internal variable to determine recursion status - do not use in calls
+	 * @return	array
+	 */
 	function get_filenames($source_dir, $include_path = FALSE, $_recursion = FALSE)
 	{
 		static $_filedata = array();
@@ -202,7 +176,7 @@
 				}
 				elseif ($file[0] !== '.')
 				{
-					$_filedata[] = ($include_path == TRUE) ? $source_dir.$file : $file;
+					$_filedata[] = ($include_path === TRUE) ? $source_dir.$file : $file;
 				}
 			}
 			closedir($fp);
@@ -216,22 +190,21 @@
 
 // --------------------------------------------------------------------
 
-/**
- * Get Directory File Information
- *
- * Reads the specified directory and builds an array containing the filenames,
- * filesize, dates, and permissions
- *
- * Any sub-folders contained within the specified path are read as well.
- *
- * @access	public
- * @param	string	path to source
- * @param	bool	Look only at the top level directory specified?
- * @param	bool	internal variable to determine recursion status - do not use in calls
- * @return	array
- */
 if ( ! function_exists('get_dir_file_info'))
 {
+	/**
+	 * Get Directory File Information
+	 *
+	 * Reads the specified directory and builds an array containing the filenames,
+	 * filesize, dates, and permissions
+	 *
+	 * Any sub-folders contained within the specified path are read as well.
+	 *
+	 * @param	string	path to source
+	 * @param	bool	Look only at the top level directory specified?
+	 * @param	bool	internal variable to determine recursion status - do not use in calls
+	 * @return	array
+	 */
 	function get_dir_file_info($source_dir, $top_level_only = TRUE, $_recursion = FALSE)
 	{
 		static $_filedata = array();
@@ -270,21 +243,20 @@
 
 // --------------------------------------------------------------------
 
-/**
-* Get File Info
-*
-* Given a file and path, returns the name, path, size, date modified
-* Second parameter allows you to explicitly declare what information you want returned
-* Options are: name, server_path, size, date, readable, writable, executable, fileperms
-* Returns FALSE if the file cannot be found.
-*
-* @access	public
-* @param	string	path to file
-* @param	mixed	array or comma separated string of information returned
-* @return	array
-*/
 if ( ! function_exists('get_file_info'))
 {
+	/**
+	 * Get File Info
+	 *
+	 * Given a file and path, returns the name, path, size, date modified
+	 * Second parameter allows you to explicitly declare what information you want returned
+	 * Options are: name, server_path, size, date, readable, writable, executable, fileperms
+	 * Returns FALSE if the file cannot be found.
+	 *
+	 * @param	string	path to file
+	 * @param	mixed	array or comma separated string of information returned
+	 * @return	array
+	 */
 	function get_file_info($file, $returned_values = array('name', 'server_path', 'size', 'date'))
 	{
 
@@ -336,55 +308,41 @@
 
 // --------------------------------------------------------------------
 
-/**
- * Get Mime by Extension
- *
- * Translates a file extension into a mime type based on config/mimes.php.
- * Returns FALSE if it can't determine the type, or open the mime config file
- *
- * Note: this is NOT an accurate way of determining file mime types, and is here strictly as a convenience
- * It should NOT be trusted, and should certainly NOT be used for security
- *
- * @access	public
- * @param	string	path to file
- * @return	mixed
- */
 if ( ! function_exists('get_mime_by_extension'))
 {
+	/**
+	 * Get Mime by Extension
+	 *
+	 * Translates a file extension into a mime type based on config/mimes.php.
+	 * Returns FALSE if it can't determine the type, or open the mime config file
+	 *
+	 * Note: this is NOT an accurate way of determining file mime types, and is here strictly as a convenience
+	 * It should NOT be trusted, and should certainly NOT be used for security
+	 *
+	 * @param	string	path to file
+	 * @return	mixed
+	 */
 	function get_mime_by_extension($file)
 	{
 		$extension = strtolower(substr(strrchr($file, '.'), 1));
 
-		global $mimes;
+		static $mimes;
 
 		if ( ! is_array($mimes))
 		{
-			if (defined('ENVIRONMENT') && is_file(APPPATH.'config/'.ENVIRONMENT.'/mimes.php'))
-			{
-				include(APPPATH.'config/'.ENVIRONMENT.'/mimes.php');
-			}
-			elseif (is_file(APPPATH.'config/mimes.php'))
-			{
-				include(APPPATH.'config/mimes.php');
-			}
+			$mimes =& get_mimes();
 
-			if ( ! is_array($mimes))
+			if (empty($mimes))
 			{
 				return FALSE;
 			}
 		}
 
-		if (array_key_exists($extension, $mimes))
+		if (isset($mimes[$extension]))
 		{
-			if (is_array($mimes[$extension]))
-			{
-				// Multiple mime types, just give the first one
-				return current($mimes[$extension]);
-			}
-			else
-			{
-				return $mimes[$extension];
-			}
+			return is_array($mimes[$extension])
+				? current($mimes[$extension]) // Multiple mime types, just give the first one
+				: $mimes[$extension];
 		}
 
 		return FALSE;
@@ -393,18 +351,17 @@
 
 // --------------------------------------------------------------------
 
-/**
- * Symbolic Permissions
- *
- * Takes a numeric value representing a file's permissions and returns
- * standard symbolic notation representing that value
- *
- * @access	public
- * @param	int
- * @return	string
- */
 if ( ! function_exists('symbolic_permissions'))
 {
+	/**
+	 * Symbolic Permissions
+	 *
+	 * Takes a numeric value representing a file's permissions and returns
+	 * standard symbolic notation representing that value
+	 *
+	 * @param	int
+	 * @return	string
+	 */
 	function symbolic_permissions($perms)
 	{
 		if (($perms & 0xC000) === 0xC000)
@@ -461,18 +418,17 @@
 
 // --------------------------------------------------------------------
 
-/**
- * Octal Permissions
- *
- * Takes a numeric value representing a file's permissions and returns
- * a three character string representing the file's octal permissions
- *
- * @access	public
- * @param	int
- * @return	string
- */
 if ( ! function_exists('octal_permissions'))
 {
+	/**
+	 * Octal Permissions
+	 *
+	 * Takes a numeric value representing a file's permissions and returns
+	 * a three character string representing the file's octal permissions
+	 *
+	 * @param	int
+	 * @return	string
+	 */
 	function octal_permissions($perms)
 	{
 		return substr(sprintf('%o', $perms), -3);
@@ -480,4 +436,4 @@
 }
 
 /* End of file file_helper.php */
-/* Location: ./system/helpers/file_helper.php */
+/* Location: ./system/helpers/file_helper.php */
\ No newline at end of file
diff --git a/system/helpers/form_helper.php b/system/helpers/form_helper.php
index bed2cb2..9846343 100644
--- a/system/helpers/form_helper.php
+++ b/system/helpers/form_helper.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -22,11 +22,8 @@
  * @license		http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
  * @link		http://codeigniter.com
  * @since		Version 1.0
- * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * CodeIgniter Form Helpers
  *
@@ -39,24 +36,23 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Form Declaration
- *
- * Creates the opening portion of the form.
- *
- * @access	public
- * @param	string	the URI segments of the form destination
- * @param	array	a key/value pair of attributes
- * @param	array	a key/value pair hidden data
- * @return	string
- */
 if ( ! function_exists('form_open'))
 {
+	/**
+	 * Form Declaration
+	 *
+	 * Creates the opening portion of the form.
+	 *
+	 * @param	string	the URI segments of the form destination
+	 * @param	array	a key/value pair of attributes
+	 * @param	array	a key/value pair hidden data
+	 * @return	string
+	 */
 	function form_open($action = '', $attributes = '', $hidden = array())
 	{
 		$CI =& get_instance();
 
-		if ($attributes == '')
+		if ($attributes === '')
 		{
 			$attributes = 'method="post"';
 		}
@@ -73,14 +69,14 @@
 		$form = '<form action="'.$action.'"'._attributes_to_string($attributes, TRUE).">\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 AND ! (strpos($action, $CI->config->site_url()) === FALSE OR strpos($form, 'method="get"')))
+		if ($CI->config->item('csrf_protection') === TRUE && ! (strpos($action, $CI->config->base_url()) === FALSE OR strpos($form, 'method="get"')))
 		{
 			$hidden[$CI->security->get_csrf_token_name()] = $CI->security->get_csrf_hash();
 		}
 
-		if (is_array($hidden) AND count($hidden) > 0)
+		if (is_array($hidden) && count($hidden) > 0)
 		{
-			$form .= sprintf("<div style=\"display:none\">%s</div>", form_hidden($hidden));
+			$form .= sprintf('<div style="display:none;">%s</div>', form_hidden($hidden));
 		}
 
 		return $form;
@@ -89,19 +85,18 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Form Declaration - Multipart type
- *
- * Creates the opening portion of the form, but with "multipart/form-data".
- *
- * @access	public
- * @param	string	the URI segments of the form destination
- * @param	array	a key/value pair of attributes
- * @param	array	a key/value pair hidden data
- * @return	string
- */
 if ( ! function_exists('form_open_multipart'))
 {
+	/**
+	 * Form Declaration - Multipart type
+	 *
+	 * Creates the opening portion of the form, but with "multipart/form-data".
+	 *
+	 * @param	string	the URI segments of the form destination
+	 * @param	array	a key/value pair of attributes
+	 * @param	array	a key/value pair hidden data
+	 * @return	string
+	 */
 	function form_open_multipart($action = '', $attributes = array(), $hidden = array())
 	{
 		if (is_string($attributes))
@@ -119,19 +114,19 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Hidden Input Field
- *
- * Generates hidden fields.  You can pass a simple key/value string or an associative
- * array with multiple values.
- *
- * @access	public
- * @param	mixed
- * @param	string
- * @return	string
- */
 if ( ! function_exists('form_hidden'))
 {
+	/**
+	 * Hidden Input Field
+	 *
+	 * Generates hidden fields. You can pass a simple key/value string or
+	 * an associative array with multiple values.
+	 *
+	 * @param	mixed
+	 * @param	string
+	 * @param	bool
+	 * @return	string
+	 */
 	function form_hidden($name, $value = '', $recursing = FALSE)
 	{
 		static $form;
@@ -158,7 +153,7 @@
 		{
 			foreach ($value as $k => $v)
 			{
-				$k = (is_int($k)) ? '' : $k;
+				$k = is_int($k) ? '' : $k;
 				form_hidden($name.'['.$k.']', $v, TRUE);
 			}
 		}
@@ -169,20 +164,19 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Text Input Field
- *
- * @access	public
- * @param	mixed
- * @param	string
- * @param	string
- * @return	string
- */
 if ( ! function_exists('form_input'))
 {
+	/**
+	 * Text Input Field
+	 *
+	 * @param	mixed
+	 * @param	string
+	 * @param	string
+	 * @return	string
+	 */
 	function form_input($data = '', $value = '', $extra = '')
 	{
-		$defaults = array('type' => 'text', 'name' => (( ! is_array($data)) ? $data : ''), 'value' => $value);
+		$defaults = array('type' => 'text', 'name' => ( ! is_array($data) ? $data : ''), 'value' => $value);
 
 		return '<input '._parse_form_attributes($data, $defaults).$extra." />\n";
 	}
@@ -190,19 +184,18 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Password Field
- *
- * Identical to the input function but adds the "password" type
- *
- * @access	public
- * @param	mixed
- * @param	string
- * @param	string
- * @return	string
- */
 if ( ! function_exists('form_password'))
 {
+	/**
+	 * Password Field
+	 *
+	 * Identical to the input function but adds the "password" type
+	 *
+	 * @param	mixed
+	 * @param	string
+	 * @param	string
+	 * @return	string
+	 */
 	function form_password($data = '', $value = '', $extra = '')
 	{
 		if ( ! is_array($data))
@@ -217,19 +210,18 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Upload Field
- *
- * Identical to the input function but adds the "file" type
- *
- * @access	public
- * @param	mixed
- * @param	string
- * @param	string
- * @return	string
- */
 if ( ! function_exists('form_upload'))
 {
+	/**
+	 * Upload Field
+	 *
+	 * Identical to the input function but adds the "file" type
+	 *
+	 * @param	mixed
+	 * @param	string
+	 * @param	string
+	 * @return	string
+	 */
 	function form_upload($data = '', $value = '', $extra = '')
 	{
 		if ( ! is_array($data))
@@ -244,20 +236,19 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Textarea field
- *
- * @access	public
- * @param	mixed
- * @param	string
- * @param	string
- * @return	string
- */
 if ( ! function_exists('form_textarea'))
 {
+	/**
+	 * Textarea field
+	 *
+	 * @param	mixed
+	 * @param	string
+	 * @param	string
+	 * @return	string
+	 */
 	function form_textarea($data = '', $value = '', $extra = '')
 	{
-		$defaults = array('name' => (( ! is_array($data)) ? $data : ''), 'cols' => '40', 'rows' => '10');
+		$defaults = array('name' => ( ! is_array($data) ? $data : ''), 'cols' => '40', 'rows' => '10');
 
 		if ( ! is_array($data) OR ! isset($data['value']))
 		{
@@ -269,25 +260,24 @@
 			unset($data['value']); // textareas don't use the value attribute
 		}
 
-		$name = (is_array($data)) ? $data['name'] : $data;
+		$name = is_array($data) ? $data['name'] : $data;
 		return '<textarea '._parse_form_attributes($data, $defaults).$extra.'>'.form_prep($val, $name)."</textarea>\n";
 	}
 }
 
 // ------------------------------------------------------------------------
 
-/**
- * Multi-select menu
- *
- * @access	public
- * @param	string
- * @param	array
- * @param	mixed
- * @param	string
- * @return	type
- */
 if ( ! function_exists('form_multiselect'))
 {
+	/**
+	 * Multi-select menu
+	 *
+	 * @param	string
+	 * @param	array
+	 * @param	mixed
+	 * @param	string
+	 * @return	string
+	 */
 	function form_multiselect($name = '', $options = array(), $selected = array(), $extra = '')
 	{
 		if ( ! strpos($extra, 'multiple'))
@@ -301,20 +291,29 @@
 
 // --------------------------------------------------------------------
 
-/**
- * Drop-down Menu
- *
- * @access	public
- * @param	string
- * @param	array
- * @param	string
- * @param	string
- * @return	string
- */
 if ( ! function_exists('form_dropdown'))
 {
+	/**
+	 * Drop-down Menu
+	 *
+	 * @param	string
+	 * @param	array
+	 * @param	string
+	 * @param	string
+	 * @return	string
+	 */
 	function form_dropdown($name = '', $options = array(), $selected = array(), $extra = '')
 	{
+		// If name is really an array then we'll call the function again using the array
+		if (is_array($name) && isset($name['name']))
+		{
+			isset($name['options']) OR $name['options'] = array();
+			isset($name['selected']) OR $name['selected'] = array();
+			isset($name['extra']) OR $name['extra'] = array();
+
+			return form_dropdown($name['name'], $name['options'], $name['selected'], $name['extra']);
+		}
+
 		if ( ! is_array($selected))
 		{
 			$selected = array($selected);
@@ -326,7 +325,10 @@
 			$selected = array($_POST[$name]);
 		}
 
-		if ($extra != '') $extra = ' '.$extra;
+		if ($extra != '')
+		{
+			$extra = ' '.$extra;
+		}
 
 		$multiple = (count($selected) > 1 && strpos($extra, 'multiple') === FALSE) ? ' multiple="multiple"' : '';
 
@@ -342,11 +344,11 @@
 
 				foreach ($val as $optgroup_key => $optgroup_val)
 				{
-					$sel = (in_array($optgroup_key, $selected)) ? ' selected="selected"' : '';
+					$sel = in_array($optgroup_key, $selected) ? ' selected="selected"' : '';
 					$form .= '<option value="'.$optgroup_key.'"'.$sel.'>'.(string) $optgroup_val."</option>\n";
 				}
 
-				$form .= '</optgroup>'."\n";
+				$form .= "</optgroup>\n";
 			}
 			else
 			{
@@ -354,31 +356,28 @@
 			}
 		}
 
-		$form .= "</select>\n";
-
-		return $form;
+		return $form."</select>\n";
 	}
 }
 
 // ------------------------------------------------------------------------
 
-/**
- * Checkbox Field
- *
- * @access	public
- * @param	mixed
- * @param	string
- * @param	bool
- * @param	string
- * @return	string
- */
 if ( ! function_exists('form_checkbox'))
 {
+	/**
+	 * Checkbox Field
+	 *
+	 * @param	mixed
+	 * @param	string
+	 * @param	bool
+	 * @param	string
+	 * @return	string
+	 */
 	function form_checkbox($data = '', $value = '', $checked = FALSE, $extra = '')
 	{
-		$defaults = array('type' => 'checkbox', 'name' => (( ! is_array($data)) ? $data : ''), 'value' => $value);
+		$defaults = array('type' => 'checkbox', 'name' => ( ! is_array($data) ? $data : ''), 'value' => $value);
 
-		if (is_array($data) AND array_key_exists('checked', $data))
+		if (is_array($data) && array_key_exists('checked', $data))
 		{
 			$checked = $data['checked'];
 
@@ -407,18 +406,17 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Radio Button
- *
- * @access	public
- * @param	mixed
- * @param	string
- * @param	bool
- * @param	string
- * @return	string
- */
 if ( ! function_exists('form_radio'))
 {
+	/**
+	 * Radio Button
+	 *
+	 * @param	mixed
+	 * @param	string
+	 * @param	bool
+	 * @param	string
+	 * @return	string
+	 */
 	function form_radio($data = '', $value = '', $checked = FALSE, $extra = '')
 	{
 		if ( ! is_array($data))
@@ -433,61 +431,58 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Submit Button
- *
- * @access	public
- * @param	mixed
- * @param	string
- * @param	string
- * @return	string
- */
 if ( ! function_exists('form_submit'))
 {
+	/**
+	 * Submit Button
+	 *
+	 * @param	mixed
+	 * @param	string
+	 * @param	string
+	 * @return	string
+	 */
 	function form_submit($data = '', $value = '', $extra = '')
 	{
-		$defaults = array('type' => 'submit', 'name' => (( ! is_array($data)) ? $data : ''), 'value' => $value);
+		$defaults = array('type' => 'submit', 'name' => ( ! is_array($data) ? $data : ''), 'value' => $value);
 		return '<input '._parse_form_attributes($data, $defaults).$extra." />\n";
 	}
 }
 
 // ------------------------------------------------------------------------
 
-/**
- * Reset Button
- *
- * @access	public
- * @param	mixed
- * @param	string
- * @param	string
- * @return	string
- */
 if ( ! function_exists('form_reset'))
 {
+	/**
+	 * Reset Button
+	 *
+	 * @param	mixed
+	 * @param	string
+	 * @param	string
+	 * @return	string
+	 */
 	function form_reset($data = '', $value = '', $extra = '')
 	{
-		$defaults = array('type' => 'reset', 'name' => (( ! is_array($data)) ? $data : ''), 'value' => $value);
+		$defaults = array('type' => 'reset', 'name' => ( ! is_array($data) ? $data : ''), 'value' => $value);
 		return '<input '._parse_form_attributes($data, $defaults).$extra." />\n";
 	}
 }
 
 // ------------------------------------------------------------------------
 
-/**
- * Form Button
- *
- * @access	public
- * @param	mixed
- * @param	string
- * @param	string
- * @return	string
- */
 if ( ! function_exists('form_button'))
 {
+	/**
+	 * Form Button
+	 *
+	 * @param	mixed
+	 * @param	string
+	 * @param	string
+	 * @return	string
+	 */
 	function form_button($data = '', $content = '', $extra = '')
 	{
-		$defaults = array('name' => (( ! is_array($data)) ? $data : ''), 'type' => 'button');
-		if ( is_array($data) AND isset($data['content']))
+		$defaults = array('name' => ( ! is_array($data) ? $data : ''), 'type' => 'button');
+		if (is_array($data) && isset($data['content']))
 		{
 			$content = $data['content'];
 			unset($data['content']); // content is not an attribute
@@ -499,28 +494,27 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Form Label Tag
- *
- * @access	public
- * @param	string	The text to appear onscreen
- * @param	string	The id the label applies to
- * @param	string	Additional attributes
- * @return	string
- */
 if ( ! function_exists('form_label'))
 {
+	/**
+	 * Form Label Tag
+	 *
+	 * @param	string	The text to appear onscreen
+	 * @param	string	The id the label applies to
+	 * @param	string	Additional attributes
+	 * @return	string
+	 */
 	function form_label($label_text = '', $id = '', $attributes = array())
 	{
 
 		$label = '<label';
 
-		if ($id != '')
+		if ($id !== '')
 		{
-			$label .= " for=\"$id\"";
+			$label .= ' for="'.$id.'"';
 		}
 
-		if (is_array($attributes) AND count($attributes) > 0)
+		if (is_array($attributes) && count($attributes) > 0)
 		{
 			foreach ($attributes as $key => $val)
 			{
@@ -528,30 +522,30 @@
 			}
 		}
 
-		return $label .= ">$label_text</label>";
+		return $label.'>'.$label_text.'</label>';
 	}
 }
 
 // ------------------------------------------------------------------------
-/**
- * Fieldset Tag
- *
- * Used to produce <fieldset><legend>text</legend>.  To close fieldset
- * use form_fieldset_close()
- *
- * @access	public
- * @param	string	The legend text
- * @param	string	Additional attributes
- * @return	string
- */
+
 if ( ! function_exists('form_fieldset'))
 {
+	/**
+	 * Fieldset Tag
+	 *
+	 * Used to produce <fieldset><legend>text</legend>.  To close fieldset
+	 * use form_fieldset_close()
+	 *
+	 * @param	string	The legend text
+	 * @param	string	Additional attributes
+	 * @return	string
+	 */
 	function form_fieldset($legend_text = '', $attributes = array())
 	{
 		$fieldset = '<fieldset'._attributes_to_string($attributes, FALSE).">\n";
-		if ($legend_text != '')
+		if ($legend_text !== '')
 		{
-			$fieldset .= "<legend>$legend_text</legend>\n";
+			return $fieldset.'<legend>'.$legend_text."</legend>\n";
 		}
 
 		return $fieldset;
@@ -560,51 +554,49 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Fieldset Close Tag
- *
- * @access	public
- * @param	string
- * @return	string
- */
 if ( ! function_exists('form_fieldset_close'))
 {
+	/**
+	 * Fieldset Close Tag
+	 *
+	 * @param	string
+	 * @return	string
+	 */
 	function form_fieldset_close($extra = '')
 	{
-		return "</fieldset>".$extra;
+		return '</fieldset>'.$extra;
 	}
 }
 
 // ------------------------------------------------------------------------
 
-/**
- * Form Close Tag
- *
- * @access	public
- * @param	string
- * @return	string
- */
 if ( ! function_exists('form_close'))
 {
+	/**
+	 * Form Close Tag
+	 *
+	 * @param	string
+	 * @return	string
+	 */
 	function form_close($extra = '')
 	{
-		return "</form>".$extra;
+		return '</form>'.$extra;
 	}
 }
 
 // ------------------------------------------------------------------------
 
-/**
- * Form Prep
- *
- * Formats text so that it can be safely placed in a form field in the event it has HTML tags.
- *
- * @access	public
- * @param	string
- * @return	string
- */
 if ( ! function_exists('form_prep'))
 {
+	/**
+	 * Form Prep
+	 *
+	 * Formats text so that it can be safely placed in a form field in the event it has HTML tags.
+	 *
+	 * @param	string
+	 * @param	string
+	 * @return	string
+	 */
 	function form_prep($str = '', $field_name = '')
 	{
 		static $prepped_fields = array();
@@ -634,7 +626,7 @@
 			return $str;
 		}
 
-		if ($field_name != '')
+		if ($field_name !== '')
 		{
 			$prepped_fields[$field_name] = $field_name;
 		}
@@ -645,19 +637,19 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Form Value
- *
- * Grabs a value from the POST array for the specified field so you can
- * re-populate an input field or textarea.  If Form Validation
- * is active it retrieves the info from the validation class
- *
- * @access	public
- * @param	string
- * @return	mixed
- */
 if ( ! function_exists('set_value'))
 {
+	/**
+	 * Form Value
+	 *
+	 * Grabs a value from the POST array for the specified field so you can
+	 * re-populate an input field or textarea. If Form Validation
+	 * is active it retrieves the info from the validation class
+	 *
+	 * @param	string
+	 * @param	string
+	 * @return	mixed
+	 */
 	function set_value($field = '', $default = '')
 	{
 		if (FALSE === ($OBJ =& _get_validation_object()))
@@ -676,20 +668,19 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Set Select
- *
- * Let's you set the selected value of a <select> menu via data in the POST array.
- * If Form Validation is active it retrieves the info from the validation class
- *
- * @access	public
- * @param	string
- * @param	string
- * @param	bool
- * @return	string
- */
 if ( ! function_exists('set_select'))
 {
+	/**
+	 * Set Select
+	 *
+	 * Let's you set the selected value of a <select> menu via data in the POST array.
+	 * If Form Validation is active it retrieves the info from the validation class
+	 *
+	 * @param	string
+	 * @param	string
+	 * @param	bool
+	 * @return	string
+	 */
 	function set_select($field = '', $value = '', $default = FALSE)
 	{
 		$OBJ =& _get_validation_object();
@@ -698,7 +689,7 @@
 		{
 			if ( ! isset($_POST[$field]))
 			{
-				if (count($_POST) === 0 AND $default == TRUE)
+				if (count($_POST) === 0 && $default === TRUE)
 				{
 					return ' selected="selected"';
 				}
@@ -714,12 +705,9 @@
 					return '';
 				}
 			}
-			else
+			elseif (($field == '' OR $value == '') OR $field !== $value)
 			{
-				if (($field == '' OR $value == '') OR ($field != $value))
-				{
-					return '';
-				}
+				return '';
 			}
 
 			return ' selected="selected"';
@@ -731,20 +719,19 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Set Checkbox
- *
- * Let's you set the selected value of a checkbox via the value in the POST array.
- * If Form Validation is active it retrieves the info from the validation class
- *
- * @access	public
- * @param	string
- * @param	string
- * @param	bool
- * @return	string
- */
 if ( ! function_exists('set_checkbox'))
 {
+	/**
+	 * Set Checkbox
+	 *
+	 * Let's you set the selected value of a checkbox via the value in the POST array.
+	 * If Form Validation is active it retrieves the info from the validation class
+	 *
+	 * @param	string
+	 * @param	string
+	 * @param	bool
+	 * @return	string
+	 */
 	function set_checkbox($field = '', $value = '', $default = FALSE)
 	{
 		$OBJ =& _get_validation_object();
@@ -753,7 +740,7 @@
 		{
 			if ( ! isset($_POST[$field]))
 			{
-				if (count($_POST) === 0 AND $default == TRUE)
+				if (count($_POST) === 0 && $default === TRUE)
 				{
 					return ' checked="checked"';
 				}
@@ -769,12 +756,9 @@
 					return '';
 				}
 			}
-			else
+			elseif (($field == '' OR $value == '') OR $field !== $value)
 			{
-				if (($field == '' OR $value == '') OR ($field != $value))
-				{
-					return '';
-				}
+				return '';
 			}
 
 			return ' checked="checked"';
@@ -786,20 +770,19 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Set Radio
- *
- * 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
- *
- * @access	public
- * @param	string
- * @param	string
- * @param	bool
- * @return	string
- */
 if ( ! function_exists('set_radio'))
 {
+	/**
+	 * Set Radio
+	 *
+	 * 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
+	 * @return	string
+	 */
 	function set_radio($field = '', $value = '', $default = FALSE)
 	{
 		$OBJ =& _get_validation_object();
@@ -808,7 +791,7 @@
 		{
 			if ( ! isset($_POST[$field]))
 			{
-				if (count($_POST) === 0 AND $default == TRUE)
+				if (count($_POST) === 0 && $default === TRUE)
 				{
 					return ' checked="checked"';
 				}
@@ -826,7 +809,7 @@
 			}
 			else
 			{
-				if (($field == '' OR $value == '') OR ($field != $value))
+				if (($field == '' OR $value == '') OR $field !== $value)
 				{
 					return '';
 				}
@@ -841,20 +824,20 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Form Error
- *
- * Returns the error for a specific form field.  This is a helper for the
- * form validation class.
- *
- * @access	public
- * @param	string
- * @param	string
- * @param	string
- * @return	string
- */
+
 if ( ! function_exists('form_error'))
 {
+	/**
+	 * Form Error
+	 *
+	 * Returns the error for a specific form field. This is a helper for the
+	 * form validation class.
+	 *
+	 * @param	string
+	 * @param	string
+	 * @param	string
+	 * @return	string
+	 */
 	function form_error($field = '', $prefix = '', $suffix = '')
 	{
 		if (FALSE === ($OBJ =& _get_validation_object()))
@@ -868,19 +851,18 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Validation Error String
- *
- * Returns all the errors associated with a form submission.  This is a helper
- * function for the form validation class.
- *
- * @access	public
- * @param	string
- * @param	string
- * @return	string
- */
 if ( ! function_exists('validation_errors'))
 {
+	/**
+	 * Validation Error String
+	 *
+	 * Returns all the errors associated with a form submission. This is a helper
+	 * function for the form validation class.
+	 *
+	 * @param	string
+	 * @param	string
+	 * @return	string
+	 */
 	function validation_errors($prefix = '', $suffix = '')
 	{
 		if (FALSE === ($OBJ =& _get_validation_object()))
@@ -894,18 +876,17 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Parse the form attributes
- *
- * Helper function used by some of the form helpers
- *
- * @access	private
- * @param	array
- * @param	array
- * @return	string
- */
 if ( ! function_exists('_parse_form_attributes'))
 {
+	/**
+	 * Parse the form attributes
+	 *
+	 * Helper function used by some of the form helpers
+	 *
+	 * @param	array
+	 * @param	array
+	 * @return	string
+	 */
 	function _parse_form_attributes($attributes, $default)
 	{
 		if (is_array($attributes))
@@ -929,12 +910,12 @@
 
 		foreach ($default as $key => $val)
 		{
-			if ($key == 'value')
+			if ($key === 'value')
 			{
 				$val = form_prep($val, $default['name']);
 			}
 
-			$att .= $key . '="' . $val . '" ';
+			$att .= $key.'="'.$val.'" ';
 		}
 
 		return $att;
@@ -943,28 +924,27 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Attributes To String
- *
- * Helper function used by some of the form helpers
- *
- * @access	private
- * @param	mixed
- * @param	bool
- * @return	string
- */
 if ( ! function_exists('_attributes_to_string'))
 {
+	/**
+	 * Attributes To String
+	 *
+	 * Helper function used by some of the form helpers
+	 *
+	 * @param	mixed
+	 * @param	bool
+	 * @return	string
+	 */
 	function _attributes_to_string($attributes, $formtag = FALSE)
 	{
-		if (is_string($attributes) AND strlen($attributes) > 0)
+		if (is_string($attributes) && strlen($attributes) > 0)
 		{
-			if ($formtag == TRUE AND strpos($attributes, 'method=') === FALSE)
+			if ($formtag === TRUE && strpos($attributes, 'method=') === FALSE)
 			{
 				$attributes .= ' method="post"';
 			}
 
-			if ($formtag == TRUE AND strpos($attributes, 'accept-charset=') === FALSE)
+			if ($formtag === TRUE && strpos($attributes, 'accept-charset=') === FALSE)
 			{
 				$attributes .= ' accept-charset="'.strtolower(config_item('charset')).'"';
 			}
@@ -972,21 +952,21 @@
 			return ' '.$attributes;
 		}
 
-		if (is_object($attributes) AND count($attributes) > 0)
+		if (is_object($attributes) && count($attributes) > 0)
 		{
-			$attributes = (array)$attributes;
+			$attributes = (array) $attributes;
 		}
 
-		if (is_array($attributes) AND ($formtag === TRUE OR count($attributes) > 0))
+		if (is_array($attributes) && ($formtag === TRUE OR count($attributes) > 0))
 		{
 			$atts = '';
 
-			if ( ! isset($attributes['method']) AND $formtag === TRUE)
+			if ( ! isset($attributes['method']) && $formtag === TRUE)
 			{
 				$atts .= ' method="post"';
 			}
 
-			if ( ! isset($attributes['accept-charset']) AND $formtag === TRUE)
+			if ( ! isset($attributes['accept-charset']) && $formtag === TRUE)
 			{
 				$atts .= ' accept-charset="'.strtolower(config_item('charset')).'"';
 			}
@@ -1003,17 +983,16 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Validation Object
- *
- * Determines what the form validation class was instantiated as, fetches
- * the object and returns it.
- *
- * @access	private
- * @return	mixed
- */
 if ( ! function_exists('_get_validation_object'))
 {
+	/**
+	 * Validation Object
+	 *
+	 * Determines what the form validation class was instantiated as, fetches
+	 * the object and returns it.
+	 *
+	 * @return	mixed
+	 */
 	function &_get_validation_object()
 	{
 		$CI =& get_instance();
@@ -1036,4 +1015,4 @@
 }
 
 /* End of file form_helper.php */
-/* Location: ./system/helpers/form_helper.php */
+/* Location: ./system/helpers/form_helper.php */
\ No newline at end of file
diff --git a/system/helpers/html_helper.php b/system/helpers/html_helper.php
index 72970d9..68ce702 100644
--- a/system/helpers/html_helper.php
+++ b/system/helpers/html_helper.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * CodeIgniter HTML Helpers
  *
@@ -39,39 +37,37 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Heading
- *
- * Generates an HTML heading tag.  First param is the data.
- * Second param is the size of the heading tag.
- *
- * @access	public
- * @param	string
- * @param	integer
- * @return	string
- */
 if ( ! function_exists('heading'))
 {
+	/**
+	 * Heading
+	 *
+	 * Generates an HTML heading tag.
+	 *
+	 * @param	string	content
+	 * @param	int	heading level
+	 * @param	string
+	 * @return	string
+	 */
 	function heading($data = '', $h = '1', $attributes = '')
 	{
-		return '<h'.$h.($attributes != '' ? ' ' : '').$attributes.'>'.$data.'</h'.$h.'>';
+		return '<h'.$h.($attributes !== '' ? ' ' : '').$attributes.'>'.$data.'</h'.$h.'>';
 	}
 }
 
 // ------------------------------------------------------------------------
 
-/**
- * Unordered List
- *
- * Generates an HTML unordered list from an single or multi-dimensional array.
- *
- * @access	public
- * @param	array
- * @param	mixed
- * @return	string
- */
 if ( ! function_exists('ul'))
 {
+	/**
+	 * Unordered List
+	 *
+	 * Generates an HTML unordered list from an single or multi-dimensional array.
+	 *
+	 * @param	array
+	 * @param	mixed
+	 * @return	string
+	 */
 	function ul($list, $attributes = '')
 	{
 		return _list('ul', $list, $attributes);
@@ -80,18 +76,17 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Ordered List
- *
- * Generates an HTML ordered list from an single or multi-dimensional array.
- *
- * @access	public
- * @param	array
- * @param	mixed
- * @return	string
- */
 if ( ! function_exists('ol'))
 {
+	/**
+	 * Ordered List
+	 *
+	 * Generates an HTML ordered list from an single or multi-dimensional array.
+	 *
+	 * @param	array
+	 * @param	mixed
+	 * @return	string
+	 */
 	function ol($list, $attributes = '')
 	{
 		return _list('ol', $list, $attributes);
@@ -100,20 +95,19 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Generates the list
- *
- * Generates an HTML ordered list from an single or multi-dimensional array.
- *
- * @access	private
- * @param	string
- * @param	mixed
- * @param	mixed
- * @param	integer
- * @return	string
- */
 if ( ! function_exists('_list'))
 {
+	/**
+	 * Generates the list
+	 *
+	 * Generates an HTML ordered list from an single or multi-dimensional array.
+	 *
+	 * @param	string
+	 * @param	mixed
+	 * @param	mixed
+	 * @param	int
+	 * @return	string
+	 */
 	function _list($type = 'ul', $list, $attributes = '', $depth = 0)
 	{
 		// If an array wasn't submitted there's nothing to do...
@@ -131,13 +125,13 @@
 			$atts = '';
 			foreach ($attributes as $key => $val)
 			{
-				$atts .= ' ' . $key . '="' . $val . '"';
+				$atts .= ' '.$key.'="'.$val.'"';
 			}
 			$attributes = $atts;
 		}
-		elseif (is_string($attributes) AND strlen($attributes) > 0)
+		elseif (is_string($attributes) && strlen($attributes) > 0)
 		{
-			$attributes = ' '. $attributes;
+			$attributes = ' '.$attributes;
 		}
 
 		// Write the opening list tag
@@ -172,15 +166,14 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Generates HTML BR tags based on number supplied
- *
- * @access	public
- * @param	integer
- * @return	string
- */
 if ( ! function_exists('br'))
 {
+	/**
+	 * Generates HTML BR tags based on number supplied
+	 *
+	 * @param	int
+	 * @return	string
+	 */
 	function br($num = 1)
 	{
 		return str_repeat('<br />', $num);
@@ -189,17 +182,17 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Image
- *
- * Generates an <img /> element
- *
- * @access	public
- * @param	mixed
- * @return	string
- */
 if ( ! function_exists('img'))
 {
+	/**
+	 * Image
+	 *
+	 * Generates an <img /> element
+	 *
+	 * @param	mixed
+	 * @param	bool
+	 * @return	string
+	 */
 	function img($src = '', $index_page = FALSE)
 	{
 		if ( ! is_array($src) )
@@ -217,7 +210,7 @@
 
 		foreach ($src as $k => $v)
 		{
-			if ($k === 'src' AND strpos($v, '://') === FALSE)
+			if ($k === 'src' && strpos($v, '://') === FALSE)
 			{
 				$CI =& get_instance();
 
@@ -232,7 +225,7 @@
 			}
 			else
 			{
-				$img .= " $k=\"$v\"";
+				$img .= ' '.$k.'="'.$v.'"';
 			}
 		}
 
@@ -242,28 +235,27 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Doctype
- *
- * Generates a page document type declaration
- *
- * Valid options are xhtml-11, xhtml-strict, xhtml-trans, xhtml-frame,
- * html4-strict, html4-trans, and html4-frame.  Values are saved in the
- * doctypes config file.
- *
- * @access	public
- * @param	string	type	The doctype to be generated
- * @return	string
- */
 if ( ! function_exists('doctype'))
 {
+	/**
+	 * Doctype
+	 *
+	 * Generates a page document type declaration
+	 *
+	 * Valid options are xhtml-11, xhtml-strict, xhtml-trans, xhtml-frame,
+	 * html4-strict, html4-trans, and html4-frame. Values are saved in the
+	 * doctypes config file.
+	 *
+	 * @param	string	type	The doctype to be generated
+	 * @return	string
+	 */
 	function doctype($type = 'xhtml1-strict')
 	{
 		global $_doctypes;
 
 		if ( ! is_array($_doctypes))
 		{
-			if (defined('ENVIRONMENT') AND is_file(APPPATH.'config/'.ENVIRONMENT.'/doctypes.php'))
+			if (defined('ENVIRONMENT') && is_file(APPPATH.'config/'.ENVIRONMENT.'/doctypes.php'))
 			{
 				include(APPPATH.'config/'.ENVIRONMENT.'/doctypes.php');
 			}
@@ -278,28 +270,27 @@
 			}
 		}
 
-		return (isset($_doctypes[$type])) ? $_doctypes[$type] : FALSE;
+		return isset($_doctypes[$type]) ? $_doctypes[$type] : FALSE;
 	}
 }
 
 // ------------------------------------------------------------------------
 
-/**
- * Link
- *
- * Generates link to a CSS file
- *
- * @access	public
- * @param	mixed	stylesheet hrefs or an array
- * @param	string	rel
- * @param	string	type
- * @param	string	title
- * @param	string	media
- * @param	boolean	should index_page be added to the css path
- * @return	string
- */
 if ( ! function_exists('link_tag'))
 {
+	/**
+	 * Link
+	 *
+	 * Generates link to a CSS file
+	 *
+	 * @param	mixed	stylesheet hrefs or an array
+	 * @param	string	rel
+	 * @param	string	type
+	 * @param	string	title
+	 * @param	string	media
+	 * @param	bool	should index_page be added to the css path
+	 * @return	string
+	 */
 	function link_tag($href = '', $rel = 'stylesheet', $type = 'text/css', $title = '', $media = '', $index_page = FALSE)
 	{
 		$CI =& get_instance();
@@ -309,7 +300,7 @@
 		{
 			foreach ($href as $k => $v)
 			{
-				if ($k === 'href' AND strpos($v, '://') === FALSE)
+				if ($k === 'href' && strpos($v, '://') === FALSE)
 				{
 					if ($index_page === TRUE)
 					{
@@ -322,11 +313,9 @@
 				}
 				else
 				{
-					$link .= "$k=\"$v\" ";
+					$link .= $k.'="'.$v.'" ';
 				}
 			}
-
-			$link .= '/>';
 		}
 		else
 		{
@@ -345,34 +334,34 @@
 
 			$link .= 'rel="'.$rel.'" type="'.$type.'" ';
 
-			if ($media != '')
+			if ($media !== '')
 			{
 				$link .= 'media="'.$media.'" ';
 			}
 
-			if ($title != '')
+			if ($title !== '')
 			{
 				$link .= 'title="'.$title.'" ';
 			}
-
-			$link .= '/>';
 		}
 
-		return $link."\n";
+		return $link."/>\n";
 	}
 }
 
 // ------------------------------------------------------------------------
 
-/**
- * Generates meta tags from an array of key/values
- *
- * @access	public
- * @param	array
- * @return	string
- */
 if ( ! function_exists('meta'))
 {
+	/**
+	 * Generates meta tags from an array of key/values
+	 *
+	 * @param	array
+	 * @param	string
+	 * @param	string
+	 * @param	string
+	 * @return	string
+	 */
 	function meta($name = '', $content = '', $type = 'name', $newline = "\n")
 	{
 		// Since we allow the data to be passes as a string, a simple array
@@ -381,22 +370,19 @@
 		{
 			$name = array(array('name' => $name, 'content' => $content, 'type' => $type, 'newline' => $newline));
 		}
-		else
+		elseif (isset($name['name']))
 		{
 			// Turn single array into multidimensional
-			if (isset($name['name']))
-			{
-				$name = array($name);
-			}
+			$name = array($name);
 		}
 
 		$str = '';
 		foreach ($name as $meta)
 		{
-			$type		= ( ! isset($meta['type']) OR $meta['type'] == 'name') ? 'name' : 'http-equiv';
-			$name		= ( ! isset($meta['name']))		? ''	: $meta['name'];
-			$content	= ( ! isset($meta['content']))	? ''	: $meta['content'];
-			$newline	= ( ! isset($meta['newline']))	? "\n"	: $meta['newline'];
+			$type		= ( ! isset($meta['type']) OR $meta['type'] === 'name') ? 'name' : 'http-equiv';
+			$name		= isset($meta['name'])					? $meta['name'] : '';
+			$content	= isset($meta['content'])				? $meta['content'] : '';
+			$newline	= isset($meta['newline'])				? $meta['newline'] : "\n";
 
 			$str .= '<meta '.$type.'="'.$name.'" content="'.$content.'" />'.$newline;
 		}
@@ -407,15 +393,14 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Generates non-breaking space entities based on number supplied
- *
- * @access	public
- * @param	integer
- * @return	string
- */
 if ( ! function_exists('nbs'))
 {
+	/**
+	 * Generates non-breaking space entities based on number supplied
+	 *
+	 * @param	int
+	 * @return	string
+	 */
 	function nbs($num = 1)
 	{
 		return str_repeat('&nbsp;', $num);
@@ -423,4 +408,4 @@
 }
 
 /* End of file html_helper.php */
-/* Location: ./system/helpers/html_helper.php */
+/* Location: ./system/helpers/html_helper.php */
\ No newline at end of file
diff --git a/system/helpers/inflector_helper.php b/system/helpers/inflector_helper.php
index 0bd1e11..647d840 100644
--- a/system/helpers/inflector_helper.php
+++ b/system/helpers/inflector_helper.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * CodeIgniter Inflector Helpers
  *
@@ -34,137 +32,160 @@
  * @subpackage	Helpers
  * @category	Helpers
  * @author		EllisLab Dev Team
- * @link		http://codeigniter.com/user_guide/helpers/directory_helper.html
+ * @link		http://codeigniter.com/user_guide/helpers/inflector_helper.html
  */
 
-
 // --------------------------------------------------------------------
 
-/**
- * Singular
- *
- * Takes a plural word and makes it singular
- *
- * @access	public
- * @param	string
- * @return	str
- */
 if ( ! function_exists('singular'))
 {
+	/**
+	 * Singular
+	 *
+	 * Takes a plural word and makes it singular
+	 *
+	 * @param	string
+	 * @return	string
+	 */
 	function singular($str)
 	{
 		$result = strval($str);
 
+		if ( ! is_countable($result))
+		{
+			return $result;
+		}
+
 		$singular_rules = array(
-			'/(matr)ices$/'			=> '\1ix',
-			'/(vert|ind)ices$/'		=> '\1ex',
-			'/^(ox)en/'				=> '\1',
-			'/(alias)es$/'			=> '\1',
-			'/([octop|vir])i$/'		=> '\1us',
-			'/(cris|ax|test)es$/'	=> '\1is',
-			'/(shoe)s$/'			=> '\1',
-			'/(o)es$/'				=> '\1',
-			'/(bus|campus)es$/'		=> '\1',
-			'/([m|l])ice$/'			=> '\1ouse',
-			'/(x|ch|ss|sh)es$/'		=> '\1',
-			'/(m)ovies$/'			=> '\1\2ovie',
-			'/(s)eries$/'			=> '\1\2eries',
-			'/([^aeiouy]|qu)ies$/'	=> '\1y',
-			'/([lr])ves$/'			=> '\1f',
-			'/(tive)s$/'			=> '\1',
-			'/(hive)s$/'			=> '\1',
-			'/([^f])ves$/'			=> '\1fe',
-			'/(^analy)ses$/'		=> '\1sis',
+			'/(matr)ices$/'         => '\1ix',
+			'/(vert|ind)ices$/'     => '\1ex',
+			'/^(ox)en/'             => '\1',
+			'/(alias)es$/'          => '\1',
+			'/([octop|vir])i$/'     => '\1us',
+			'/(cris|ax|test)es$/'   => '\1is',
+			'/(shoe)s$/'            => '\1',
+			'/(o)es$/'              => '\1',
+			'/(bus|campus)es$/'     => '\1',
+			'/([m|l])ice$/'         => '\1ouse',
+			'/(x|ch|ss|sh)es$/'     => '\1',
+			'/(m)ovies$/'           => '\1\2ovie',
+			'/(s)eries$/'           => '\1\2eries',
+			'/([^aeiouy]|qu)ies$/'  => '\1y',
+			'/([lr])ves$/'          => '\1f',
+			'/(tive)s$/'            => '\1',
+			'/(hive)s$/'            => '\1',
+			'/([^f])ves$/'          => '\1fe',
+			'/(^analy)ses$/'        => '\1sis',
 			'/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/' => '\1\2sis',
-			'/([ti])a$/'			=> '\1um',
-			'/(p)eople$/'			=> '\1\2erson',
-			'/(m)en$/'				=> '\1an',
-			'/(s)tatuses$/'			=> '\1\2tatus',
-			'/(c)hildren$/'			=> '\1\2hild',
-			'/(n)ews$/'				=> '\1\2ews',
-			'/([^u])s$/'			=> '\1',
+			'/([ti])a$/'            => '\1um',
+			'/(p)eople$/'           => '\1\2erson',
+			'/(m)en$/'              => '\1an',
+			'/(s)tatuses$/'         => '\1\2tatus',
+			'/(c)hildren$/'         => '\1\2hild',
+			'/(n)ews$/'             => '\1\2ews',
+			'/([^us])s$/'           => '\1',
 		);
 
-		return preg_replace(array_keys($singular_values), $singular_values, $result);
+		foreach ($singular_rules as $rule => $replacement)
+		{
+			if (preg_match($rule, $result))
+			{
+				$result = preg_replace($rule, $replacement, $result);
+				break;
+			}
+		}
+
+		return $result;
 	}
 }
 
 // --------------------------------------------------------------------
 
-/**
- * Plural
- *
- * Takes a singular word and makes it plural
- *
- * @access	public
- * @param	string
- * @param	bool
- * @return	str
- */
 if ( ! function_exists('plural'))
 {
+	/**
+	 * Plural
+	 *
+	 * Takes a singular word and makes it plural
+	 *
+	 * @param	string
+	 * @param	bool
+	 * @return	string
+	 */
 	function plural($str, $force = FALSE)
 	{
 		$result = strval($str);
 
+		if ( ! is_countable($result))
+		{
+			return $result;
+		}
+
 		$plural_rules = array(
-			'/^(ox)$/'					=> '\1\2en',	 // ox
-			'/([m|l])ouse$/'			=> '\1ice',	  // mouse, louse
-			'/(matr|vert|ind)ix|ex$/'	=> '\1ices',	 // matrix, vertex, index
-			'/(x|ch|ss|sh)$/'			=> '\1es',	   // search, switch, fix, box, process, address
-			'/([^aeiouy]|qu)y$/'		=> '\1ies',	  // query, ability, agency
-			'/(hive)$/'					=> '\1s',		// archive, hive
-			'/(?:([^f])fe|([lr])f)$/'	=> '\1\2ves',	// half, safe, wife
-			'/sis$/'					=> 'ses',		// basis, diagnosis
-			'/([ti])um$/'				=> '\1a',		// datum, medium
-			'/(p)erson$/'				=> '\1eople',	// person, salesperson
-			'/(m)an$/'					=> '\1en',	   // man, woman, spokesman
-			'/(c)hild$/'				=> '\1hildren',  // child
-			'/(buffal|tomat)o$/'		=> '\1\2oes',	// buffalo, tomato
-			'/(bu|campu)s$/'			=> '\1\2ses',	// bus, campus
-			'/(alias|status|virus)/'	=> '\1es',	   // alias
-			'/(octop)us$/'				=> '\1i',		// octopus
-			'/(ax|cris|test)is$/'		=> '\1es',	   // axis, crisis
-			'/s$/'						=> 's',		  // no change (compatibility)
-			'/$/'						=> 's',
+			'/^(ox)$/'                 => '\1\2en',     // ox
+			'/([m|l])ouse$/'           => '\1ice',      // mouse, louse
+			'/(matr|vert|ind)ix|ex$/'  => '\1ices',     // matrix, vertex, index
+			'/(x|ch|ss|sh)$/'          => '\1es',       // search, switch, fix, box, process, address
+			'/([^aeiouy]|qu)y$/'       => '\1ies',      // query, ability, agency
+			'/(hive)$/'                => '\1s',        // archive, hive
+			'/(?:([^f])fe|([lr])f)$/'  => '\1\2ves',    // half, safe, wife
+			'/sis$/'                   => 'ses',        // basis, diagnosis
+			'/([ti])um$/'              => '\1a',        // datum, medium
+			'/(p)erson$/'              => '\1eople',    // person, salesperson
+			'/(m)an$/'                 => '\1en',       // man, woman, spokesman
+			'/(c)hild$/'               => '\1hildren',  // child
+			'/(buffal|tomat)o$/'       => '\1\2oes',    // buffalo, tomato
+			'/(bu|campu)s$/'           => '\1\2ses',    // bus, campus
+			'/(alias|status|virus)$/'  => '\1es',       // alias
+			'/(octop)us$/'             => '\1i',        // octopus
+			'/(ax|cris|test)is$/'      => '\1es',       // axis, crisis
+			'/s$/'                     => 's',          // no change (compatibility)
+			'/$/'                      => 's',
 		);
 
-		return preg_replace(array_keys($plural_rules), $plural_rules, $result);
+		foreach ($plural_rules as $rule => $replacement)
+		{
+			if (preg_match($rule, $result))
+			{
+				$result = preg_replace($rule, $replacement, $result);
+				break;
+			}
+		}
+
+		return $result;
 	}
 }
 
 // --------------------------------------------------------------------
 
-/**
- * Camelize
- *
- * Takes multiple words separated by spaces or underscores and camelizes them
- *
- * @access	public
- * @param	string
- * @return	str
- */
 if ( ! function_exists('camelize'))
 {
+	/**
+	 * Camelize
+	 *
+	 * Takes multiple words separated by spaces or underscores and camelizes them
+	 *
+	 * @param	string
+	 * @return	string
+	 */
 	function camelize($str)
 	{
-		return substr(str_replace(' ', '', ucwords(preg_replace('/[\s_]+/', ' ', $str))), 1);
+		return strtolower($str[0]).substr(str_replace(' ', '', ucwords(preg_replace('/[\s_]+/', ' ', $str))), 1);
 	}
 }
 
 // --------------------------------------------------------------------
 
-/**
- * Underscore
- *
- * Takes multiple words separated by spaces and underscores them
- *
- * @access	public
- * @param	string
- * @return	str
- */
 if ( ! function_exists('underscore'))
 {
+	/**
+	 * Underscore
+	 *
+	 * Takes multiple words separated by spaces and underscores them
+	 *
+	 * @param	string
+	 * @return	string
+	 */
 	function underscore($str)
 	{
 		return preg_replace('/[\s]+/', '_', strtolower(trim($str)));
@@ -173,23 +194,43 @@
 
 // --------------------------------------------------------------------
 
-/**
- * Humanize
- *
- * Takes multiple words separated by the separator and changes them to spaces
- *
- * @access	public
- * @param	string $str
- * @param 	string $separator
- * @return	str
- */
 if ( ! function_exists('humanize'))
 {
+	/**
+	 * Humanize
+	 *
+	 * Takes multiple words separated by the separator and changes them to spaces
+	 *
+	 * @param	string	$str
+	 * @param 	string	$separator
+	 * @return	string
+	 */
 	function humanize($str, $separator = '_')
 	{
 		return ucwords(preg_replace('/['.$separator.']+/', ' ', strtolower(trim($str))));
 	}
 }
 
+// --------------------------------------------------------------------
+
+if ( ! function_exists('is_countable'))
+{
+	/**
+	 * Checks if the given word has a plural version.
+	 *
+	 * @param	string	the word to check
+	 * @return	bool	if the word is countable
+	 */
+	function is_countable($word)
+	{
+		return ! in_array(strtolower(strval($word)),
+					array(
+						'equipment', 'information', 'rice', 'money',
+						'species', 'series', 'fish', 'meta'
+					)
+			);
+	}
+}
+
 /* End of file inflector_helper.php */
-/* Location: ./system/helpers/inflector_helper.php */
+/* Location: ./system/helpers/inflector_helper.php */
\ No newline at end of file
diff --git a/system/helpers/language_helper.php b/system/helpers/language_helper.php
index a83580a..bd567ed 100644
--- a/system/helpers/language_helper.php
+++ b/system/helpers/language_helper.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * CodeIgniter Language Helpers
  *
@@ -39,26 +37,25 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Lang
- *
- * Fetches a language variable and optionally outputs a form label
- *
- * @access	public
- * @param	string	the language line
- * @param	string	the id of the form element
- * @return	string
- */
 if ( ! function_exists('lang'))
 {
+	/**
+	 * Lang
+	 *
+	 * Fetches a language variable and optionally outputs a form label
+	 *
+	 * @param	string	the language line
+	 * @param	string	the id of the form element
+	 * @return	string
+	 */
 	function lang($line, $id = '')
 	{
 		$CI =& get_instance();
 		$line = $CI->lang->line($line);
 
-		if ($id != '')
+		if ($id !== '')
 		{
-			$line = '<label for="'.$id.'">'.$line."</label>";
+			$line = '<label for="'.$id.'">'.$line.'</label>';
 		}
 
 		return $line;
@@ -66,4 +63,4 @@
 }
 
 /* End of file language_helper.php */
-/* Location: ./system/helpers/language_helper.php */
+/* Location: ./system/helpers/language_helper.php */
\ No newline at end of file
diff --git a/system/helpers/number_helper.php b/system/helpers/number_helper.php
index 331b468..e49f2f7 100644
--- a/system/helpers/number_helper.php
+++ b/system/helpers/number_helper.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * CodeIgniter Number Helpers
  *
@@ -39,15 +37,15 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Formats a numbers as bytes, based on size, and adds the appropriate suffix
- *
- * @access	public
- * @param	mixed	// will be cast as int
- * @return	string
- */
 if ( ! function_exists('byte_format'))
 {
+	/**
+	 * Formats a numbers as bytes, based on size, and adds the appropriate suffix
+	 *
+	 * @param	mixed	will be cast as int
+	 * @param	int
+	 * @return	string
+	 */
 	function byte_format($num, $precision = 1)
 	{
 		$CI =& get_instance();
@@ -84,4 +82,4 @@
 }
 
 /* End of file number_helper.php */
-/* Location: ./system/helpers/number_helper.php */
+/* Location: ./system/helpers/number_helper.php */
\ No newline at end of file
diff --git a/system/helpers/path_helper.php b/system/helpers/path_helper.php
index cd87a73..fec4a1a 100644
--- a/system/helpers/path_helper.php
+++ b/system/helpers/path_helper.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * CodeIgniter Path Helpers
  *
@@ -39,42 +37,37 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Set Realpath
- *
- * @access	public
- * @param	string
- * @param	bool	checks to see if the path exists
- * @return	string
- */
 if ( ! function_exists('set_realpath'))
 {
+	/**
+	 * Set Realpath
+	 *
+	 * @param	string
+	 * @param	bool	checks to see if the path exists
+	 * @return	string
+	 */
 	function set_realpath($path, $check_existance = FALSE)
 	{
-		// Security check to make sure the path is NOT a URL.  No remote file inclusion!
-		if (preg_match("#^(http:\/\/|https:\/\/|www\.|ftp|[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})#i", $path))
+		// Security check to make sure the path is NOT a URL. No remote file inclusion!
+		if (preg_match('#^(http:\/\/|https:\/\/|www\.|ftp|[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})#i', $path))
 		{
 			show_error('The path you submitted must be a local server path, not a URL');
 		}
 
 		// Resolve the path
-		if (function_exists('realpath') AND @realpath($path) !== FALSE)
+		if (@realpath($path) !== FALSE)
 		{
 			$path = realpath($path);
 		}
-
-		// Add a trailing slash
-		$path = rtrim($path, DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR;
-
-		// Make sure the path exists
-		if ($check_existance == TRUE && ! is_dir($path))
+		elseif ($check_existance && ! is_dir($path) && ! is_file($path))
 		{
 			show_error('Not a valid path: '.$path);
 		}
 
-		return $path;
+		// Add a trailing slash, if this is a directory
+		return is_dir($path) ? rtrim($path, DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR : $path;
 	}
 }
 
 /* End of file path_helper.php */
-/* Location: ./system/helpers/path_helper.php */
+/* Location: ./system/helpers/path_helper.php */
\ No newline at end of file
diff --git a/system/helpers/security_helper.php b/system/helpers/security_helper.php
index 99fda56..3e6e914 100644
--- a/system/helpers/security_helper.php
+++ b/system/helpers/security_helper.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * CodeIgniter Security Helpers
  *
@@ -39,16 +37,15 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * XSS Filtering
- *
- * @access	public
- * @param	string
- * @param	bool	whether or not the content is an image file
- * @return	string
- */
 if ( ! function_exists('xss_clean'))
 {
+	/**
+	 * XSS Filtering
+	 *
+	 * @param	string
+	 * @param	bool	whether or not the content is an image file
+	 * @return	string
+	 */
 	function xss_clean($str, $is_image = FALSE)
 	{
 		$CI =& get_instance();
@@ -58,15 +55,14 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Sanitize Filename
- *
- * @access	public
- * @param	string
- * @return	string
- */
 if ( ! function_exists('sanitize_filename'))
 {
+	/**
+	 * Sanitize Filename
+	 *
+	 * @param	string
+	 * @return	string
+	 */
 	function sanitize_filename($filename)
 	{
 		$CI =& get_instance();
@@ -76,49 +72,55 @@
 
 // --------------------------------------------------------------------
 
-/**
- * Hash encode a string
- *
- * @access	public
- * @param	string
- * @return	string
- */
 if ( ! function_exists('do_hash'))
 {
+	/**
+	 * Hash encode a string
+	 *
+	 * This function is DEPRECATED and should be removed in
+	 * CodeIgniter 3.1+. Use hash() instead.
+	 *
+	 * @param	string
+	 * @param	string
+	 * @return	string
+	 */
 	function do_hash($str, $type = 'sha1')
 	{
-		return ($type === 'sha1') ? sha1($str) : md5($str);
+		if ( ! in_array(strtolower($type), hash_algos()))
+		{
+			$type = 'md5';
+		}
+
+		return hash($type, $str);
 	}
 }
 
 // ------------------------------------------------------------------------
 
-/**
- * Strip Image Tags
- *
- * @access	public
- * @param	string
- * @return	string
- */
 if ( ! function_exists('strip_image_tags'))
 {
+	/**
+	 * Strip Image Tags
+	 *
+	 * @param	string
+	 * @return	string
+	 */
 	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);
 	}
 }
 
 // ------------------------------------------------------------------------
 
-/**
- * Convert PHP tags to entities
- *
- * @access	public
- * @param	string
- * @return	string
- */
 if ( ! function_exists('encode_php_tags'))
 {
+	/**
+	 * Convert PHP tags to entities
+	 *
+	 * @param	string
+	 * @return	string
+	 */
 	function encode_php_tags($str)
 	{
 		return str_replace(array('<?php', '<?PHP', '<?', '?>'),  array('&lt;?php', '&lt;?PHP', '&lt;?', '?&gt;'), $str);
@@ -126,4 +128,4 @@
 }
 
 /* End of file security_helper.php */
-/* Location: ./system/helpers/security_helper.php */
+/* Location: ./system/helpers/security_helper.php */
\ No newline at end of file
diff --git a/system/helpers/smiley_helper.php b/system/helpers/smiley_helper.php
index 700f448..b6b2afc 100644
--- a/system/helpers/smiley_helper.php
+++ b/system/helpers/smiley_helper.php
@@ -1,13 +1,13 @@
-<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
- * 
+ *
  * Licensed under the Open Software License version 3.0
- * 
+ *
  * This source file is subject to the Open Software License (OSL 3.0) that is
  * bundled with this package in the files license.txt / license.rst.  It is
  * also available through the world wide web at this URL:
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * CodeIgniter Smiley Helpers
  *
@@ -39,127 +37,112 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Smiley Javascript
- *
- * Returns the javascript required for the smiley insertion.  Optionally takes
- * an array of aliases to loosely couple the smiley array to the view.
- *
- * @access	public
- * @param	mixed	alias name or array of alias->field_id pairs
- * @param	string	field_id if alias name was passed in
- * @return	array
- */
 if ( ! function_exists('smiley_js'))
 {
+	/**
+	 * Smiley Javascript
+	 *
+	 * Returns the javascript required for the smiley insertion.  Optionally takes
+	 * an array of aliases to loosely couple the smiley array to the view.
+	 *
+	 * @param	mixed	alias name or array of alias->field_id pairs
+	 * @param	string	field_id if alias name was passed in
+	 * @param	bool
+	 * @return	array
+	 */
 	function smiley_js($alias = '', $field_id = '', $inline = TRUE)
 	{
 		static $do_setup = TRUE;
-
 		$r = '';
 
-		if ($alias != '' && ! is_array($alias))
+		if ($alias !== '' && ! is_array($alias))
 		{
 			$alias = array($alias => $field_id);
 		}
 
 		if ($do_setup === TRUE)
 		{
-				$do_setup = FALSE;
+			$do_setup = FALSE;
+			$m = array();
 
-				$m = array();
-
-				if (is_array($alias))
-				{
-					foreach ($alias as $name => $id)
-					{
-						$m[] = '"'.$name.'" : "'.$id.'"';
-					}
-				}
-
-				$m = '{'.implode(',', $m).'}';
-
-				$r .= <<<EOF
-				var smiley_map = {$m};
-
-				function insert_smiley(smiley, field_id) {
-					var el = document.getElementById(field_id), newStart;
-
-					if ( ! el && smiley_map[field_id]) {
-						el = document.getElementById(smiley_map[field_id]);
-
-						if ( ! el)
-							return false;
-					}
-
-					el.focus();
-					smiley = " " + smiley;
-
-					if ('selectionStart' in el) {
-						newStart = el.selectionStart + smiley.length;
-
-						el.value = el.value.substr(0, el.selectionStart) +
-										smiley +
-										el.value.substr(el.selectionEnd, el.value.length);
-						el.setSelectionRange(newStart, newStart);
-					}
-					else if (document.selection) {
-						document.selection.createRange().text = smiley;
-					}
-				}
-EOF;
-		}
-		else
-		{
 			if (is_array($alias))
 			{
 				foreach ($alias as $name => $id)
 				{
-					$r .= 'smiley_map["'.$name.'"] = "'.$id.'";'."\n";
+					$m[] = '"'.$name.'" : "'.$id.'"';
 				}
 			}
+
+			$m = '{'.implode(',', $m).'}';
+
+			$r .= <<<EOF
+			var smiley_map = {$m};
+
+			function insert_smiley(smiley, field_id) {
+				var el = document.getElementById(field_id), newStart;
+
+				if ( ! el && smiley_map[field_id]) {
+					el = document.getElementById(smiley_map[field_id]);
+
+					if ( ! el)
+						return false;
+				}
+
+				el.focus();
+				smiley = " " + smiley;
+
+				if ('selectionStart' in el) {
+					newStart = el.selectionStart + smiley.length;
+
+					el.value = el.value.substr(0, el.selectionStart) +
+									smiley +
+									el.value.substr(el.selectionEnd, el.value.length);
+					el.setSelectionRange(newStart, newStart);
+				}
+				else if (document.selection) {
+					document.selection.createRange().text = smiley;
+				}
+			}
+EOF;
+		}
+		elseif (is_array($alias))
+		{
+			foreach ($alias as $name => $id)
+			{
+				$r .= 'smiley_map["'.$name.'"] = "'.$id."\";\n";
+			}
 		}
 
-		if ($inline)
-		{
-			return '<script type="text/javascript" charset="utf-8">/*<![CDATA[ */'.$r.'// ]]></script>';
-		}
-		else
-		{
-			return $r;
-		}
+		return ($inline) ? '<script type="text/javascript" charset="utf-8">/*<![CDATA[ */'.$r.'// ]]></script>' : $r;
 	}
 }
 
 // ------------------------------------------------------------------------
 
-/**
- * Get Clickable Smileys
- *
- * Returns an array of image tag links that can be clicked to be inserted
- * into a form field.
- *
- * @access	public
- * @param	string	the URL to the folder containing the smiley images
- * @return	array
- */
+
 if ( ! function_exists('get_clickable_smileys'))
 {
+	/**
+	 * Get Clickable Smileys
+	 *
+	 * Returns an array of image tag links that can be clicked to be inserted
+	 * into a form field.
+	 *
+	 * @param	string	the URL to the folder containing the smiley images
+	 * @param	array
+	 * @param	array
+	 * @return	array
+	 */
 	function get_clickable_smileys($image_url, $alias = '', $smileys = NULL)
 	{
 		// For backward compatibility with js_insert_smiley
-
 		if (is_array($alias))
 		{
 			$smileys = $alias;
 		}
-
-		if ( ! is_array($smileys))
+		elseif (FALSE === ($smileys = _get_smiley_array()))
 		{
-			if (FALSE === ($smileys = _get_smiley_array()))
-			{
-				return $smileys;
-			}
+			return $smileys;
 		}
 
 		// Add a trailing slash to the file path if needed
@@ -169,7 +152,7 @@
 		foreach ($smileys as $key => $val)
 		{
 			// Keep duplicates from being used, which can happen if the
-			// mapping array contains multiple identical replacements.  For example:
+			// mapping array contains multiple identical replacements. For example:
 			// :-) and :) might be replaced with the same image so both smileys
 			// will be in the array.
 			if (isset($used[$smileys[$key][0]]))
@@ -177,8 +160,7 @@
 				continue;
 			}
 
-			$link[] = "<a href=\"javascript:void(0);\" onclick=\"insert_smiley('".$key."', '".$alias."')\"><img src=\"".$image_url.$smileys[$key][0]."\" width=\"".$smileys[$key][1]."\" height=\"".$smileys[$key][2]."\" alt=\"".$smileys[$key][3]."\" style=\"border:0;\" /></a>";
-
+			$link[] = '<a href="javascript:void(0);" onclick="insert_smiley(\''.$key.'\', \''.$alias.'\')"><img src="'.$image_url.$smileys[$key][0].'" alt="'.$smileys[$key][3].'" style="width: '.$smileys[$key][1].'; height: '.$smileys[$key][2].'; border: 0;" /></a>';
 			$used[$smileys[$key][0]] = TRUE;
 		}
 
@@ -188,39 +170,31 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Parse Smileys
- *
- * Takes a string as input and swaps any contained smileys for the actual image
- *
- * @access	public
- * @param	string	the text to be parsed
- * @param	string	the URL to the folder containing the smiley images
- * @return	string
- */
 if ( ! function_exists('parse_smileys'))
 {
+	/**
+	 * Parse Smileys
+	 *
+	 * Takes a string as input and swaps any contained smileys for the actual image
+	 *
+	 * @param	string	the text to be parsed
+	 * @param	string	the URL to the folder containing the smiley images
+	 * @param	array
+	 * @return	string
+	 */
 	function parse_smileys($str = '', $image_url = '', $smileys = NULL)
 	{
-		if ($image_url == '')
+		if ($image_url === '' OR ( ! is_array($smileys) && FALSE === ($smileys = _get_smiley_array())))
 		{
 			return $str;
 		}
 
-		if ( ! is_array($smileys))
-		{
-			if (FALSE === ($smileys = _get_smiley_array()))
-			{
-				return $str;
-			}
-		}
-
 		// Add a trailing slash to the file path if needed
-		$image_url = preg_replace("/(.+?)\/*$/", "\\1/",  $image_url);
+		$image_url = rtrim($image_url, '/').'/';
 
 		foreach ($smileys as $key => $val)
 		{
-			$str = str_replace($key, "<img src=\"".$image_url.$smileys[$key][0]."\" width=\"".$smileys[$key][1]."\" height=\"".$smileys[$key][2]."\" alt=\"".$smileys[$key][3]."\" style=\"border:0;\" />", $str);
+			$str = str_replace($key, '<img src="'.$image_url.$smileys[$key][0].'" alt="'.$smileys[$key][3].'" style="width: '.$smileys[$key][1].'; height: '.$smileys[$key][2].'; border: 0;" />', $str);
 		}
 
 		return $str;
@@ -229,19 +203,18 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Get Smiley Array
- *
- * Fetches the config/smiley.php file
- *
- * @access	private
- * @return	mixed
- */
 if ( ! function_exists('_get_smiley_array'))
 {
+	/**
+	 * Get Smiley Array
+	 *
+	 * Fetches the config/smiley.php file
+	 *
+	 * @return	mixed
+	 */
 	function _get_smiley_array()
 	{
-		if (defined('ENVIRONMENT') AND file_exists(APPPATH.'config/'.ENVIRONMENT.'/smileys.php'))
+		if (defined('ENVIRONMENT') && file_exists(APPPATH.'config/'.ENVIRONMENT.'/smileys.php'))
 		{
 			include(APPPATH.'config/'.ENVIRONMENT.'/smileys.php');
 		}
@@ -249,45 +222,10 @@
 		{
 			include(APPPATH.'config/smileys.php');
 		}
-		
-		if (isset($smileys) AND is_array($smileys))
-		{
-			return $smileys;
-		}
 
-		return FALSE;
+		return (isset($smileys) && is_array($smileys)) ? $smileys : FALSE;
 	}
 }
 
-// ------------------------------------------------------------------------
-
-/**
- * JS Insert Smiley
- *
- * Generates the javascript function needed to insert smileys into a form field
- *
- * DEPRECATED as of version 1.7.2, use smiley_js instead
- *
- * @access	public
- * @param	string	form name
- * @param	string	field name
- * @return	string
- */
-if ( ! function_exists('js_insert_smiley'))
-{
-	function js_insert_smiley($form_name = '', $form_field = '')
-	{
-		return <<<EOF
-<script type="text/javascript">
-	function insert_smiley(smiley)
-	{
-		document.{$form_name}.{$form_field}.value += " " + smiley;
-	}
-</script>
-EOF;
-	}
-}
-
-
 /* End of file smiley_helper.php */
 /* Location: ./system/helpers/smiley_helper.php */
\ No newline at end of file
diff --git a/system/helpers/string_helper.php b/system/helpers/string_helper.php
index 04d51c2..4eee2a2 100644
--- a/system/helpers/string_helper.php
+++ b/system/helpers/string_helper.php
@@ -1,13 +1,13 @@
-<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
- * 
+ *
  * Licensed under the Open Software License version 3.0
- * 
+ *
  * This source file is subject to the Open Software License (OSL 3.0) that is
  * bundled with this package in the files license.txt / license.rst.  It is
  * also available through the world wide web at this URL:
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * CodeIgniter String Helpers
  *
@@ -39,23 +37,22 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Trim Slashes
- *
- * Removes any leading/trailing slashes from a string:
- *
- * /this/that/theother/
- *
- * becomes:
- *
- * this/that/theother
- *
- * @access	public
- * @param	string
- * @return	string
- */
 if ( ! function_exists('trim_slashes'))
 {
+	/**
+	 * Trim Slashes
+	 *
+	 * Removes any leading/trailing slashes from a string:
+	 *
+	 * /this/that/theother/
+	 *
+	 * becomes:
+	 *
+	 * this/that/theother
+	 *
+	 * @param	string
+	 * @return	string
+	 */
 	function trim_slashes($str)
 	{
 		return trim($str, '/');
@@ -64,29 +61,26 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Strip Slashes
- *
- * Removes slashes contained in a string or in an array
- *
- * @access	public
- * @param	mixed	string or array
- * @return	mixed	string or array
- */
 if ( ! function_exists('strip_slashes'))
 {
+	/**
+	 * Strip Slashes
+	 *
+	 * Removes slashes contained in a string or in an array
+	 *
+	 * @param	mixed	string or array
+	 * @return	mixed	string or array
+	 */
 	function strip_slashes($str)
 	{
-		if (is_array($str))
+		if ( ! is_array($str))
 		{
-			foreach ($str as $key => $val)
-			{
-				$str[$key] = strip_slashes($val);
-			}
+			return stripslashes($str);
 		}
-		else
+
+		foreach ($str as $key => $val)
 		{
-			$str = stripslashes($str);
+			$str[$key] = strip_slashes($val);
 		}
 
 		return $str;
@@ -95,17 +89,16 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Strip Quotes
- *
- * Removes single and double quotes from a string
- *
- * @access	public
- * @param	string
- * @return	string
- */
 if ( ! function_exists('strip_quotes'))
 {
+	/**
+	 * Strip Quotes
+	 *
+	 * Removes single and double quotes from a string
+	 *
+	 * @param	string
+	 * @return	string
+	 */
 	function strip_quotes($str)
 	{
 		return str_replace(array('"', "'"), '', $str);
@@ -114,17 +107,16 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Quotes to Entities
- *
- * Converts single and double quotes to entities
- *
- * @access	public
- * @param	string
- * @return	string
- */
 if ( ! function_exists('quotes_to_entities'))
 {
+	/**
+	 * Quotes to Entities
+	 *
+	 * Converts single and double quotes to entities
+	 *
+	 * @param	string
+	 * @return	string
+	 */
 	function quotes_to_entities($str)
 	{
 		return str_replace(array("\'","\"","'",'"'), array("&#39;","&quot;","&#39;","&quot;"), $str);
@@ -133,157 +125,141 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Reduce Double Slashes
- *
- * Converts double slashes in a string to a single slash,
- * except those found in http://
- *
- * http://www.some-site.com//index.php
- *
- * becomes:
- *
- * http://www.some-site.com/index.php
- *
- * @access	public
- * @param	string
- * @return	string
- */
 if ( ! function_exists('reduce_double_slashes'))
 {
+	/**
+	 * Reduce Double Slashes
+	 *
+	 * Converts double slashes in a string to a single slash,
+	 * except those found in http://
+	 *
+	 * http://www.some-site.com//index.php
+	 *
+	 * becomes:
+	 *
+	 * http://www.some-site.com/index.php
+	 *
+	 * @param	string
+	 * @return	string
+	 */
 	function reduce_double_slashes($str)
 	{
-		return preg_replace("#(^|[^:])//+#", "\\1/", $str);
+		return preg_replace('#(^|[^:])//+#', '\\1/', $str);
 	}
 }
 
 // ------------------------------------------------------------------------
 
-/**
- * Reduce Multiples
- *
- * Reduces multiple instances of a particular character.  Example:
- *
- * Fred, Bill,, Joe, Jimmy
- *
- * becomes:
- *
- * Fred, Bill, Joe, Jimmy
- *
- * @access	public
- * @param	string
- * @param	string	the character you wish to reduce
- * @param	bool	TRUE/FALSE - whether to trim the character from the beginning/end
- * @return	string
- */
 if ( ! function_exists('reduce_multiples'))
 {
+	/**
+	 * Reduce Multiples
+	 *
+	 * Reduces multiple instances of a particular character.  Example:
+	 *
+	 * Fred, Bill,, Joe, Jimmy
+	 *
+	 * becomes:
+	 *
+	 * Fred, Bill, Joe, Jimmy
+	 *
+	 * @param	string
+	 * @param	string	the character you wish to reduce
+	 * @param	bool	TRUE/FALSE - whether to trim the character from the beginning/end
+	 * @return	string
+	 */
 	function reduce_multiples($str, $character = ',', $trim = FALSE)
 	{
 		$str = preg_replace('#'.preg_quote($character, '#').'{2,}#', $character, $str);
-
-		if ($trim === TRUE)
-		{
-			$str = trim($str, $character);
-		}
-
-		return $str;
+		return ($trim === TRUE) ? trim($str, $character) : $str;
 	}
 }
 
 // ------------------------------------------------------------------------
 
-/**
- * Create a Random String
- *
- * Useful for generating passwords or hashes.
- *
- * @access	public
- * @param	string	type of random string.  basic, alpha, alunum, numeric, nozero, unique, md5, encrypt and sha1
- * @param	integer	number of characters
- * @return	string
- */
 if ( ! function_exists('random_string'))
 {
+	/**
+	 * Create a Random String
+	 *
+	 * Useful for generating passwords or hashes.
+	 *
+	 * @param	string	type of random string.  basic, alpha, alunum, numeric, nozero, unique, md5, encrypt and sha1
+	 * @param	int	number of characters
+	 * @return	string
+	 */
 	function random_string($type = 'alnum', $len = 8)
 	{
-		switch($type)
+		switch ($type)
 		{
-			case 'basic'	: return mt_rand();
-				break;
-			case 'alnum'	:
-			case 'numeric'	:
-			case 'nozero'	:
-			case 'alpha'	:
-
-					switch ($type)
-					{
-						case 'alpha'	:	$pool = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
-							break;
-						case 'alnum'	:	$pool = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
-							break;
-						case 'numeric'	:	$pool = '0123456789';
-							break;
-						case 'nozero'	:	$pool = '123456789';
-							break;
-					}
-					
-					$str = substr(str_shuffle(str_repeat($pool, ceil($len/strlen($pool)))),0,$len);
-					
-					return $str;
-				break;
-			case 'unique'	:
-			case 'md5'		:
-
-						return md5(uniqid(mt_rand()));
-				break;
-			case 'encrypt'	:
-			case 'sha1'	:
-
-						$CI =& get_instance();
-						$CI->load->helper('security');
-
-						return do_hash(uniqid(mt_rand(), TRUE), 'sha1');
-				break;
+			case 'basic':
+				return mt_rand();
+			case 'alnum':
+			case 'numeric':
+			case 'nozero':
+			case 'alpha':
+				switch ($type)
+				{
+					case 'alpha':
+						$pool = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
+						break;
+					case 'alnum':
+						$pool = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
+						break;
+					case 'numeric':
+						$pool = '0123456789';
+						break;
+					case 'nozero':
+						$pool = '123456789';
+						break;
+				}
+				return substr(str_shuffle(str_repeat($pool, ceil($len / strlen($pool)))), 0, $len);
+			case 'unique':
+			case 'md5':
+				return md5(uniqid(mt_rand()));
+			case 'encrypt':
+			case 'sha1':
+				return sha1(uniqid(mt_rand(), TRUE));
 		}
 	}
 }
 
 // ------------------------------------------------------------------------
 
-/**
- * Add's _1 to a string or increment the ending number to allow _2, _3, etc
- *
- * @param   string  $str  required
- * @param   string  $separator  What should the duplicate number be appended with
- * @param   string  $first  Which number should be used for the first dupe increment
- * @return  string
- */
-function increment_string($str, $separator = '_', $first = 1)
+if ( ! function_exists('increment_string'))
 {
-	preg_match('/(.+)'.$separator.'([0-9]+)$/', $str, $match);
-
-	return isset($match[2]) ? $match[1].$separator.($match[2] + 1) : $str.$separator.$first;
+	/**
+	 * Add's _1 to a string or increment the ending number to allow _2, _3, etc
+	 *
+	 * @param	string	required
+	 * @param	string	What should the duplicate number be appended with
+	 * @param	string	Which number should be used for the first dupe increment
+	 * @return	string
+	 */
+	function increment_string($str, $separator = '_', $first = 1)
+	{
+		preg_match('/(.+)'.$separator.'([0-9]+)$/', $str, $match);
+		return isset($match[2]) ? $match[1].$separator.($match[2] + 1) : $str.$separator.$first;
+	}
 }
 
 // ------------------------------------------------------------------------
 
-/**
- * Alternator
- *
- * Allows strings to be alternated.  See docs...
- *
- * @access	public
- * @param	string (as many parameters as needed)
- * @return	string
- */
 if ( ! function_exists('alternator'))
 {
-	function alternator()
+	/**
+	 * Alternator
+	 *
+	 * Allows strings to be alternated. See docs...
+	 *
+	 * @param	string (as many parameters as needed)
+	 * @return	string
+	 */
+	function alternator($args)
 	{
 		static $i;
 
-		if (func_num_args() == 0)
+		if (func_num_args() === 0)
 		{
 			$i = 0;
 			return '';
@@ -295,22 +271,20 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Repeater function
- *
- * @access	public
- * @param	string
- * @param	integer	number of repeats
- * @return	string
- */
 if ( ! function_exists('repeater'))
 {
+	/**
+	 * Repeater function
+	 *
+	 * @param	string
+	 * @param	int	number of repeats
+	 * @return	string
+	 */
 	function repeater($data, $num = 1)
 	{
-		return (($num > 0) ? str_repeat($data, $num) : '');
+		return ($num > 0) ? str_repeat($data, $num) : '';
 	}
 }
 
-
 /* End of file string_helper.php */
 /* Location: ./system/helpers/string_helper.php */
\ No newline at end of file
diff --git a/system/helpers/text_helper.php b/system/helpers/text_helper.php
index 842a31d..8a1f01b 100644
--- a/system/helpers/text_helper.php
+++ b/system/helpers/text_helper.php
@@ -1,13 +1,13 @@
-<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
- * 
+ *
  * Licensed under the Open Software License version 3.0
- * 
+ *
  * This source file is subject to the Open Software License (OSL 3.0) that is
  * bundled with this package in the files license.txt / license.rst.  It is
  * also available through the world wide web at this URL:
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * CodeIgniter Text Helpers
  *
@@ -39,29 +37,28 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Word Limiter
- *
- * Limits a string to X number of words.
- *
- * @access	public
- * @param	string
- * @param	integer
- * @param	string	the end character. Usually an ellipsis
- * @return	string
- */
 if ( ! function_exists('word_limiter'))
 {
+	/**
+	 * Word Limiter
+	 *
+	 * Limits a string to X number of words.
+	 *
+	 * @param	string
+	 * @param	int
+	 * @param	string	the end character. Usually an ellipsis
+	 * @return	string
+	 */
 	function word_limiter($str, $limit = 100, $end_char = '&#8230;')
 	{
-		if (trim($str) == '')
+		if (trim($str) === '')
 		{
 			return $str;
 		}
 
 		preg_match('/^\s*+(?:\S++\s*+){1,'.(int) $limit.'}/', $str, $matches);
 
-		if (strlen($str) == strlen($matches[0]))
+		if (strlen($str) === strlen($matches[0]))
 		{
 			$end_char = '';
 		}
@@ -72,20 +69,19 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Character Limiter
- *
- * Limits the string based on the character count.  Preserves complete words
- * so the character count may not be exactly as specified.
- *
- * @access	public
- * @param	string
- * @param	integer
- * @param	string	the end character. Usually an ellipsis
- * @return	string
- */
 if ( ! function_exists('character_limiter'))
 {
+	/**
+	 * Character Limiter
+	 *
+	 * Limits the string based on the character count.  Preserves complete words
+	 * so the character count may not be exactly as specified.
+	 *
+	 * @param	string
+	 * @param	int
+	 * @param	string	the end character. Usually an ellipsis
+	 * @return	string
+	 */
 	function character_limiter($str, $n = 500, $end_char = '&#8230;')
 	{
 		if (strlen($str) < $n)
@@ -93,14 +89,14 @@
 			return $str;
 		}
 
-		$str = preg_replace("/\s+/", ' ', str_replace(array("\r\n", "\r", "\n"), ' ', $str));
+		$str = preg_replace('/\s+/', ' ', str_replace(array("\r\n", "\r", "\n"), ' ', $str));
 
 		if (strlen($str) <= $n)
 		{
 			return $str;
 		}
 
-		$out = "";
+		$out = '';
 		foreach (explode(' ', trim($str)) as $val)
 		{
 			$out .= $val.' ';
@@ -108,7 +104,7 @@
 			if (strlen($out) >= $n)
 			{
 				$out = trim($out);
-				return (strlen($out) == strlen($str)) ? $out : $out.$end_char;
+				return (strlen($out) === strlen($str)) ? $out : $out.$end_char;
 			}
 		}
 	}
@@ -116,17 +112,16 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * High ASCII to Entities
- *
- * Converts High ascii text and MS Word special characters to character entities
- *
- * @access	public
- * @param	string
- * @return	string
- */
 if ( ! function_exists('ascii_to_entities'))
 {
+	/**
+	 * High ASCII to Entities
+	 *
+	 * Converts High ascii text and MS Word special characters to character entities
+	 *
+	 * @param	string
+	 * @return	string
+	 */
 	function ascii_to_entities($str)
 	{
 		$count	= 1;
@@ -143,7 +138,7 @@
 					If the $temp array has a value but we have moved on, then it seems only
 					fair that we output that entity and restart $temp before continuing. -Paul
 				*/
-				if (count($temp) == 1)
+				if (count($temp) === 1)
 				{
 					$out  .= '&#'.array_shift($temp).';';
 					$count = 1;
@@ -153,16 +148,18 @@
 			}
 			else
 			{
-				if (count($temp) == 0)
+				if (count($temp) === 0)
 				{
 					$count = ($ordinal < 224) ? 2 : 3;
 				}
 
 				$temp[] = $ordinal;
 
-				if (count($temp) == $count)
+				if (count($temp) === $count)
 				{
-					$number = ($count == 3) ? (($temp['0'] % 16) * 4096) + (($temp['1'] % 64) * 64) + ($temp['2'] % 64) : (($temp['0'] % 32) * 64) + ($temp['1'] % 64);
+					$number = ($count === 3)
+							? (($temp[0] % 16) * 4096) + (($temp[1] % 64) * 64) + ($temp[2] % 64)
+							: (($temp[0] % 32) * 64) + ($temp[1] % 64);
 
 					$out .= '&#'.$number.';';
 					$count = 1;
@@ -177,26 +174,24 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Entities to ASCII
- *
- * Converts character entities back to ASCII
- *
- * @access	public
- * @param	string
- * @param	bool
- * @return	string
- */
 if ( ! function_exists('entities_to_ascii'))
 {
+	/**
+	 * Entities to ASCII
+	 *
+	 * Converts character entities back to ASCII
+	 *
+	 * @param	string
+	 * @param	bool
+	 * @return	string
+	 */
 	function entities_to_ascii($str, $all = TRUE)
 	{
 		if (preg_match_all('/\&#(\d+)\;/', $str, $matches))
 		{
-			for ($i = 0, $s = count($matches['0']); $i < $s; $i++)
+			for ($i = 0, $s = count($matches[0]); $i < $s; $i++)
 			{
-				$digits = $matches['1'][$i];
-
+				$digits = $matches[1][$i];
 				$out = '';
 
 				if ($digits < 128)
@@ -206,25 +201,24 @@
 				}
 				elseif ($digits < 2048)
 				{
-					$out .= chr(192 + (($digits - ($digits % 64)) / 64));
-					$out .= chr(128 + ($digits % 64));
+					$out .= chr(192 + (($digits - ($digits % 64)) / 64)).chr(128 + ($digits % 64));
 				}
 				else
 				{
-					$out .= chr(224 + (($digits - ($digits % 4096)) / 4096));
-					$out .= chr(128 + ((($digits % 4096) - ($digits % 64)) / 64));
-					$out .= chr(128 + ($digits % 64));
+					$out .= chr(224 + (($digits - ($digits % 4096)) / 4096))
+						.chr(128 + ((($digits % 4096) - ($digits % 64)) / 64))
+						.chr(128 + ($digits % 64));
 				}
 
-				$str = str_replace($matches['0'][$i], $out, $str);
+				$str = str_replace($matches[0][$i], $out, $str);
 			}
 		}
 
 		if ($all)
 		{
-			$str = str_replace(array("&amp;", "&lt;", "&gt;", "&quot;", "&apos;", "&#45;"),
-								array("&","<",">","\"", "'", "-"),
-								$str);
+			return str_replace(array('&amp;', '&lt;', '&gt;', '&quot;', '&apos;', '&#45;'),
+						array('&', '<', '>', '"', "'", '-'),
+						$str);
 		}
 
 		return $str;
@@ -233,21 +227,20 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Word Censoring Function
- *
- * Supply a string and an array of disallowed words and any
- * matched words will be converted to #### or to the replacement
- * word you've submitted.
- *
- * @access	public
- * @param	string	the text string
- * @param	string	the array of censoered words
- * @param	string	the optional replacement value
- * @return	string
- */
 if ( ! function_exists('word_censor'))
 {
+	/**
+	 * Word Censoring Function
+	 *
+	 * Supply a string and an array of disallowed words and any
+	 * matched words will be converted to #### or to the replacement
+	 * word you've submitted.
+	 *
+	 * @param	string	the text string
+	 * @param	string	the array of censoered words
+	 * @param	string	the optional replacement value
+	 * @return	string
+	 */
 	function word_censor($str, $censored, $replacement = '')
 	{
 		if ( ! is_array($censored))
@@ -265,7 +258,7 @@
 
 		foreach ($censored as $badword)
 		{
-			if ($replacement != '')
+			if ($replacement !== '')
 			{
 				$str = preg_replace("/({$delim})(".str_replace('\*', '\w*?', preg_quote($badword, '/')).")({$delim})/i", "\\1{$replacement}\\3", $str);
 			}
@@ -281,84 +274,78 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Code Highlighter
- *
- * Colorizes code strings
- *
- * @access	public
- * @param	string	the text string
- * @return	string
- */
 if ( ! function_exists('highlight_code'))
 {
+	/**
+	 * Code Highlighter
+	 *
+	 * Colorizes code strings
+	 *
+	 * @param	string	the text string
+	 * @return	string
+	 */
 	function highlight_code($str)
 	{
-		// The highlight string function encodes and highlights
-		// brackets so we need them to start raw
-		$str = str_replace(array('&lt;', '&gt;'), array('<', '>'), $str);
-
-		// Replace any existing PHP tags to temporary markers so they don't accidentally
-		// break the string out of PHP, and thus, thwart the highlighting.
-
-		$str = str_replace(array('<?', '?>', '<%', '%>', '\\', '</script>'),
-							array('phptagopen', 'phptagclose', 'asptagopen', 'asptagclose', 'backslashtmp', 'scriptclose'), $str);
+		/* The highlight string function encodes and highlights
+		 * brackets so we need them to start raw.
+		 *
+		 * Also replace any existing PHP tags to temporary markers
+		 * so they don't accidentally break the string out of PHP,
+		 * and thus, thwart the highlighting.
+		 */
+		$str = str_replace(array('&lt;', '&gt;', '<?', '?>', '<%', '%>', '\\', '</script>'),
+					array('<', '>', 'phptagopen', 'phptagclose', 'asptagopen', 'asptagclose', 'backslashtmp', 'scriptclose'),
+					$str);
 
 		// The highlight_string function requires that the text be surrounded
 		// by PHP tags, which we will remove later
-		$str = '<?php '.$str.' ?>'; // <?
-
-		// All the magic happens here, baby!
-		$str = highlight_string($str, TRUE);
-
-		// Prior to PHP 5, the highligh function used icky <font> tags
-		// so we'll replace them with <span> tags.
-
-		if (abs(PHP_VERSION) < 5)
-		{
-			$str = str_replace(array('<font ', '</font>'), array('<span ', '</span>'), $str);
-			$str = preg_replace('#color="(.*?)"#', 'style="color: \\1"', $str);
-		}
+		$str = highlight_string('<?php '.$str.' ?>', TRUE);
 
 		// Remove our artificially added PHP, and the syntax highlighting that came with it
-		$str = preg_replace('/<span style="color: #([A-Z0-9]+)">&lt;\?php(&nbsp;| )/i', '<span style="color: #$1">', $str);
-		$str = preg_replace('/(<span style="color: #[A-Z0-9]+">.*?)\?&gt;<\/span>\n<\/span>\n<\/code>/is', "$1</span>\n</span>\n</code>", $str);
-		$str = preg_replace('/<span style="color: #[A-Z0-9]+"\><\/span>/i', '', $str);
+		$str = preg_replace(array(
+						'/<span style="color: #([A-Z0-9]+)">&lt;\?php(&nbsp;| )/i',
+						'/(<span style="color: #[A-Z0-9]+">.*?)\?&gt;<\/span>\n<\/span>\n<\/code>/is',
+						'/<span style="color: #[A-Z0-9]+"\><\/span>/i'
+					),
+					array(
+						'<span style="color: #$1">',
+						"$1</span>\n</span>\n</code>",
+						''
+					),
+					$str);
 
 		// Replace our markers back to PHP tags.
-		$str = str_replace(array('phptagopen', 'phptagclose', 'asptagopen', 'asptagclose', 'backslashtmp', 'scriptclose'),
-							array('&lt;?', '?&gt;', '&lt;%', '%&gt;', '\\', '&lt;/script&gt;'), $str);
-
-		return $str;
+		return str_replace(array('phptagopen', 'phptagclose', 'asptagopen', 'asptagclose', 'backslashtmp', 'scriptclose'),
+					array('&lt;?', '?&gt;', '&lt;%', '%&gt;', '\\', '&lt;/script&gt;'),
+					$str);
 	}
 }
 
 // ------------------------------------------------------------------------
 
-/**
- * Phrase Highlighter
- *
- * Highlights a phrase within a text string
- *
- * @access	public
- * @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
- * @return	string
- */
 if ( ! function_exists('highlight_phrase'))
 {
+	/**
+	 * Phrase Highlighter
+	 *
+	 * 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
+	 * @return	string
+	 */
 	function highlight_phrase($str, $phrase, $tag_open = '<strong>', $tag_close = '</strong>')
 	{
-		if ($str == '')
+		if ($str === '')
 		{
 			return '';
 		}
 
-		if ($phrase != '')
+		if ($phrase !== '')
 		{
-			return preg_replace('/('.preg_quote($phrase, '/').')/i', $tag_open."\\1".$tag_close, $str);
+			return preg_replace('/('.preg_quote($phrase, '/').')/i', $tag_open.'\\1'.$tag_close, $str);
 		}
 
 		return $str;
@@ -367,29 +354,33 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Convert Accented Foreign Characters to ASCII
- *
- * @access	public
- * @param	string	the text string
- * @return	string
- */
 if ( ! function_exists('convert_accented_characters'))
 {
+	/**
+	 * Convert Accented Foreign Characters to ASCII
+	 *
+	 * @param	string	the text string
+	 * @return	string
+	 */
 	function convert_accented_characters($str)
 	{
-		if (defined('ENVIRONMENT') AND is_file(APPPATH.'config/'.ENVIRONMENT.'/foreign_chars.php'))
-		{
-			include(APPPATH.'config/'.ENVIRONMENT.'/foreign_chars.php');
-		}
-		elseif (is_file(APPPATH.'config/foreign_chars.php'))
-		{
-			include(APPPATH.'config/foreign_chars.php');
-		}
+		global $foreign_characters;
 
-		if ( ! isset($foreign_characters))
+		if ( ! isset($foreign_characters) OR ! is_array($foreign_characters))
 		{
-			return $str;
+			if (defined('ENVIRONMENT') && is_file(APPPATH.'config/'.ENVIRONMENT.'/foreign_chars.php'))
+			{
+				include(APPPATH.'config/'.ENVIRONMENT.'/foreign_chars.php');
+			}
+			elseif (is_file(APPPATH.'config/foreign_chars.php'))
+			{
+				include(APPPATH.'config/foreign_chars.php');
+			}
+
+			if ( ! isset($foreign_characters) OR ! is_array($foreign_characters))
+			{
+				return $str;
+			}
 		}
 
 		return preg_replace(array_keys($foreign_characters), array_values($foreign_characters), $str);
@@ -401,25 +392,26 @@
 /**
  * Word Wrap
  *
- * Wraps text at the specified character.  Maintains the integrity of words.
+ * Wraps text at the specified character. Maintains the integrity of words.
  * Anything placed between {unwrap}{/unwrap} will not be word wrapped, nor
  * will URLs.
  *
- * @access	public
  * @param	string	the text string
- * @param	integer	the number of characters to wrap at
+ * @param	int	the number of characters to wrap at
  * @return	string
  */
 if ( ! function_exists('word_wrap'))
 {
-	function word_wrap($str, $charlim = '76')
+	function word_wrap($str, $charlim = 76)
 	{
-		// Se the character limit
+		// Set the character limit
 		if ( ! is_numeric($charlim))
+		{
 			$charlim = 76;
+		}
 
 		// Reduce multiple spaces
-		$str = preg_replace("| +|", " ", $str);
+		$str = preg_replace('| +|', ' ', $str);
 
 		// Standardize newlines
 		if (strpos($str, "\r") !== FALSE)
@@ -430,22 +422,22 @@
 		// If the current word is surrounded by {unwrap} tags we'll
 		// strip the entire chunk and replace it with a marker.
 		$unwrap = array();
-		if (preg_match_all("|(\{unwrap\}.+?\{/unwrap\})|s", $str, $matches))
+		if (preg_match_all('|(\{unwrap\}.+?\{/unwrap\})|s', $str, $matches))
 		{
-			for ($i = 0; $i < count($matches['0']); $i++)
+			for ($i = 0, $c = count($matches[0]); $i < $c; $i++)
 			{
-				$unwrap[] = $matches['1'][$i];
-				$str = str_replace($matches['1'][$i], "{{unwrapped".$i."}}", $str);
+				$unwrap[] = $matches[1][$i];
+				$str = str_replace($matches[1][$i], '{{unwrapped'.$i.'}}', $str);
 			}
 		}
 
 		// Use PHP's native function to do the initial wordwrap.
 		// We set the cut flag to FALSE so that any individual words that are
-		// too long get left alone.  In the next step we'll deal with them.
+		// too long get left alone. In the next step we'll deal with them.
 		$str = wordwrap($str, $charlim, "\n", FALSE);
 
 		// Split the string into individual lines of text and cycle through them
-		$output = "";
+		$output = '';
 		foreach (explode("\n", $str) as $line)
 		{
 			// Is the line within the allowed character count?
@@ -460,28 +452,26 @@
 			while ((strlen($line)) > $charlim)
 			{
 				// If the over-length word is a URL we won't wrap it
-				if (preg_match("!\[url.+\]|://|wwww.!", $line))
+				if (preg_match('!\[url.+\]|://|wwww.!', $line))
 				{
 					break;
 				}
 
 				// Trim the word down
-				$temp .= substr($line, 0, $charlim-1);
-				$line = substr($line, $charlim-1);
+				$temp .= substr($line, 0, $charlim - 1);
+				$line = substr($line, $charlim - 1);
 			}
 
 			// If $temp contains data it means we had to split up an over-length
 			// word into smaller chunks so we'll add it back to our current line
-			if ($temp != '')
+			if ($temp !== '')
 			{
-				$output .= $temp."\n".$line;
+				$output .= $temp."\n".$line."\n";
 			}
 			else
 			{
-				$output .= $line;
+				$output .= $line."\n";
 			}
-
-			$output .= "\n";
 		}
 
 		// Put our markers back
@@ -489,32 +479,30 @@
 		{
 			foreach ($unwrap as $key => $val)
 			{
-				$output = str_replace("{{unwrapped".$key."}}", $val, $output);
+				$output = str_replace('{{unwrapped'.$key.'}}', $val, $output);
 			}
 		}
 
-		// Remove the unwrap tags
-		$output = str_replace(array('{unwrap}', '{/unwrap}'), '', $output);
-
-		return $output;
+		// Remove the unwrap tags and return
+		return str_replace(array('{unwrap}', '{/unwrap}'), '', $output);
 	}
 }
 
 // ------------------------------------------------------------------------
 
-/**
- * Ellipsize String
- *
- * This function will strip tags from a string, split it at its max_length and ellipsize
- *
- * @param	string		string to ellipsize
- * @param	integer		max length of string
- * @param	mixed		int (1|0) or float, .5, .2, etc for position to split
- * @param	string		ellipsis ; Default '...'
- * @return	string		ellipsized string
- */
 if ( ! function_exists('ellipsize'))
 {
+	/**
+	 * Ellipsize String
+	 *
+	 * This function will strip tags from a string, split it at its max_length and ellipsize
+	 *
+	 * @param	string	string to ellipsize
+	 * @param	int	max length of string
+	 * @param	mixed	int (1|0) or float, .5, .2, etc for position to split
+	 * @param	string	ellipsis ; Default '...'
+	 * @return	string	ellipsized string
+	 */
 	function ellipsize($str, $max_length, $position = 1, $ellipsis = '&hellip;')
 	{
 		// Strip tags
@@ -527,7 +515,6 @@
 		}
 
 		$beg = substr($str, 0, floor($max_length * $position));
-
 		$position = ($position > 1) ? 1 : $position;
 
 		if ($position === 1)
diff --git a/system/helpers/typography_helper.php b/system/helpers/typography_helper.php
index c49348e..af9d16a 100644
--- a/system/helpers/typography_helper.php
+++ b/system/helpers/typography_helper.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * CodeIgniter Typography Helpers
  *
@@ -39,15 +37,14 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Convert newlines to HTML line breaks except within PRE tags
- *
- * @access	public
- * @param	string
- * @return	string
- */
 if ( ! function_exists('nl2br_except_pre'))
 {
+	/**
+	 * Convert newlines to HTML line breaks except within PRE tags
+	 *
+	 * @param	string
+	 * @return	string
+	 */
 	function nl2br_except_pre($str)
 	{
 		$CI =& get_instance();
@@ -58,18 +55,16 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Auto Typography Wrapper Function
- *
- *
- * @access	public
- * @param	string
- * @param	bool	whether to allow javascript event handlers
- * @param	bool	whether to reduce multiple instances of double newlines to two
- * @return	string
- */
 if ( ! function_exists('auto_typography'))
 {
+	/**
+	 * Auto Typography Wrapper Function
+	 *
+	 * @param	string
+	 * @param	bool	whether to allow javascript event handlers
+	 * @param	bool	whether to reduce multiple instances of double newlines to two
+	 * @return	string
+	 */
 	function auto_typography($str, $strip_js_event_handlers = TRUE, $reduce_linebreaks = FALSE)
 	{
 		$CI =& get_instance();
@@ -78,21 +73,19 @@
 	}
 }
 
-
 // --------------------------------------------------------------------
 
-/**
- * HTML Entities Decode
- *
- * This function is a replacement for html_entity_decode()
- *
- * @access	public
- * @param	string
- * @param	string
- * @return	string
- */
 if ( ! function_exists('entity_decode'))
 {
+	/**
+	 * HTML Entities Decode
+	 *
+	 * This function is a replacement for html_entity_decode()
+	 *
+	 * @param	string
+	 * @param	string
+	 * @return	string
+	 */
 	function entity_decode($str, $charset = NULL)
 	{
 		global $SEC;
@@ -101,4 +94,4 @@
 }
 
 /* End of file typography_helper.php */
-/* Location: ./system/helpers/typography_helper.php */
+/* Location: ./system/helpers/typography_helper.php */
\ No newline at end of file
diff --git a/system/helpers/url_helper.php b/system/helpers/url_helper.php
index 2cbcd9d..2bd41b0 100644
--- a/system/helpers/url_helper.php
+++ b/system/helpers/url_helper.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * CodeIgniter URL Helpers
  *
@@ -39,18 +37,17 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Site URL
- *
- * Create a local URL based on your basepath. Segments can be passed via the
- * first parameter either as a string or an array.
- *
- * @access	public
- * @param	string
- * @return	string
- */
 if ( ! function_exists('site_url'))
 {
+	/**
+	 * Site URL
+	 *
+	 * Create a local URL based on your basepath. Segments can be passed via the
+	 * first parameter either as a string or an array.
+	 *
+	 * @param	string
+	 * @return	string
+	 */
 	function site_url($uri = '')
 	{
 		$CI =& get_instance();
@@ -60,19 +57,18 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Base URL
- *
- * Create a local URL based on your basepath.
- * Segments can be passed in as a string or an array, same as site_url
- * or a URL to a file can be passed in, e.g. to an image file.
- *
- * @access	public
- * @param string
- * @return	string
- */
 if ( ! function_exists('base_url'))
 {
+	/**
+	 * Base URL
+	 *
+	 * Create a local URL based on your basepath.
+	 * Segments can be passed in as a string or an array, same as site_url
+	 * or a URL to a file can be passed in, e.g. to an image file.
+	 *
+	 * @param	string
+	 * @return	string
+	 */
 	function base_url($uri = '')
 	{
 		$CI =& get_instance();
@@ -82,17 +78,16 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Current URL
- *
- * Returns the full URL (including segments) of the page where this
- * function is placed
- *
- * @access	public
- * @return	string
- */
 if ( ! function_exists('current_url'))
 {
+	/**
+	 * Current URL
+	 *
+	 * Returns the full URL (including segments) of the page where this
+	 * function is placed
+	 *
+	 * @return	string
+	 */
 	function current_url()
 	{
 		$CI =& get_instance();
@@ -101,16 +96,16 @@
 }
 
 // ------------------------------------------------------------------------
-/**
- * URL String
- *
- * Returns the URI segments.
- *
- * @access	public
- * @return	string
- */
+
 if ( ! function_exists('uri_string'))
 {
+	/**
+	 * URL String
+	 *
+	 * Returns the URI segments.
+	 *
+	 * @return	string
+	 */
 	function uri_string()
 	{
 		$CI =& get_instance();
@@ -120,16 +115,15 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Index page
- *
- * Returns the "index_page" from your config file
- *
- * @access	public
- * @return	string
- */
 if ( ! function_exists('index_page'))
 {
+	/**
+	 * Index page
+	 *
+	 * Returns the "index_page" from your config file
+	 *
+	 * @return	string
+	 */
 	function index_page()
 	{
 		$CI =& get_instance();
@@ -139,38 +133,37 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Anchor Link
- *
- * Creates an anchor based on the local URL.
- *
- * @access	public
- * @param	string	the URL
- * @param	string	the link title
- * @param	mixed	any attributes
- * @return	string
- */
 if ( ! function_exists('anchor'))
 {
+	/**
+	 * Anchor Link
+	 *
+	 * Creates an anchor based on the local URL.
+	 *
+	 * @param	string	the URL
+	 * @param	string	the link title
+	 * @param	mixed	any attributes
+	 * @return	string
+	 */
 	function anchor($uri = '', $title = '', $attributes = '')
 	{
 		$title = (string) $title;
 
 		if ( ! is_array($uri))
 		{
-			$site_url = ( ! preg_match('!^\w+://! i', $uri)) ? site_url($uri) : $uri;
+			$site_url = preg_match('!^\w+://! i', $uri) ? $uri : site_url($uri);
 		}
 		else
 		{
 			$site_url = site_url($uri);
 		}
 
-		if ($title == '')
+		if ($title === '')
 		{
 			$title = $site_url;
 		}
 
-		if ($attributes != '')
+		if ($attributes !== '')
 		{
 			$attributes = _parse_attributes($attributes);
 		}
@@ -181,33 +174,32 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Anchor Link - Pop-up version
- *
- * Creates an anchor based on the local URL. The link
- * opens a new window based on the attributes specified.
- *
- * @access	public
- * @param	string	the URL
- * @param	string	the link title
- * @param	mixed	any attributes
- * @return	string
- */
 if ( ! function_exists('anchor_popup'))
 {
+	/**
+	 * Anchor Link - Pop-up version
+	 *
+	 * Creates an anchor based on the local URL. The link
+	 * opens a new window based on the attributes specified.
+	 *
+	 * @param	string	the URL
+	 * @param	string	the link title
+	 * @param	mixed	any attributes
+	 * @return	string
+	 */
 	function anchor_popup($uri = '', $title = '', $attributes = FALSE)
 	{
 		$title = (string) $title;
-		$site_url = ( ! preg_match('!^\w+://! i', $uri)) ? site_url($uri) : $uri;
+		$site_url = preg_match('!^\w+://! i', $uri) ? $uri : site_url($uri);
 
-		if ($title == '')
+		if ($title === '')
 		{
 			$title = $site_url;
 		}
 
 		if ($attributes === FALSE)
 		{
-			return "<a href='javascript:void(0);' onclick=\"window.open('".$site_url."', '_blank');\">".$title."</a>";
+			return '<a href="javascript:void(0);" onclick="window.open(\''.$site_url."', '_blank');\">".$title.'</a>';
 		}
 
 		if ( ! is_array($attributes))
@@ -217,37 +209,36 @@
 
 		foreach (array('width' => '800', 'height' => '600', 'scrollbars' => 'yes', 'status' => 'yes', 'resizable' => 'yes', 'screenx' => '0', 'screeny' => '0', ) as $key => $val)
 		{
-			$atts[$key] = ( ! isset($attributes[$key])) ? $val : $attributes[$key];
+			$atts[$key] = isset($attributes[$key]) ? $attributes[$key] : $val;
 			unset($attributes[$key]);
 		}
 
-		if ($attributes != '')
+		if ($attributes !== '')
 		{
 			$attributes = _parse_attributes($attributes);
 		}
 
-		return "<a href='javascript:void(0);' onclick=\"window.open('".$site_url."', '_blank', '"._parse_attributes($atts, TRUE)."');\"$attributes>".$title."</a>";
+		return '<a href="javascript:void(0);" onclick="window.open(\''.$site_url."', '_blank', '"._parse_attributes($atts, TRUE)."');\"".$attributes.'>'.$title.'</a>';
 	}
 }
 
 // ------------------------------------------------------------------------
 
-/**
- * Mailto Link
- *
- * @access	public
- * @param	string	the email address
- * @param	string	the link title
- * @param	mixed	any attributes
- * @return	string
- */
 if ( ! function_exists('mailto'))
 {
+	/**
+	 * Mailto Link
+	 *
+	 * @param	string	the email address
+	 * @param	string	the link title
+	 * @param	mixed	any attributes
+	 * @return	string
+	 */
 	function mailto($email, $title = '', $attributes = '')
 	{
 		$title = (string) $title;
 
-		if ($title == '')
+		if ($title === '')
 		{
 			$title = $email;
 		}
@@ -258,24 +249,23 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Encoded Mailto Link
- *
- * Create a spam-protected mailto link written in Javascript
- *
- * @access	public
- * @param	string	the email address
- * @param	string	the link title
- * @param	mixed	any attributes
- * @return	string
- */
 if ( ! function_exists('safe_mailto'))
 {
+	/**
+	 * Encoded Mailto Link
+	 *
+	 * Create a spam-protected mailto link written in Javascript
+	 *
+	 * @param	string	the email address
+	 * @param	string	the link title
+	 * @param	mixed	any attributes
+	 * @return	string
+	 */
 	function safe_mailto($email, $title = '', $attributes = '')
 	{
 		$title = (string) $title;
 
-		if ($title == '')
+		if ($title === '')
 		{
 			$title = $email;
 		}
@@ -289,7 +279,7 @@
 
 		$x[] = '"';
 
-		if ($attributes != '')
+		if ($attributes !== '')
 		{
 			if (is_array($attributes))
 			{
@@ -355,7 +345,7 @@
 	for ($i = 0, $c = count($x); $i < $c; $i++) { ?>l[<?php echo $i; ?>]='<?php echo $x[$i]; ?>';<?php } ?>
 
 	for (var i = l.length-1; i >= 0; i=i-1){
-	if (l[i].substring(0, 1) == '|') document.write("&#"+unescape(l[i].substring(1))+";");
+	if (l[i].substring(0, 1) === '|') document.write("&#"+unescape(l[i].substring(1))+";");
 	else document.write(unescape(l[i]));}
 	//]]>
 	</script><?php
@@ -368,22 +358,21 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Auto-linker
- *
- * Automatically links URL and Email addresses.
- * Note: There's a bit of extra code here to deal with
- * URLs or emails that end in a period.  We'll strip these
- * off and add them after the link.
- *
- * @access	public
- * @param	string	the string
- * @param	string	the type: email, url, or both
- * @param	bool	whether to create pop-up links
- * @return	string
- */
 if ( ! function_exists('auto_link'))
 {
+	/**
+	 * Auto-linker
+	 *
+	 * Automatically links URL and Email addresses.
+	 * Note: There's a bit of extra code here to deal with
+	 * URLs or emails that end in a period. We'll strip these
+	 * off and add them after the link.
+	 *
+	 * @param	string	the string
+	 * @param	string	the type: email, url, or both
+	 * @param	bool	whether to create pop-up links
+	 * @return	string
+	 */
 	function auto_link($str, $type = 'both', $popup = FALSE)
 	{
 		if ($type !== 'email' && preg_match_all('#(^|\s|\(|\b)((http(s?)://)|(www\.))(\w+[^\s\)\<]+)#i', $str, $matches))
@@ -435,20 +424,19 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Prep URL
- *
- * Simply adds the http:// part if no scheme is included
- *
- * @access	public
- * @param	string	the URL
- * @return	string
- */
 if ( ! function_exists('prep_url'))
 {
+	/**
+	 * Prep URL
+	 *
+	 * Simply adds the http:// part if no scheme is included
+	 *
+	 * @param	string	the URL
+	 * @return	string
+	 */
 	function prep_url($str = '')
 	{
-		if ($str === 'http://' OR $str == '')
+		if ($str === 'http://' OR $str === '')
 		{
 			return '';
 		}
@@ -466,43 +454,39 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Create URL Title
- *
- * Takes a "title" string as input and creates a
- * human-friendly URL string with either a dash
- * or an underscore as the word separator.
- *
- * @access	public
- * @param	string	the string
- * @param	string	the separator: dash, or underscore
- * @return	string
- */
 if ( ! function_exists('url_title'))
 {
-	function url_title($str, $separator = 'dash', $lowercase = FALSE)
+	/**
+	 * Create URL Title
+	 *
+	 * Takes a "title" string as input and creates a
+	 * human-friendly URL string with a "separator" string
+	 * as the word separator.
+	 *
+	 * @param	string	the string
+	 * @param	string	the separator
+	 * @param	bool
+	 * @return	string
+	 */
+	function url_title($str, $separator = '-', $lowercase = FALSE)
 	{
 		if ($separator === 'dash')
 		{
-			$search		= '_';
-			$replace	= '-';
+			$separator = '-';
 		}
-		else
+		elseif ($separator === 'underscore')
 		{
-			$search		= '-';
-			$replace	= '_';
+			$separator = '_';
 		}
 
+		$q_separator = preg_quote($separator);
+
 		$trans = array(
-						'&\#\d+?;'				=> '',
-						'&\S+?;'				=> '',
-						'\s+'					=> $replace,
-						'[^a-z0-9\-\._]'		=> '',
-						$replace.'+'			=> $replace,
-						$replace.'$'			=> $replace,
-						'^'.$replace			=> $replace,
-						'\.+$'					=> ''
-					);
+				'&.+?;'			=> '',
+				'[^a-z0-9 _-]'		=> '',
+				'\s+'			=> $separator,
+				'('.$q_separator.')+'	=> $separator
+			);
 
 		$str = strip_tags($str);
 		foreach ($trans as $key => $val)
@@ -515,26 +499,26 @@
 			$str = strtolower($str);
 		}
 
-		return trim(trim(stripslashes($str)), $replace);
+		return trim(trim($str, $separator));
 	}
 }
 
 // ------------------------------------------------------------------------
 
-/**
- * Header Redirect
- *
- * Header redirect in two flavors
- * For very fine grained control over headers, you could use the Output
- * Library's set_header() function.
- *
- * @access	public
- * @param	string	the URL
- * @param	string	the method: location or refresh
- * @return	string
- */
 if ( ! function_exists('redirect'))
 {
+	/**
+	 * Header Redirect
+	 *
+	 * Header redirect in two flavors
+	 * For very fine grained control over headers, you could use the Output
+	 * Library's set_header() function.
+	 *
+	 * @param	string	the URL
+	 * @param	string	the method: location or refresh
+	 * @param	int
+	 * @return	string
+	 */
 	function redirect($uri = '', $method = 'auto', $http_response_code = 302)
 	{
 		if ( ! preg_match('#^https?://#i', $uri))
@@ -563,39 +547,38 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Parse out the attributes
- *
- * Some of the functions use this
- *
- * @access	private
- * @param	array
- * @param	bool
- * @return	string
- */
 if ( ! function_exists('_parse_attributes'))
 {
+	/**
+	 * Parse out the attributes
+	 *
+	 * Some of the functions use this
+	 *
+	 * @param	array
+	 * @param	bool
+	 * @return	string
+	 */
 	function _parse_attributes($attributes, $javascript = FALSE)
 	{
 		if (is_string($attributes))
 		{
-			return ($attributes != '') ? ' '.$attributes : '';
+			return ($attributes !== '') ? ' '.$attributes : '';
 		}
 
 		$att = '';
 		foreach ($attributes as $key => $val)
 		{
-			if ($javascript == TRUE)
+			if ($javascript === TRUE)
 			{
-				$att .= $key . '=' . $val . ',';
+				$att .= $key.'='.$val.',';
 			}
 			else
 			{
-				$att .= ' ' . $key . '="' . $val . '"';
+				$att .= ' '.$key.'="'.$val.'"';
 			}
 		}
 
-		if ($javascript == TRUE AND $att != '')
+		if ($javascript === TRUE && $att !== '')
 		{
 			return substr($att, 0, -1);
 		}
@@ -605,4 +588,4 @@
 }
 
 /* End of file url_helper.php */
-/* Location: ./system/helpers/url_helper.php */
+/* Location: ./system/helpers/url_helper.php */
\ No newline at end of file
diff --git a/system/helpers/xml_helper.php b/system/helpers/xml_helper.php
index 5242193..1431777 100644
--- a/system/helpers/xml_helper.php
+++ b/system/helpers/xml_helper.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * CodeIgniter XML Helpers
  *
@@ -39,26 +37,26 @@
 
 // ------------------------------------------------------------------------
 
-/**
- * Convert Reserved XML characters to Entities
- *
- * @access	public
- * @param	string
- * @return	string
- */
 if ( ! function_exists('xml_convert'))
 {
+	/**
+	 * Convert Reserved XML characters to Entities
+	 *
+	 * @param	string
+	 * @param	bool
+	 * @return	string
+	 */
 	function xml_convert($str, $protect_all = FALSE)
 	{
 		$temp = '__TEMP_AMPERSANDS__';
 
 		// Replace entities to temporary markers so that
 		// ampersands won't get messed up
-		$str = preg_replace("/&#(\d+);/", "$temp\\1;", $str);
+		$str = preg_replace('/&#(\d+);/', $temp.'\\1;', $str);
 
-		if ($protect_all == TRUE)
+		if ($protect_all === TRUE)
 		{
-			$str = preg_replace('/&(\w+);/', "$temp\\1;", $str);
+			$str = preg_replace('/&(\w+);/', $temp.'\\1;', $str);
 		}
 
 		$str = str_replace(array('&', '<', '>', '"', "'", '-'),
@@ -66,11 +64,11 @@
 					$str);
 
 		// Decode the temp markers back to entities
-		$str = preg_replace('/$temp(\d+);/', '&#\\1;', $str);
+		$str = preg_replace('/'.$temp.'(\d+);/', '&#\\1;', $str);
 
-		if ($protect_all == TRUE)
+		if ($protect_all === TRUE)
 		{
-			return preg_replace("/$temp(\w+);/", '&\\1;', $str);
+			return preg_replace('/'.$temp.'(\w+);/', '&\\1;', $str);
 		}
 
 		return $str;
@@ -78,4 +76,4 @@
 }
 
 /* End of file xml_helper.php */
-/* Location: ./system/helpers/xml_helper.php */
+/* Location: ./system/helpers/xml_helper.php */
\ No newline at end of file
diff --git a/system/language/english/calendar_lang.php b/system/language/english/calendar_lang.php
index bf61db0..48939d4 100644
--- a/system/language/english/calendar_lang.php
+++ b/system/language/english/calendar_lang.php
@@ -2,12 +2,12 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
- * 
+ *
  * Licensed under the Open Software License version 3.0
- * 
+ *
  * This source file is subject to the Open Software License (OSL 3.0) that is
  * bundled with this package in the files license.txt / license.rst.  It is
  * also available through the world wide web at this URL:
diff --git a/system/language/english/date_lang.php b/system/language/english/date_lang.php
index cd6cf39..38532b7 100644
--- a/system/language/english/date_lang.php
+++ b/system/language/english/date_lang.php
@@ -2,12 +2,12 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
- * 
+ *
  * Licensed under the Open Software License version 3.0
- * 
+ *
  * This source file is subject to the Open Software License (OSL 3.0) that is
  * bundled with this package in the files license.txt / license.rst.  It is
  * also available through the world wide web at this URL:
diff --git a/system/language/english/db_lang.php b/system/language/english/db_lang.php
index 2a91597..479cbb1 100644
--- a/system/language/english/db_lang.php
+++ b/system/language/english/db_lang.php
@@ -2,12 +2,12 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
- * 
+ *
  * Licensed under the Open Software License version 3.0
- * 
+ *
  * This source file is subject to the Open Software License (OSL 3.0) that is
  * bundled with this package in the files license.txt / license.rst.  It is
  * also available through the world wide web at this URL:
diff --git a/system/language/english/email_lang.php b/system/language/english/email_lang.php
index e0ef427..95a16d1 100644
--- a/system/language/english/email_lang.php
+++ b/system/language/english/email_lang.php
@@ -2,12 +2,12 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
- * 
+ *
  * Licensed under the Open Software License version 3.0
- * 
+ *
  * This source file is subject to the Open Software License (OSL 3.0) that is
  * bundled with this package in the files license.txt / license.rst.  It is
  * also available through the world wide web at this URL:
diff --git a/system/language/english/form_validation_lang.php b/system/language/english/form_validation_lang.php
index 6afa37a..eb4624e 100644
--- a/system/language/english/form_validation_lang.php
+++ b/system/language/english/form_validation_lang.php
@@ -2,12 +2,12 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
- * 
+ *
  * Licensed under the Open Software License version 3.0
- * 
+ *
  * This source file is subject to the Open Software License (OSL 3.0) that is
  * bundled with this package in the files license.txt / license.rst.  It is
  * also available through the world wide web at this URL:
@@ -25,30 +25,32 @@
  * @filesource
  */
 
-$lang['required']			= "The %s field is required.";
-$lang['isset']				= "The %s field must have a value.";
-$lang['valid_email']		= "The %s field must contain a valid email address.";
-$lang['valid_emails']		= "The %s field must contain all valid email addresses.";
-$lang['valid_url']			= "The %s field must contain a valid URL.";
-$lang['valid_ip']			= "The %s field must contain a valid IP.";
-$lang['min_length']			= "The %s field must be at least %s characters in length.";
-$lang['max_length']			= "The %s field cannot exceed %s characters in length.";
-$lang['exact_length']		= "The %s field must be exactly %s characters in length.";
-$lang['alpha']				= "The %s field may only contain alphabetical characters.";
-$lang['alpha_numeric']		= "The %s field may only contain alpha-numeric characters.";
-$lang['alpha_dash']			= "The %s field may only contain alpha-numeric characters, underscores, and dashes.";
-$lang['numeric']			= "The %s field must contain only numbers.";
-$lang['is_numeric']			= "The %s field must contain only numeric characters.";
-$lang['integer']			= "The %s field must contain an integer.";
-$lang['regex_match']		= "The %s field is not in the correct format.";
-$lang['matches']			= "The %s field does not match the %s field.";
-$lang['is_unique'] 			= "The %s field must contain a unique value.";
-$lang['is_natural']			= "The %s field must contain only positive numbers.";
-$lang['is_natural_no_zero']	= "The %s field must contain a number greater than zero.";
-$lang['decimal']			= "The %s field must contain a decimal number.";
-$lang['less_than']			= "The %s field must contain a number less than %s.";
-$lang['greater_than']		= "The %s field must contain a number greater than %s.";
+$lang['required']				= "The %s field is required.";
+$lang['isset']					= "The %s field must have a value.";
+$lang['valid_email']			= "The %s field must contain a valid email address.";
+$lang['valid_emails']			= "The %s field must contain all valid email addresses.";
+$lang['valid_url']				= "The %s field must contain a valid URL.";
+$lang['valid_ip']				= "The %s field must contain a valid IP.";
+$lang['min_length']				= "The %s field must be at least %s characters in length.";
+$lang['max_length']				= "The %s field cannot exceed %s characters in length.";
+$lang['exact_length']			= "The %s field must be exactly %s characters in length.";
+$lang['alpha']					= "The %s field may only contain alphabetical characters.";
+$lang['alpha_numeric']			= "The %s field may only contain alpha-numeric characters.";
+$lang['alpha_dash']				= "The %s field may only contain alpha-numeric characters, underscores, and dashes.";
+$lang['numeric']				= "The %s field must contain only numbers.";
+$lang['is_numeric']				= "The %s field must contain only numeric characters.";
+$lang['integer']				= "The %s field must contain an integer.";
+$lang['regex_match']			= "The %s field is not in the correct format.";
+$lang['matches']				= "The %s field does not match the %s field.";
+$lang['is_unique'] 				= "The %s field must contain a unique value.";
+$lang['is_natural']				= "The %s field must contain only positive numbers.";
+$lang['is_natural_no_zero']		= "The %s field must contain a number greater than zero.";
+$lang['decimal']				= "The %s field must contain a decimal number.";
+$lang['less_than']				= "The %s field must contain a number less than %s.";
+$lang['less_than_equal_to']		= "The %s field must contain a number less than or equal to %s.";
+$lang['greater_than']			= "The %s field must contain a number greater than %s.";
+$lang['greater_than_equal_to']	= "The %s field must contain a number greater than or equal to %s.";
 
 
 /* End of file form_validation_lang.php */
-/* Location: ./system/language/english/form_validation_lang.php */
\ No newline at end of file
+/* Location: ./system/language/english/form_validation_lang.php */
diff --git a/system/language/english/ftp_lang.php b/system/language/english/ftp_lang.php
index 18ca927..d00126b 100644
--- a/system/language/english/ftp_lang.php
+++ b/system/language/english/ftp_lang.php
@@ -2,12 +2,12 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
- * 
+ *
  * Licensed under the Open Software License version 3.0
- * 
+ *
  * This source file is subject to the Open Software License (OSL 3.0) that is
  * bundled with this package in the files license.txt / license.rst.  It is
  * also available through the world wide web at this URL:
diff --git a/system/language/english/imglib_lang.php b/system/language/english/imglib_lang.php
index fbb92ab..67a36e1 100644
--- a/system/language/english/imglib_lang.php
+++ b/system/language/english/imglib_lang.php
@@ -2,12 +2,12 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
- * 
+ *
  * Licensed under the Open Software License version 3.0
- * 
+ *
  * This source file is subject to the Open Software License (OSL 3.0) that is
  * bundled with this package in the files license.txt / license.rst.  It is
  * also available through the world wide web at this URL:
diff --git a/system/language/english/migration_lang.php b/system/language/english/migration_lang.php
index 9765562..9e3e188 100644
--- a/system/language/english/migration_lang.php
+++ b/system/language/english/migration_lang.php
@@ -2,12 +2,12 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
- * 
+ *
  * Licensed under the Open Software License version 3.0
- * 
+ *
  * This source file is subject to the Open Software License (OSL 3.0) that is
  * bundled with this package in the files license.txt / license.rst.  It is
  * also available through the world wide web at this URL:
diff --git a/system/language/english/number_lang.php b/system/language/english/number_lang.php
index 5dfd882..429c647 100644
--- a/system/language/english/number_lang.php
+++ b/system/language/english/number_lang.php
@@ -2,12 +2,12 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
- * 
+ *
  * Licensed under the Open Software License version 3.0
- * 
+ *
  * This source file is subject to the Open Software License (OSL 3.0) that is
  * bundled with this package in the files license.txt / license.rst.  It is
  * also available through the world wide web at this URL:
@@ -25,11 +25,11 @@
  * @filesource
  */
 
-$lang['terabyte_abbr'] = "TB";
-$lang['gigabyte_abbr'] = "GB";
-$lang['megabyte_abbr'] = "MB";
-$lang['kilobyte_abbr'] = "KB";
-$lang['bytes'] = "Bytes";
+$lang['terabyte_abbr'] = 'TB';
+$lang['gigabyte_abbr'] = 'GB';
+$lang['megabyte_abbr'] = 'MB';
+$lang['kilobyte_abbr'] = 'KB';
+$lang['bytes'] = 'Bytes';
 
 /* End of file number_lang.php */
 /* Location: ./system/language/english/number_lang.php */
\ No newline at end of file
diff --git a/system/language/english/profiler_lang.php b/system/language/english/profiler_lang.php
index 1d10efa..112527f 100644
--- a/system/language/english/profiler_lang.php
+++ b/system/language/english/profiler_lang.php
@@ -2,12 +2,12 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
- * 
+ *
  * Licensed under the Open Software License version 3.0
- * 
+ *
  * This source file is subject to the Open Software License (OSL 3.0) that is
  * bundled with this package in the files license.txt / license.rst.  It is
  * also available through the world wide web at this URL:
diff --git a/system/language/english/unit_test_lang.php b/system/language/english/unit_test_lang.php
index ed98439..36e9aca 100644
--- a/system/language/english/unit_test_lang.php
+++ b/system/language/english/unit_test_lang.php
@@ -2,12 +2,12 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
- * 
+ *
  * Licensed under the Open Software License version 3.0
- * 
+ *
  * This source file is subject to the Open Software License (OSL 3.0) that is
  * bundled with this package in the files license.txt / license.rst.  It is
  * also available through the world wide web at this URL:
diff --git a/system/language/english/upload_lang.php b/system/language/english/upload_lang.php
index a9a2fe7..c3cb9c3 100644
--- a/system/language/english/upload_lang.php
+++ b/system/language/english/upload_lang.php
@@ -2,12 +2,12 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
- * 
+ *
  * Licensed under the Open Software License version 3.0
- * 
+ *
  * This source file is subject to the Open Software License (OSL 3.0) that is
  * bundled with this package in the files license.txt / license.rst.  It is
  * also available through the world wide web at this URL:
@@ -35,7 +35,7 @@
 $lang['upload_no_file_selected'] = "You did not select a file to upload.";
 $lang['upload_invalid_filetype'] = "The filetype you are attempting to upload is not allowed.";
 $lang['upload_invalid_filesize'] = "The file you are attempting to upload is larger than the permitted size.";
-$lang['upload_invalid_dimensions'] = "The image you are attempting to upload exceedes the maximum height or width.";
+$lang['upload_invalid_dimensions'] = "The image you are attempting to upload exceeds the maximum height or width.";
 $lang['upload_destination_error'] = "A problem was encountered while attempting to move the uploaded file to the final destination.";
 $lang['upload_no_filepath'] = "The upload path does not appear to be valid.";
 $lang['upload_no_file_types'] = "You have not specified any allowed file types.";
diff --git a/system/libraries/Cache/Cache.php b/system/libraries/Cache/Cache.php
index 2e78a66..4395cf4 100644
--- a/system/libraries/Cache/Cache.php
+++ b/system/libraries/Cache/Cache.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * CodeIgniter Caching Class
  *
@@ -38,128 +36,55 @@
  */
 class CI_Cache extends CI_Driver_Library {
 
+	/**
+	 * Valid cache drivers
+	 *
+	 * @var array
+	 */
 	protected $valid_drivers 	= array(
-		'cache_apc', 'cache_file', 'cache_memcached', 'cache_dummy'
+		'cache_apc',
+		'cache_dummy',
+		'cache_file',
+		'cache_memcached',
+		'cache_redis',
+		'cache_wincache'
 	);
 
-	protected $_cache_path		= NULL;		// Path of cache files (if file-based cache)
-	protected $_adapter			= 'dummy';
-	protected $_backup_driver;
+	/**
+	 * Path of cache files (if file-based cache)
+	 *
+	 * @var string
+	 */
+	protected $_cache_path = NULL;
 
-	// ------------------------------------------------------------------------
+	/**
+	 * Reference to the driver
+	 *
+	 * @var mixed
+	 */
+	protected $_adapter = 'dummy';
+
+	/**
+	 * Fallback driver
+	 *
+	 * @param string
+	 */
+	protected $_backup_driver = 'dummy';
 
 	/**
 	 * Constructor
 	 *
-	 * @param array
-	 */
-	public function __construct($config = array())
-	{
-		if ( ! empty($config))
-		{
-			$this->_initialize($config);
-		}
-	}
-
-	// ------------------------------------------------------------------------
-
-	/**
-	 * Get
-	 *
-	 * 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
-	 */
-	public function get($id)
-	{
-		return $this->{$this->_adapter}->get($id);
-	}
-
-	// ------------------------------------------------------------------------
-
-	/**
-	 * Cache Save
-	 *
-	 * @param 	string		Unique Key
-	 * @param 	mixed		Data to store
-	 * @param 	int			Length of time (in seconds) to cache the data
-	 *
-	 * @return 	boolean		true on success/false on failure
-	 */
-	public function save($id, $data, $ttl = 60)
-	{
-		return $this->{$this->_adapter}->save($id, $data, $ttl);
-	}
-
-	// ------------------------------------------------------------------------
-
-	/**
-	 * Delete from Cache
-	 *
-	 * @param 	mixed		unique identifier of the item in the cache
-	 * @return 	boolean		true on success/false on failure
-	 */
-	public function delete($id)
-	{
-		return $this->{$this->_adapter}->delete($id);
-	}
-
-	// ------------------------------------------------------------------------
-
-	/**
-	 * Clean the cache
-	 *
-	 * @return 	boolean		false on failure/true on success
-	 */
-	public function clean()
-	{
-		return $this->{$this->_adapter}->clean();
-	}
-
-	// ------------------------------------------------------------------------
-
-	/**
-	 * Cache Info
-	 *
-	 * @param 	string		user/filehits
-	 * @return 	mixed		array on success, false on failure
-	 */
-	public function cache_info($type = 'user')
-	{
-		return $this->{$this->_adapter}->cache_info($type);
-	}
-
-	// ------------------------------------------------------------------------
-
-	/**
-	 * Get Cache Metadata
-	 *
-	 * @param 	mixed		key to get cache metadata on
-	 * @return 	mixed		return value from child method
-	 */
-	public function get_metadata($id)
-	{
-		return $this->{$this->_adapter}->get_metadata($id);
-	}
-
-	// ------------------------------------------------------------------------
-
-	/**
-	 * Initialize
-	 *
 	 * Initialize class properties based on the configuration array.
 	 *
 	 * @param	array
-	 * @return 	void
+	 * @return	void
 	 */
-	private function _initialize($config)
+	public function __construct($config = array())
 	{
 		$default_config = array(
-				'adapter',
-				'memcached'
-			);
+			'adapter',
+			'memcached'
+		);
 
 		foreach ($default_config as $key)
 		{
@@ -178,6 +103,104 @@
 				$this->_backup_driver = $config['backup'];
 			}
 		}
+
+		// If the specified adapter isn't available, check the backup.
+		if ( ! $this->is_supported($this->_adapter))
+		{
+			if ( ! $this->is_supported($this->_backup_driver))
+			{
+				// Backup isn't supported either. Default to 'Dummy' driver.
+				log_message('error', 'Cache adapter "'.$this->_adapter.'" and backup "'.$this->_backup_driver.'" are both unavailable. Cache is now using "Dummy" adapter.');
+				$this->_adapter = 'dummy';
+			}
+			else
+			{
+				// Backup is supported. Set it to primary.
+				$this->_adapter = $this->_backup_driver;
+			}
+		}
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * Get
+	 *
+	 * 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
+	 */
+	public function get($id)
+	{
+		return $this->{$this->_adapter}->get($id);
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * 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
+	 */
+	public function save($id, $data, $ttl = 60)
+	{
+		return $this->{$this->_adapter}->save($id, $data, $ttl);
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * Delete from Cache
+	 *
+	 * @param	mixed	unique identifier of the item in the cache
+	 * @return	bool	true on success/false on failure
+	 */
+	public function delete($id)
+	{
+		return $this->{$this->_adapter}->delete($id);
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * Clean the cache
+	 *
+	 * @return	bool	false on failure/true on success
+	 */
+	public function clean()
+	{
+		return $this->{$this->_adapter}->clean();
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * Cache Info
+	 *
+	 * @param	string	user/filehits
+	 * @return	mixed	array on success, false on failure
+	 */
+	public function cache_info($type = 'user')
+	{
+		return $this->{$this->_adapter}->cache_info($type);
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * Get Cache Metadata
+	 *
+	 * @param	mixed	key to get cache metadata on
+	 * @return	mixed	return value from child method
+	 */
+	public function get_metadata($id)
+	{
+		return $this->{$this->_adapter}->get_metadata($id);
 	}
 
 	// ------------------------------------------------------------------------
@@ -185,8 +208,8 @@
 	/**
 	 * Is the requested driver supported in this environment?
 	 *
-	 * @param 	string	The driver to test.
-	 * @return 	array
+	 * @param	string	The driver to test.
+	 * @return	array
 	 */
 	public function is_supported($driver)
 	{
@@ -200,29 +223,7 @@
 		return $support[$driver];
 	}
 
-	// ------------------------------------------------------------------------
-
-	/**
-	 * __get()
-	 *
-	 * @param 	child
-	 * @return 	object
-	 */
-	public function __get($child)
-	{
-		$obj = parent::__get($child);
-
-		if ( ! $this->is_supported($child))
-		{
-			$this->_adapter = $this->_backup_driver;
-		}
-
-		return $obj;
-	}
-
-	// ------------------------------------------------------------------------
 }
-// End Class
 
 /* End of file Cache.php */
-/* Location: ./system/libraries/Cache/Cache.php */
+/* Location: ./system/libraries/Cache/Cache.php */
\ No newline at end of file
diff --git a/system/libraries/Cache/drivers/Cache_apc.php b/system/libraries/Cache/drivers/Cache_apc.php
index a3dd469..c85034f 100644
--- a/system/libraries/Cache/drivers/Cache_apc.php
+++ b/system/libraries/Cache/drivers/Cache_apc.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * CodeIgniter APC Caching Class
  *
@@ -36,23 +34,22 @@
  * @author		EllisLab Dev Team
  * @link
  */
-
 class CI_Cache_apc extends CI_Driver {
 
 	/**
 	 * Get
 	 *
-	 * Look for a value in the cache.  If it exists, return the data
+	 * 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
+	 * @return	mixed	value that is stored/FALSE on failure
 	 */
 	public function get($id)
 	{
 		$data = apc_fetch($id);
 
-		return (is_array($data)) ? $data[0] : FALSE;
+		return is_array($data) ? $data[0] : FALSE;
 	}
 
 	// ------------------------------------------------------------------------
@@ -60,11 +57,11 @@
 	/**
 	 * Cache Save
 	 *
-	 * @param 	string		Unique Key
-	 * @param 	mixed		Data to store
-	 * @param 	int			Length of time (in seconds) to cache the data
+	 * @param	string	Unique Key
+	 * @param	mixed	Data to store
+	 * @param	int	Length of time (in seconds) to cache the data
 	 *
-	 * @return 	boolean		true on success/false on failure
+	 * @return	bool	true on success/false on failure
 	 */
 	public function save($id, $data, $ttl = 60)
 	{
@@ -77,8 +74,8 @@
 	/**
 	 * Delete from Cache
 	 *
-	 * @param 	mixed		unique identifier of the item in the cache
-	 * @param 	boolean		true on success/false on failure
+	 * @param	mixed	unique identifier of the item in the cache
+	 * @return	bool	true on success/false on failure
 	 */
 	public function delete($id)
 	{
@@ -90,7 +87,7 @@
 	/**
 	 * Clean the cache
 	 *
-	 * @return 	boolean		false on failure/true on success
+	 * @return	bool	false on failure/true on success
 	 */
 	public function clean()
 	{
@@ -102,8 +99,8 @@
 	/**
 	 * Cache Info
 	 *
-	 * @param 	string		user/filehits
-	 * @return 	mixed		array on success, false on failure
+	 * @param	string	user/filehits
+	 * @return	mixed	array on success, false on failure
 	 */
 	 public function cache_info($type = NULL)
 	 {
@@ -115,8 +112,8 @@
 	/**
 	 * Get Cache Metadata
 	 *
-	 * @param 	mixed		key to get cache metadata on
-	 * @return 	mixed		array on success/false on failure
+	 * @param	mixed	key to get cache metadata on
+	 * @return	mixed	array on success/false on failure
 	 */
 	public function get_metadata($id)
 	{
@@ -142,10 +139,12 @@
 	 * is_supported()
 	 *
 	 * Check to see if APC is available on this system, bail if it isn't.
+	 *
+	 * @return	bool
 	 */
 	public function is_supported()
 	{
-		if ( ! extension_loaded('apc') OR ini_get('apc.enabled') != "1")
+		if ( ! extension_loaded('apc') OR ! (bool) @ini_get('apc.enabled'))
 		{
 			log_message('error', 'The APC PHP extension must be loaded to use APC Cache.');
 			return FALSE;
@@ -154,11 +153,7 @@
 		return TRUE;
 	}
 
-	// ------------------------------------------------------------------------
-
-
 }
-// End Class
 
 /* End of file Cache_apc.php */
-/* Location: ./system/libraries/Cache/drivers/Cache_apc.php */
+/* Location: ./system/libraries/Cache/drivers/Cache_apc.php */
\ No newline at end of file
diff --git a/system/libraries/Cache/drivers/Cache_dummy.php b/system/libraries/Cache/drivers/Cache_dummy.php
index fcd55da..3f2b4b9 100644
--- a/system/libraries/Cache/drivers/Cache_dummy.php
+++ b/system/libraries/Cache/drivers/Cache_dummy.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * CodeIgniter Dummy Caching Class
  *
@@ -36,7 +34,6 @@
  * @author		EllisLab Dev Team
  * @link
  */
-
 class CI_Cache_dummy extends CI_Driver {
 
 	/**
@@ -44,8 +41,8 @@
 	 *
 	 * Since this is the dummy class, it's always going to return FALSE.
 	 *
-	 * @param 	string
-	 * @return 	Boolean		FALSE
+	 * @param	string
+	 * @return	bool	FALSE
 	 */
 	public function get($id)
 	{
@@ -57,11 +54,10 @@
 	/**
 	 * Cache Save
 	 *
-	 * @param 	string		Unique Key
-	 * @param 	mixed		Data to store
-	 * @param 	int			Length of time (in seconds) to cache the data
-	 *
-	 * @return 	boolean		TRUE, Simulating success
+	 * @param	string	Unique Key
+	 * @param	mixed	Data to store
+	 * @param	int	Length of time (in seconds) to cache the data
+	 * @return	bool	TRUE, Simulating success
 	 */
 	public function save($id, $data, $ttl = 60)
 	{
@@ -73,8 +69,8 @@
 	/**
 	 * Delete from Cache
 	 *
-	 * @param 	mixed		unique identifier of the item in the cache
-	 * @param 	boolean		TRUE, simulating success
+	 * @param	mixed	unique identifier of the item in the cache
+	 * @return	bool	TRUE, simulating success
 	 */
 	public function delete($id)
 	{
@@ -86,7 +82,7 @@
 	/**
 	 * Clean the cache
 	 *
-	 * @return 	boolean		TRUE, simulating success
+	 * @return	bool	TRUE, simulating success
 	 */
 	public function clean()
 	{
@@ -98,8 +94,8 @@
 	/**
 	 * Cache Info
 	 *
-	 * @param 	string		user/filehits
-	 * @return 	boolean		FALSE
+	 * @param	string	user/filehits
+	 * @return	bool	FALSE
 	 */
 	 public function cache_info($type = NULL)
 	 {
@@ -111,8 +107,8 @@
 	/**
 	 * Get Cache Metadata
 	 *
-	 * @param 	mixed		key to get cache metadata on
-	 * @return 	boolean		FALSE
+	 * @param	mixed	key to get cache metadata on
+	 * @return	bool	FALSE
 	 */
 	public function get_metadata($id)
 	{
@@ -125,17 +121,14 @@
 	 * Is this caching driver supported on the system?
 	 * Of course this one is.
 	 *
-	 * @return TRUE;
+	 * @return	bool	TRUE
 	 */
 	public function is_supported()
 	{
 		return TRUE;
 	}
 
-	// ------------------------------------------------------------------------
-
 }
-// End Class
 
 /* End of file Cache_dummy.php */
-/* Location: ./system/libraries/Cache/drivers/Cache_dummy.php */
+/* Location: ./system/libraries/Cache/drivers/Cache_dummy.php */
\ No newline at end of file
diff --git a/system/libraries/Cache/drivers/Cache_file.php b/system/libraries/Cache/drivers/Cache_file.php
index ff88957..1b57c89 100644
--- a/system/libraries/Cache/drivers/Cache_file.php
+++ b/system/libraries/Cache/drivers/Cache_file.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * CodeIgniter Memcached Caching Class
  *
@@ -36,20 +34,26 @@
  * @author		EllisLab Dev Team
  * @link
  */
-
 class CI_Cache_file extends CI_Driver {
 
+	/**
+	 * Directory in which to save cache files
+	 *
+	 * @var string
+	 */
 	protected $_cache_path;
 
 	/**
-	 * Constructor
+	 * Initialize file-based cache
+	 *
+	 * @return	void
 	 */
 	public function __construct()
 	{
 		$CI =& get_instance();
 		$CI->load->helper('file');
 		$path = $CI->config->item('cache_path');
-		$this->_cache_path = ($path == '') ? APPPATH.'cache/' : $path;
+		$this->_cache_path = ($path === '') ? APPPATH.'cache/' : $path;
 	}
 
 	// ------------------------------------------------------------------------
@@ -57,8 +61,8 @@
 	/**
 	 * Fetch from cache
 	 *
-	 * @param 	mixed		unique key id
-	 * @return 	mixed		data on success/false on failure
+	 * @param	mixed	unique key id
+	 * @return	mixed	data on success/false on failure
 	 */
 	public function get($id)
 	{
@@ -67,7 +71,7 @@
 			return FALSE;
 		}
 
-		$data = unserialize(read_file($this->_cache_path.$id));
+		$data = unserialize(file_get_contents($this->_cache_path.$id));
 
 		if (time() >  $data['time'] + $data['ttl'])
 		{
@@ -83,23 +87,23 @@
 	/**
 	 * 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 	boolean		true on success/false on failure
+	 * @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
 	 */
 	public function save($id, $data, $ttl = 60)
 	{
 		$contents = array(
-				'time'		=> time(),
-				'ttl'		=> $ttl,
-				'data'		=> $data
-			);
+			'time'		=> time(),
+			'ttl'		=> $ttl,
+			'data'		=> $data
+		);
 
 		if (write_file($this->_cache_path.$id, serialize($contents)))
 		{
-			@chmod($this->_cache_path.$id, 0777);
+			@chmod($this->_cache_path.$id, 0660);
 			return TRUE;
 		}
 
@@ -111,12 +115,12 @@
 	/**
 	 * Delete from Cache
 	 *
-	 * @param 	mixed		unique identifier of item in cache
-	 * @return 	boolean		true on success/false on failure
+	 * @param	mixed	unique identifier of item in cache
+	 * @return	bool	true on success/false on failure
 	 */
 	public function delete($id)
 	{
-		return (file_exists($this->_cache_path.$id)) ? unlink($this->_cache_path.$id) : FALSE;
+		return file_exists($this->_cache_path.$id) ? unlink($this->_cache_path.$id) : FALSE;
 	}
 
 	// ------------------------------------------------------------------------
@@ -124,7 +128,7 @@
 	/**
 	 * Clean the Cache
 	 *
-	 * @return 	boolean		false on failure/true on success
+	 * @return	bool	false on failure/true on success
 	 */
 	public function clean()
 	{
@@ -138,8 +142,8 @@
 	 *
 	 * Not supported by file-based caching
 	 *
-	 * @param 	string	user/filehits
-	 * @return 	mixed 	FALSE
+	 * @param	string	user/filehits
+	 * @return	mixed	FALSE
 	 */
 	public function cache_info($type = NULL)
 	{
@@ -151,8 +155,8 @@
 	/**
 	 * Get Cache Metadata
 	 *
-	 * @param 	mixed		key to get cache metadata on
-	 * @return 	mixed		FALSE on failure, array on success.
+	 * @param	mixed	key to get cache metadata on
+	 * @return	mixed	FALSE on failure, array on success.
 	 */
 	public function get_metadata($id)
 	{
@@ -161,7 +165,7 @@
 			return FALSE;
 		}
 
-		$data = unserialize(read_file($this->_cache_path.$id));
+		$data = unserialize(file_get_contents($this->_cache_path.$id));
 
 		if (is_array($data))
 		{
@@ -188,16 +192,14 @@
 	 *
 	 * In the file driver, check to see that the cache directory is indeed writable
 	 *
-	 * @return boolean
+	 * @return	bool
 	 */
 	public function is_supported()
 	{
 		return is_really_writable($this->_cache_path);
 	}
 
-	// ------------------------------------------------------------------------
 }
-// End Class
 
 /* End of file Cache_file.php */
 /* Location: ./system/libraries/Cache/drivers/Cache_file.php */
diff --git a/system/libraries/Cache/drivers/Cache_memcached.php b/system/libraries/Cache/drivers/Cache_memcached.php
index ffe6f2f..bf90f61 100644
--- a/system/libraries/Cache/drivers/Cache_memcached.php
+++ b/system/libraries/Cache/drivers/Cache_memcached.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * CodeIgniter Memcached Caching Class
  *
@@ -36,32 +34,39 @@
  * @author		EllisLab Dev Team
  * @link
  */
-
 class CI_Cache_memcached extends CI_Driver {
 
-	private $_memcached;	// Holds the memcached object
+	/**
+	 * Holds the memcached object
+	 *
+	 * @var object
+	 */
+	protected $_memcached;
 
-	protected $_memcache_conf 	= array(
-					'default' => array(
-						'default_host'		=> '127.0.0.1',
-						'default_port'		=> 11211,
-						'default_weight'	=> 1
-					)
-				);
-
-	// ------------------------------------------------------------------------
+	/**
+	 * Memcached configuration
+	 *
+	 * @var array
+	 */
+	protected $_memcache_conf	= array(
+		'default' => array(
+			'default_host'		=> '127.0.0.1',
+			'default_port'		=> 11211,
+			'default_weight'	=> 1
+		)
+	);
 
 	/**
 	 * Fetch from cache
 	 *
-	 * @param 	mixed		unique key id
-	 * @return 	mixed		data on success/false on failure
+	 * @param	mixed	unique key 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] : FALSE;
 	}
 
 	// ------------------------------------------------------------------------
@@ -69,18 +74,18 @@
 	/**
 	 * Save
 	 *
-	 * @param 	string		unique identifier
-	 * @param 	mixed		data being cached
-	 * @param 	int			time to live
-	 * @return 	boolean 	true on success, false on failure
+	 * @param	string	unique identifier
+	 * @param	mixed	data being cached
+	 * @param	int	time to live
+	 * @return	bool	true on success, false on failure
 	 */
 	public function save($id, $data, $ttl = 60)
 	{
-		if (get_class($this->_memcached) == 'Memcached')
+		if (get_class($this->_memcached) === 'Memcached')
 		{
 			return $this->_memcached->set($id, array($data, time(), $ttl), $ttl);
 		}
-		else if (get_class($this->_memcached) == 'Memcache')
+		elseif (get_class($this->_memcached) === 'Memcache')
 		{
 			return $this->_memcached->set($id, array($data, time(), $ttl), 0, $ttl);
 		}
@@ -93,8 +98,8 @@
 	/**
 	 * Delete from Cache
 	 *
-	 * @param 	mixed		key to be deleted.
-	 * @return 	boolean 	true on success, false on failure
+	 * @param	mixed	key to be deleted.
+	 * @return	bool	true on success, false on failure
 	 */
 	public function delete($id)
 	{
@@ -106,7 +111,7 @@
 	/**
 	 * Clean the Cache
 	 *
-	 * @return 	boolean		false on failure/true on success
+	 * @return	bool	false on failure/true on success
 	 */
 	public function clean()
 	{
@@ -118,10 +123,9 @@
 	/**
 	 * Cache Info
 	 *
-	 * @param 	null		type not supported in memcached
-	 * @return 	mixed 		array on success, false on failure
+	 * @return	mixed	array on success, false on failure
 	 */
-	public function cache_info($type = NULL)
+	public function cache_info()
 	{
 		return $this->_memcached->getStats();
 	}
@@ -131,8 +135,8 @@
 	/**
 	 * Get Cache Metadata
 	 *
-	 * @param 	mixed		key to get cache metadata on
-	 * @return 	mixed		FALSE on failure, array on success.
+	 * @param	mixed	key to get cache metadata on
+	 * @return	mixed	FALSE on failure, array on success.
 	 */
 	public function get_metadata($id)
 	{
@@ -156,8 +160,10 @@
 
 	/**
 	 * Setup memcached.
+	 *
+	 * @return	bool
 	 */
-	private function _setup_memcached()
+	protected function _setup_memcached()
 	{
 		// Try to load memcached server info from the config file.
 		$CI =& get_instance();
@@ -179,14 +185,13 @@
 		{
 			$this->_memcached = new Memcached();
 		}
-		else if (class_exists('Memcache'))
+		elseif (class_exists('Memcache'))
 		{
 			$this->_memcached = new Memcache();
 		}
 		else
 		{
 			log_message('error', 'Failed to create object for Memcached Cache; extension not loaded?');
-
 			return FALSE;
 		}
 
@@ -194,20 +199,20 @@
 		{
 			if ( ! array_key_exists('hostname', $cache_server))
 			{
-				$cache_server['hostname'] = $this->_default_options['default_host'];
+				$cache_server['hostname'] = $this->_memcache_conf['default']['default_host'];
 			}
 
 			if ( ! array_key_exists('port', $cache_server))
 			{
-				$cache_server['port'] = $this->_default_options['default_port'];
+				$cache_server['port'] = $this->_memcache_conf['default']['default_port'];
 			}
 
 			if ( ! array_key_exists('weight', $cache_server))
 			{
-				$cache_server['weight'] = $this->_default_options['default_weight'];
+				$cache_server['weight'] = $this->_memcache_conf['default']['default_weight'];
 			}
 
-			if (get_class($this->_memcached) == 'Memcache')
+			if (get_class($this->_memcached) === 'Memcache')
 			{
 				// Third parameter is persistance and defaults to TRUE.
 				$this->_memcached->addServer(
@@ -237,23 +242,21 @@
 	 *
 	 * Returns FALSE if memcached is not supported on the system.
 	 * If it is, we setup the memcached object & return TRUE
+	 *
+	 * @return	bool
 	 */
 	public function is_supported()
 	{
 		if ( ! extension_loaded('memcached') && ! extension_loaded('memcache'))
 		{
 			log_message('error', 'The Memcached Extension must be loaded to use Memcached Cache.');
-
 			return FALSE;
 		}
 
 		return $this->_setup_memcached();
 	}
 
-	// ------------------------------------------------------------------------
-
 }
-// End Class
 
 /* End of file Cache_memcached.php */
-/* Location: ./system/libraries/Cache/drivers/Cache_memcached.php */
+/* Location: ./system/libraries/Cache/drivers/Cache_memcached.php */
\ No newline at end of file
diff --git a/system/libraries/Cache/drivers/Cache_redis.php b/system/libraries/Cache/drivers/Cache_redis.php
new file mode 100644
index 0000000..e4a26b5
--- /dev/null
+++ b/system/libraries/Cache/drivers/Cache_redis.php
@@ -0,0 +1,236 @@
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.2.4 or newer
+ *
+ * NOTICE OF LICENSE
+ *
+ * Licensed under the Open Software License version 3.0
+ *
+ * This source file is subject to the Open Software License (OSL 3.0) that is
+ * bundled with this package in the files license.txt / license.rst.  It is
+ * also available through the world wide web at this URL:
+ * http://opensource.org/licenses/OSL-3.0
+ * If you did not receive a copy of the license and are unable to obtain it
+ * through the world wide web, please send an email to
+ * licensing@ellislab.com so we can send you a copy immediately.
+ *
+ * @package		CodeIgniter
+ * @author		EllisLab Dev Team
+ * @copyright	Copyright (c) 2006 - 2012 EllisLab, Inc.
+ * @license		http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
+ * @link		http://codeigniter.com
+ * @since		Version 3.0
+ * @filesource
+ */
+
+/**
+ * CodeIgniter Redis Caching Class
+ *
+ * @package	   CodeIgniter
+ * @subpackage Libraries
+ * @category   Core
+ * @author	   Anton Lindqvist <anton@qvister.se>
+ * @link
+ */
+class CI_Cache_redis extends CI_Driver
+{
+	/**
+	 * Default config
+	 *
+	 * @static
+	 * @var	array
+	 */
+	protected static $_default_config = array(
+		'host' => '127.0.0.1',
+		'password' => NULL,
+		'port' => 6379,
+		'timeout' => 0
+	);
+
+	/**
+	 * Redis connection
+	 *
+	 * @var	Redis
+	 */
+	protected $_redis;
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * Get cache
+	 *
+	 * @param	string	Cache key identifier
+	 * @return	mixed
+	 */
+	public function get($key)
+	{
+		return $this->_redis->get($key);
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * Save cache
+	 *
+	 * @param	string	Cache key identifier
+	 * @param	mixed	Data to save
+	 * @param	int	Time to live
+	 * @return	bool
+	 */
+	public function save($key, $value, $ttl = NULL)
+	{
+		return ($ttl)
+			? $this->_redis->setex($key, $ttl, $value)
+			: $this->_redis->set($key, $value);
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * Delete from cache
+	 *
+	 * @param	string	Cache key
+	 * @return	bool
+	 */
+	public function delete($key)
+	{
+		return ($this->_redis->delete($key) === 1);
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * Clean cache
+	 *
+	 * @return	bool
+	 * @see		Redis::flushDB()
+	 */
+	public function clean()
+	{
+		return $this->_redis->flushDB();
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * Get cache driver info
+	 *
+	 * @param	string	Not supported in Redis.
+	 *			Only included in order to offer a
+	 *			consistent cache API.
+	 * @return	array
+	 * @see		Redis::info()
+	 */
+	public function cache_info($type = NULL)
+	{
+		return $this->_redis->info();
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * Get cache metadata
+	 *
+	 * @param	string	Cache key
+	 * @return	array
+	 */
+	public function get_metadata($key)
+	{
+		$value = $this->get($key);
+
+		if ($value)
+		{
+			return array(
+				'expire' => time() + $this->_redis->ttl($key),
+				'data' => $value
+			);
+		}
+
+		return FALSE;
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * Check if Redis driver is supported
+	 *
+	 * @return	bool
+	 */
+	public function is_supported()
+	{
+		if (extension_loaded('redis'))
+		{
+			$this->_setup_redis();
+			return TRUE;
+		}
+		else
+		{
+			log_message('error', 'The Redis extension must be loaded to use Redis cache.');
+			return FALSE;
+		}
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * Setup Redis config and connection
+	 *
+	 * Loads Redis config file if present. Will halt execution
+	 * if a Redis connection can't be established.
+	 *
+	 * @return	bool
+	 * @see		Redis::connect()
+	 */
+	protected function _setup_redis()
+	{
+		$config = array();
+		$CI =& get_instance();
+
+		if ($CI->config->load('redis', TRUE, TRUE))
+		{
+			$config += $CI->config->item('redis');
+		}
+
+		$config = array_merge(self::$_default_config, $config);
+
+		$this->_redis = new Redis();
+
+		try
+		{
+			$this->_redis->connect($config['host'], $config['port'], $config['timeout']);
+		}
+		catch (RedisException $e)
+		{
+			show_error('Redis connection refused. ' . $e->getMessage());
+		}
+
+		if (isset($config['password']))
+		{
+			$this->_redis->auth($config['password']);
+		}
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+
+	 * Class destructor
+	 *
+	 * Closes the connection to Redis if present.
+	 *
+	 * @return	void
+	 */
+	public function __destruct()
+	{
+		if ($this->_redis)
+		{
+			$this->_redis->close();
+		}
+	}
+
+}
+
+/* End of file Cache_redis.php */
+/* Location: ./system/libraries/Cache/drivers/Cache_redis.php */
\ No newline at end of file
diff --git a/system/libraries/Cache/drivers/Cache_wincache.php b/system/libraries/Cache/drivers/Cache_wincache.php
new file mode 100644
index 0000000..74048d5
--- /dev/null
+++ b/system/libraries/Cache/drivers/Cache_wincache.php
@@ -0,0 +1,162 @@
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.1.6 or newer
+ *
+ * NOTICE OF LICENSE
+ *
+ * Licensed under the Open Software License version 3.0
+ *
+ * This source file is subject to the Open Software License (OSL 3.0) that is
+ * bundled with this package in the files license.txt / license.rst.  It is
+ * also available through the world wide web at this URL:
+ * http://opensource.org/licenses/OSL-3.0
+ * If you did not receive a copy of the license and are unable to obtain it
+ * through the world wide web, please send an email to
+ * licensing@ellislab.com so we can send you a copy immediately.
+ *
+ * @package		CodeIgniter
+ * @author		EllisLab Dev Team
+ * @copyright	Copyright (c) 2006 - 2012 EllisLab, Inc.
+ * @license		http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
+ * @link		http://codeigniter.com
+ * @since		Version 3.0
+ * @filesource
+ */
+
+/**
+ * CodeIgniter Wincache Caching Class
+ *
+ * Read more about Wincache functions here:
+ * http://www.php.net/manual/en/ref.wincache.php
+ *
+ * @package		CodeIgniter
+ * @subpackage	Libraries
+ * @category	Core
+ * @author		Mike Murkovic
+ * @link
+ */
+class CI_Cache_wincache extends CI_Driver {
+
+	/**
+	 * Get
+	 *
+	 * 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
+	 */
+	public function get($id)
+	{
+		$success = FALSE;
+		$data = wincache_ucache_get($id, $success);
+
+		// Success returned by reference from wincache_ucache_get()
+		return ($success) ? $data : FALSE;
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * 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
+	 */
+	public function save($id, $data, $ttl = 60)
+	{
+		return wincache_ucache_set($id, $data, $ttl);
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * Delete from Cache
+	 *
+	 * @param	mixed	unique identifier of the item in the cache
+	 * @return	bool	true on success/false on failure
+	 */
+	public function delete($id)
+	{
+		return wincache_ucache_delete($id);
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * Clean the cache
+	 *
+	 * @return	bool	false on failure/true on success
+	 */
+	public function clean()
+	{
+		return wincache_ucache_clear();
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * Cache Info
+	 *
+	 * @return	mixed	array on success, false on failure
+	 */
+	 public function cache_info()
+	 {
+		 return wincache_ucache_info(TRUE);
+	 }
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * Get Cache Metadata
+	 *
+	 * @param	mixed	key to get cache metadata on
+	 * @return	mixed	array on success/false on failure
+	 */
+	public function get_metadata($id)
+	{
+		if ($stored = wincache_ucache_info(FALSE, $id))
+		{
+			$age = $stored['ucache_entries'][1]['age_seconds'];
+			$ttl = $stored['ucache_entries'][1]['ttl_seconds'];
+			$hitcount = $stored['ucache_entries'][1]['hitcount'];
+
+			return array(
+				'expire'    => $ttl - $age,
+				'hitcount'  => $hitcount,
+				'age'       => $age,
+				'ttl'       => $ttl
+			);
+		}
+
+		return FALSE;
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * is_supported()
+	 *
+	 * Check to see if WinCache is available on this system, bail if it isn't.
+	 *
+	 * @return	bool
+	 */
+	public function is_supported()
+	{
+		if ( ! extension_loaded('wincache'))
+		{
+			log_message('error', 'The Wincache PHP extension must be loaded to use Wincache Cache.');
+			return FALSE;
+		}
+
+		return TRUE;
+	}
+
+}
+
+/* End of file Cache_wincache.php */
+/* Location: ./system/libraries/Cache/drivers/Cache_wincache.php */
\ No newline at end of file
diff --git a/system/libraries/Calendar.php b/system/libraries/Calendar.php
index a05a7ba..969a761 100644
--- a/system/libraries/Calendar.php
+++ b/system/libraries/Calendar.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * CodeIgniter Calendar Class
  *
@@ -40,20 +38,69 @@
  */
 class CI_Calendar {
 
-	private $CI;
-	public $lang;
+	/**
+	 * Reference to CodeIgniter instance
+	 *
+	 * @var object
+	 */
+	protected $CI;
+
+	/**
+	 * Current local time
+	 *
+	 * @var int
+	 */
 	public $local_time;
+
+	/**
+	 * Calendar layout template
+	 *
+	 * @var string
+	 */
 	public $template		= '';
+
+	/**
+	 * Day of the week to start the calendar on
+	 *
+	 * @var string
+	 */
 	public $start_day		= 'sunday';
+
+	/**
+	 * How to display months
+	 *
+	 * @var string
+	 */
 	public $month_type		= 'long';
+
+	/**
+	 * How to display names of days
+	 *
+	 * @var string
+	 */
 	public $day_type		= 'abr';
-	public $show_next_prev	= FALSE;
-	public $next_prev_url	= '';
+
+	/**
+	 * Whether to show next/prev month links
+	 *
+	 * @var bool
+	 */
+	public $show_next_prev		= FALSE;
+
+	/**
+	 * Url base to use for next/prev month links
+	 *
+	 * @var bool
+	 */
+	public $next_prev_url		= '';
 
 	/**
 	 * Constructor
 	 *
 	 * Loads the calendar language file and sets the default time reference
+	 *
+	 * @param	array
+	 * @return	void
 	 */
 	public function __construct($config = array())
 	{
@@ -71,7 +118,7 @@
 			$this->initialize($config);
 		}
 
-		log_message('debug', "Calendar Class Initialized");
+		log_message('debug', 'Calendar Class Initialized');
 	}
 
 	// --------------------------------------------------------------------
@@ -81,7 +128,6 @@
 	 *
 	 * Accepts an associative array as input, containing display preferences
 	 *
-	 * @access	public
 	 * @param	array	config preferences
 	 * @return	void
 	 */
@@ -101,16 +147,15 @@
 	/**
 	 * Generate the calendar
 	 *
-	 * @access	public
-	 * @param	integer	the year
-	 * @param	integer	the month
+	 * @param	int	the year
+	 * @param	int	the month
 	 * @param	array	the data to be shown in the calendar cells
 	 * @return	string
 	 */
 	public function generate($year = '', $month = '', $data = array())
 	{
 		// Set and validate the supplied month/year
-		if ($year == '')
+		if ($year === '')
 		{
 			$year  = date('Y', $this->local_time);
 		}
@@ -123,7 +168,7 @@
 			$year = '20'.$year;
 		}
 
-		if ($month == '')
+		if ($month === '')
 		{
 			$month = date('m', $this->local_time);
 		}
@@ -142,12 +187,12 @@
 
 		// Set the starting day of the week
 		$start_days	= array('sunday' => 0, 'monday' => 1, 'tuesday' => 2, 'wednesday' => 3, 'thursday' => 4, 'friday' => 5, 'saturday' => 6);
-		$start_day = ( ! isset($start_days[$this->start_day])) ? 0 : $start_days[$this->start_day];
+		$start_day	= isset($start_days[$this->start_day]) ? $start_days[$this->start_day] : 0;
 
 		// Set the starting day number
 		$local_date = mktime(12, 0, 0, $month, 1, $year);
 		$date = getdate($local_date);
-		$day  = $start_day + 1 - $date["wday"];
+		$day  = $start_day + 1 - $date['wday'];
 
 		while ($day > 1)
 		{
@@ -160,7 +205,7 @@
 		$cur_month	= date('m', $this->local_time);
 		$cur_day	= date('j', $this->local_time);
 
-		$is_current_month = ($cur_year == $year AND $cur_month == $month) ? TRUE : FALSE;
+		$is_current_month = ($cur_year == $year && $cur_month == $month);
 
 		// Generate the template data array
 		$this->parse_template();
@@ -169,17 +214,17 @@
 		$out = $this->temp['table_open']."\n\n".$this->temp['heading_row_start']."\n";
 
 		// "previous" month link
-		if ($this->show_next_prev == TRUE)
+		if ($this->show_next_prev === TRUE)
 		{
 			// Add a trailing slash to the  URL if needed
-			$this->next_prev_url = preg_replace("/(.+?)\/*$/", "\\1/",  $this->next_prev_url);
+			$this->next_prev_url = preg_replace('/(.+?)\/*$/', '\\1/',  $this->next_prev_url);
 
 			$adjusted_date = $this->adjust_date($month - 1, $year);
 			$out .= str_replace('{previous_url}', $this->next_prev_url.$adjusted_date['year'].'/'.$adjusted_date['month'], $this->temp['heading_previous_cell'])."\n";
 		}
 
 		// Heading containing the month/year
-		$colspan = ($this->show_next_prev == TRUE) ? 5 : 7;
+		$colspan = ($this->show_next_prev === TRUE) ? 5 : 7;
 
 		$this->temp['heading_title_cell'] = str_replace('{colspan}', $colspan,
 								str_replace('{heading}', $this->get_month_name($month).'&nbsp;'.$year, $this->temp['heading_title_cell']));
@@ -187,7 +232,7 @@
 		$out .= $this->temp['heading_title_cell']."\n";
 
 		// "next" month link
-		if ($this->show_next_prev == TRUE)
+		if ($this->show_next_prev === TRUE)
 		{
 			$adjusted_date = $this->adjust_date($month + 1, $year);
 			$out .= str_replace('{next_url}', $this->next_prev_url.$adjusted_date['year'].'/'.$adjusted_date['month'], $this->temp['heading_next_cell']);
@@ -213,21 +258,21 @@
 
 			for ($i = 0; $i < 7; $i++)
 			{
-				$out .= ($is_current_month === TRUE AND $day == $cur_day) ? $this->temp['cal_cell_start_today'] : $this->temp['cal_cell_start'];
+				$out .= ($is_current_month === TRUE && $day == $cur_day) ? $this->temp['cal_cell_start_today'] : $this->temp['cal_cell_start'];
 
-				if ($day > 0 AND $day <= $total_days)
+				if ($day > 0 && $day <= $total_days)
 				{
 					if (isset($data[$day]))
 					{
 						// Cells with content
-						$temp = ($is_current_month === TRUE AND $day == $cur_day) ?
+						$temp = ($is_current_month === TRUE && $day == $cur_day) ?
 								$this->temp['cal_cell_content_today'] : $this->temp['cal_cell_content'];
 						$out .= str_replace(array('{content}', '{day}'), array($data[$day], $day), $temp);
 					}
 					else
 					{
 						// Cells with no content
-						$temp = ($is_current_month === TRUE AND $day == $cur_day) ?
+						$temp = ($is_current_month === TRUE && $day == $cur_day) ?
 								$this->temp['cal_cell_no_content_today'] : $this->temp['cal_cell_no_content'];
 						$out .= str_replace('{day}', $day, $temp);
 					}
@@ -238,16 +283,14 @@
 					$out .= $this->temp['cal_cell_blank'];
 				}
 
-				$out .= ($is_current_month === TRUE AND $day == $cur_day) ? $this->temp['cal_cell_end_today'] : $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++;
 			}
 
 			$out .= "\n".$this->temp['cal_row_end']."\n";
 		}
 
-		$out .= "\n".$this->temp['table_close'];
-
-		return $out;
+		return $out .= "\n".$this->temp['table_close'];
 	}
 
 	// --------------------------------------------------------------------
@@ -258,13 +301,12 @@
 	 * Generates a textual month name based on the numeric
 	 * month provided.
 	 *
-	 * @access	public
-	 * @param	integer	the month
+	 * @param	int	the month
 	 * @return	string
 	 */
 	public function get_month_name($month)
 	{
-		if ($this->month_type == 'short')
+		if ($this->month_type === 'short')
 		{
 			$month_names = array('01' => 'cal_jan', '02' => 'cal_feb', '03' => 'cal_mar', '04' => 'cal_apr', '05' => 'cal_may', '06' => 'cal_jun', '07' => 'cal_jul', '08' => 'cal_aug', '09' => 'cal_sep', '10' => 'cal_oct', '11' => 'cal_nov', '12' => 'cal_dec');
 		}
@@ -273,14 +315,9 @@
 			$month_names = array('01' => 'cal_january', '02' => 'cal_february', '03' => 'cal_march', '04' => 'cal_april', '05' => 'cal_mayl', '06' => 'cal_june', '07' => 'cal_july', '08' => 'cal_august', '09' => 'cal_september', '10' => 'cal_october', '11' => 'cal_november', '12' => 'cal_december');
 		}
 
-		$month = $month_names[$month];
-
-		if ($this->CI->lang->line($month) === FALSE)
-		{
-			return ucfirst(substr($month, 4));
-		}
-
-		return $this->CI->lang->line($month);
+		return ($this->CI->lang->line($month_names[$month]) === FALSE)
+			? ucfirst(substr($month_names[$month], 4))
+			: $this->CI->lang->line($month_names[$month]);
 	}
 
 	// --------------------------------------------------------------------
@@ -289,24 +326,23 @@
 	 * Get Day Names
 	 *
 	 * Returns an array of day names (Sunday, Monday, etc.) based
-	 * on the type.  Options: long, short, abrev
+	 * on the type. Options: long, short, abrev
 	 *
-	 * @access	public
 	 * @param	string
 	 * @return	array
 	 */
 	public function get_day_names($day_type = '')
 	{
-		if ($day_type != '')
+		if ($day_type !== '')
 		{
 			$this->day_type = $day_type;
 		}
 
-		if ($this->day_type == 'long')
+		if ($this->day_type === 'long')
 		{
 			$day_names = array('sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday');
 		}
-		elseif ($this->day_type == 'short')
+		elseif ($this->day_type === 'short')
 		{
 			$day_names = array('sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat');
 		}
@@ -333,9 +369,8 @@
 	 * For example, if you submit 13 as the month, the year will
 	 * increment and the month will become January.
 	 *
-	 * @access	public
-	 * @param	integer	the month
-	 * @param	integer	the year
+	 * @param	int	the month
+	 * @param	int	the year
 	 * @return	array
 	 */
 	public function adjust_date($month, $year)
@@ -370,10 +405,9 @@
 	/**
 	 * Total days in a given month
 	 *
-	 * @access	public
-	 * @param	integer	the month
-	 * @param	integer	the year
-	 * @return	integer
+	 * @param	int	the month
+	 * @param	int	the year
+	 * @return	int
 	 */
 	public function get_total_days($month, $year)
 	{
@@ -387,7 +421,7 @@
 		// Is the year a leap year?
 		if ($month == 2)
 		{
-			if ($year % 400 == 0 OR ($year % 4 == 0 AND $year % 100 != 0))
+			if ($year % 400 === 0 OR ($year % 4 === 0 && $year % 100 !== 0))
 			{
 				return 29;
 			}
@@ -403,34 +437,33 @@
 	 *
 	 * This is used in the event that the user has not created their own template
 	 *
-	 * @access	public
-	 * @return array
+	 * @return	array
 	 */
 	public function default_template()
 	{
-		return  array (
-						'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>',
-						'cal_cell_start_today'		=> '<td>',
-						'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_end_today'		=> '</td>',
-						'cal_row_end'				=> '</tr>',
-						'table_close'				=> '</table>'
-					);
+		return  array(
+			'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>',
+			'cal_cell_start_today'		=> '<td>',
+			'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_end_today'		=> '</td>',
+			'cal_row_end'				=> '</tr>',
+			'table_close'				=> '</table>'
+		);
 	}
 
 	// --------------------------------------------------------------------
@@ -441,14 +474,13 @@
 	 * Harvests the data within the template {pseudo-variables}
 	 * used to display the calendar
 	 *
-	 * @access	public
 	 * @return	void
 	 */
 	public function parse_template()
 	{
 		$this->temp = $this->default_template();
 
-		if ($this->template == '')
+		if ($this->template === '')
 		{
 			return;
 		}
@@ -457,7 +489,7 @@
 
 		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)
 		{
-			if (preg_match("/\{".$val."\}(.*?)\{\/".$val."\}/si", $this->template, $match))
+			if (preg_match('/\{'.$val.'\}(.*?)\{\/'.$val.'\}/si', $this->template, $match))
 			{
 				$this->temp[$val] = $match[1];
 			}
@@ -470,7 +502,5 @@
 
 }
 
-// END CI_Calendar class
-
 /* End of file Calendar.php */
-/* Location: ./system/libraries/Calendar.php */
+/* Location: ./system/libraries/Calendar.php */
\ No newline at end of file
diff --git a/system/libraries/Cart.php b/system/libraries/Cart.php
index ba8d69b..c442f88 100644
--- a/system/libraries/Cart.php
+++ b/system/libraries/Cart.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * Shopping Cart Class
  *
@@ -38,20 +36,54 @@
  */
 class CI_Cart {
 
-	// These are the regular expression rules that we use to validate the product ID and product name
-	public $product_id_rules	= '\.a-z0-9_-'; // alpha-numeric, dashes, underscores, or periods
-	public $product_name_rules	= '\.\:\-_ a-z0-9'; // alpha-numeric, dashes, underscores, colons or periods
-	public $product_name_safe  = true; // only allow safe product names
+	/**
+	 * These are the regular expression rules that we use to validate the product ID and product name
+	 * alpha-numeric, dashes, underscores, or periods
+	 *
+	 * @var string
+	 */
+	public $product_id_rules	= '\.a-z0-9_-';
 
-	// Private variables.  Do not change!
-	private $CI;
-	private $_cart_contents	= array();
+	/**
+	 * These are the regular expression rules that we use to validate the product ID and product name
+	 * alpha-numeric, dashes, underscores, colons or periods
+	 *
+	 * @var string
+	 */
+	public $product_name_rules	= '\.\:\-_ a-z0-9';
 
+	/**
+	 * only allow safe product names
+	 *
+	 * @var bool
+	 */
+	public $product_name_safe	= TRUE;
+
+	// --------------------------------------------------------------------------
+	// Protected variables. Do not change!
+	// --------------------------------------------------------------------------
+
+	/**
+	 * Reference to CodeIgniter instance
+	 *
+	 * @var object
+	 */
+	protected $CI;
+
+	/**
+	 * Contents of the cart
+	 *
+	 * @var array
+	 */
+	protected $_cart_contents	= array();
 
 	/**
 	 * Shopping Class Constructor
 	 *
 	 * The constructor loads the Session class, used to store the shopping cart contents.
+	 *
+	 * @param	array
+	 * @return	void
 	 */
 	public function __construct($params = array())
 	{
@@ -72,7 +104,7 @@
 			$this->_cart_contents = array('cart_total' => 0, 'total_items' => 0);
 		}
 
-		log_message('debug', "Cart Class Initialized");
+		log_message('debug', 'Cart Class Initialized');
 	}
 
 	// --------------------------------------------------------------------
@@ -80,7 +112,6 @@
 	/**
 	 * Insert items into the cart and save it to the session table
 	 *
-	 * @access	public
 	 * @param	array
 	 * @return	bool
 	 */
@@ -110,7 +141,7 @@
 		{
 			foreach ($items as $val)
 			{
-				if (is_array($val) AND isset($val['id']))
+				if (is_array($val) && isset($val['id']))
 				{
 					if ($this->_insert($val))
 					{
@@ -135,11 +166,10 @@
 	/**
 	 * Insert
 	 *
-	 * @access	private
 	 * @param	array
 	 * @return	bool
 	 */
-	private function _insert($items = array())
+	protected function _insert($items = array())
 	{
 		// Was any cart data passed? No? Bah...
 		if ( ! is_array($items) OR count($items) === 0)
@@ -151,7 +181,7 @@
 		// --------------------------------------------------------------------
 
 		// Does the $items array contain an id, quantity, price, and name?  These are required
-		if ( ! isset($items['id']) OR ! isset($items['qty']) OR ! isset($items['price']) OR ! isset($items['name']))
+		if ( ! isset($items['id'], $items['qty'], $items['price'], $items['name']))
 		{
 			log_message('error', 'The cart array must contain a product ID, quantity, price, and name.');
 			return FALSE;
@@ -213,9 +243,9 @@
 		// Internally, we need to treat identical submissions, but with different options, as a unique product.
 		// Our solution is to convert the options array to a string and MD5 it along with the product ID.
 		// This becomes the unique "row ID"
-		if (isset($items['options']) AND count($items['options']) > 0)
+		if (isset($items['options']) && count($items['options']) > 0)
 		{
-			$rowid = md5($items['id'].implode('', $items['options']));
+			$rowid = md5($items['id'].serialize($items['options']));
 		}
 		else
 		{
@@ -249,9 +279,7 @@
 	 * changes to the quantity before checkout. That array must contain the
 	 * product ID and quantity for each item.
 	 *
-	 * @access	public
 	 * @param	array
-	 * @param	string
 	 * @return	bool
 	 */
 	public function update($items = array())
@@ -308,14 +336,13 @@
 	 * changes to the quantity before checkout. That array must contain the
 	 * product ID and quantity for each item.
 	 *
-	 * @access	private
 	 * @param	array
 	 * @return	bool
 	 */
-	private function _update($items = array())
+	protected function _update($items = array())
 	{
 		// Without these array indexes there is nothing we can do
-		if ( ! isset($items['qty']) OR ! isset($items['rowid']) OR ! isset($this->_cart_contents[$items['rowid']]))
+		if ( ! isset($items['qty'], $items['rowid'], $this->_cart_contents[$items['rowid']]))
 		{
 			return FALSE;
 		}
@@ -329,13 +356,6 @@
 			return FALSE;
 		}
 
-		// Is the new quantity different than what is already saved in the cart?
-		// If it's the same there's nothing to do
-		if ($this->_cart_contents[$items['rowid']]['qty'] == $items['qty'])
-		{
-			return FALSE;
-		}
-
 		// Is the quantity zero?  If so we will remove the item from the cart.
 		// If the quantity is greater than zero we are updating
 		if ($items['qty'] == 0)
@@ -355,17 +375,16 @@
 	/**
 	 * Save the cart array to the session DB
 	 *
-	 * @access	private
 	 * @return	bool
 	 */
-	private function _save_cart()
+	protected function _save_cart()
 	{
 		// Lets add up the individual prices and set the cart sub-total
 		$this->_cart_contents['total_items'] = $this->_cart_contents['cart_total'] = 0;
 		foreach ($this->_cart_contents as $key => $val)
 		{
 			// We make sure the array contains the proper indexes
-			if ( ! is_array($val) OR ! isset($val['price']) OR ! isset($val['qty']))
+			if ( ! is_array($val) OR ! isset($val['price'], $val['qty']))
 			{
 				continue;
 			}
@@ -375,7 +394,7 @@
 			$this->_cart_contents[$key]['subtotal'] = ($this->_cart_contents[$key]['price'] * $this->_cart_contents[$key]['qty']);
 		}
 
-		// Is our cart empty?  If so we delete it from the session
+		// Is our cart empty? If so we delete it from the session
 		if (count($this->_cart_contents) <= 2)
 		{
 			$this->CI->session->unset_userdata('cart_contents');
@@ -397,8 +416,7 @@
 	/**
 	 * Cart Total
 	 *
-	 * @access	public
-	 * @return	integer
+	 * @return	int
 	 */
 	public function total()
 	{
@@ -412,8 +430,8 @@
 	 *
 	 * Removes an item from the cart
 	 *
-	 * @access	public
-	 * @return	boolean
+	 * @param	int
+	 * @return	bool
 	 */
 	 public function remove($rowid)
 	 {
@@ -430,8 +448,7 @@
 	 *
 	 * Returns the total item count
 	 *
-	 * @access	public
-	 * @return	integer
+	 * @return	int
 	 */
 	public function total_items()
 	{
@@ -445,7 +462,7 @@
 	 *
 	 * Returns the entire cart array
 	 *
-	 * @access	public
+	 * @param	bool
 	 * @return	array
 	 */
 	public function contents($newest_first = FALSE)
@@ -468,12 +485,12 @@
 	 * Returns TRUE if the rowid passed to this function correlates to an item
 	 * that has options associated with it.
 	 *
-	 * @access	public
+	 * @param	mixed
 	 * @return	bool
 	 */
 	public function has_options($rowid = '')
 	{
-		return (isset($this->_cart_contents[$rowid]['options']) && count($this->_cart_contents[$rowid]['options']) !== 0) ? TRUE : FALSE;
+		return (isset($this->_cart_contents[$rowid]['options']) && count($this->_cart_contents[$rowid]['options']) !== 0);
 	}
 
 	// --------------------------------------------------------------------
@@ -483,7 +500,7 @@
 	 *
 	 * Returns the an array of options, for a particular product row ID
 	 *
-	 * @access	public
+	 * @param	int
 	 * @return	array
 	 */
 	public function product_options($rowid = '')
@@ -498,20 +515,12 @@
 	 *
 	 * Returns the supplied number with commas and a decimal point.
 	 *
-	 * @access	public
+	 * @param	float
 	 * @return	string
 	 */
 	public function format_number($n = '')
 	{
-		if ($n == '')
-		{
-			return '';
-		}
-
-		// Remove anything that isn't a number or decimal point.
-		$n = (float) $n;
-
-		return number_format($n, 2, '.', ',');
+		return ($n === '') ? '' : number_format( (float) $n, 2, '.', ',');
 	}
 
 	// --------------------------------------------------------------------
@@ -521,7 +530,6 @@
 	 *
 	 * Empties the cart and kills the session
 	 *
-	 * @access	public
 	 * @return	void
 	 */
 	public function destroy()
@@ -530,9 +538,7 @@
 		$this->CI->session->unset_userdata('cart_contents');
 	}
 
-
 }
-// END Cart Class
 
 /* End of file Cart.php */
-/* Location: ./system/libraries/Cart.php */
+/* Location: ./system/libraries/Cart.php */
\ No newline at end of file
diff --git a/system/libraries/Driver.php b/system/libraries/Driver.php
index 4e89443..d67ee25 100644
--- a/system/libraries/Driver.php
+++ b/system/libraries/Driver.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * CodeIgniter Driver Library Class
  *
@@ -41,11 +39,27 @@
  */
 class CI_Driver_Library {
 
-	protected $valid_drivers	= array();
-	protected static $lib_name;
+	/**
+	 * Array of drivers that are available to use with the driver class
+	 *
+	 * @var array
+	 */
+	protected $valid_drivers = array();
 
-	// The first time a child is used it won't exist, so we instantiate it
-	// subsequents calls will go straight to the proper child.
+	/**
+	 * Name of the current class - usually the driver class
+	 *
+	 * @var string
+	 */
+	protected $lib_name;
+
+	/**
+	 * The first time a child is used it won't exist, so we instantiate it
+	 * subsequents calls will go straight to the proper child.
+	 *
+	 * @param	mixed	$child
+	 * @return	mixed
+	 */
 	public function __get($child)
 	{
 		if ( ! isset($this->lib_name))
@@ -84,8 +98,8 @@
 				// it's a valid driver, but the file simply can't be found
 				if ( ! class_exists($child_class))
 				{
-					log_message('error', "Unable to load the requested driver: ".$child_class);
-					show_error("Unable to load the requested driver: ".$child_class);
+					log_message('error', 'Unable to load the requested driver: '.$child_class);
+					show_error('Unable to load the requested driver: '.$child_class);
 				}
 			}
 
@@ -96,15 +110,13 @@
 		}
 
 		// The requested driver isn't valid!
-		log_message('error', "Invalid driver requested: ".$child_class);
-		show_error("Invalid driver requested: ".$child_class);
+		log_message('error', 'Invalid driver requested: '.$child_class);
+		show_error('Invalid driver requested: '.$child_class);
 	}
 
-	// --------------------------------------------------------------------
-
 }
-// END CI_Driver_Library CLASS
 
+// --------------------------------------------------------------------------
 
 /**
  * CodeIgniter Driver Class
@@ -120,12 +132,33 @@
  */
 class CI_Driver {
 
-	protected $parent;
+	/**
+	 * Instance of the parent class
+	 *
+	 * @var object
+	 */
+	protected $_parent;
 
-	private $methods = array();
-	private $properties = array();
+	/**
+	 * List of methods in the parent class
+	 *
+	 * @var array
+	 */
+	protected $_methods = array();
 
-	private static $reflections = array();
+	/**
+	 * List of properties in the parent class
+	 *
+	 * @var array
+	 */
+	protected $_properties = array();
+
+	/**
+	 * Array of methods and properties for the parent class(es)
+	 *
+	 * @var array
+	 */
+	protected static $_reflections = array();
 
 	/**
 	 * Decorate
@@ -137,14 +170,14 @@
 	 */
 	public function decorate($parent)
 	{
-		$this->parent = $parent;
+		$this->_parent = $parent;
 
 		// Lock down attributes to what is defined in the class
 		// and speed up references in magic methods
 
 		$class_name = get_class($parent);
 
-		if ( ! isset(self::$reflections[$class_name]))
+		if ( ! isset(self::$_reflections[$class_name]))
 		{
 			$r = new ReflectionObject($parent);
 
@@ -152,7 +185,7 @@
 			{
 				if ($method->isPublic())
 				{
-					$this->methods[] = $method->getName();
+					$this->_methods[] = $method->getName();
 				}
 			}
 
@@ -160,15 +193,15 @@
 			{
 				if ($prop->isPublic())
 				{
-					$this->properties[] = $prop->getName();
+					$this->_properties[] = $prop->getName();
 				}
 			}
 
-			self::$reflections[$class_name] = array($this->methods, $this->properties);
+			self::$_reflections[$class_name] = array($this->_methods, $this->_properties);
 		}
 		else
 		{
-			list($this->methods, $this->properties) = self::$reflections[$class_name];
+			list($this->_methods, $this->_properties) = self::$_reflections[$class_name];
 		}
 	}
 
@@ -179,16 +212,15 @@
 	 *
 	 * Handles access to the parent driver library's methods
 	 *
-	 * @access	public
 	 * @param	string
 	 * @param	array
 	 * @return	mixed
 	 */
 	public function __call($method, $args = array())
 	{
-		if (in_array($method, $this->methods))
+		if (in_array($method, $this->_methods))
 		{
-			return call_user_func_array(array($this->parent, $method), $args);
+			return call_user_func_array(array($this->_parent, $method), $args);
 		}
 
 		$trace = debug_backtrace();
@@ -208,9 +240,9 @@
 	 */
 	public function __get($var)
 	{
-		if (in_array($var, $this->properties))
+		if (in_array($var, $this->_properties))
 		{
-			return $this->parent->$var;
+			return $this->_parent->$var;
 		}
 	}
 
@@ -227,16 +259,13 @@
 	 */
 	public function __set($var, $val)
 	{
-		if (in_array($var, $this->properties))
+		if (in_array($var, $this->_properties))
 		{
-			$this->parent->$var = $val;
+			$this->_parent->$var = $val;
 		}
 	}
 
-	// --------------------------------------------------------------------
-
 }
-// END CI_Driver CLASS
 
 /* End of file Driver.php */
-/* Location: ./system/libraries/Driver.php */
+/* Location: ./system/libraries/Driver.php */
\ No newline at end of file
diff --git a/system/libraries/Email.php b/system/libraries/Email.php
index 922107e..09f2175 100644
--- a/system/libraries/Email.php
+++ b/system/libraries/Email.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * CodeIgniter Email Class
  *
@@ -40,60 +38,63 @@
  */
 class CI_Email {
 
-	public $useragent		= "CodeIgniter";
-	public $mailpath		= "/usr/sbin/sendmail";	// Sendmail path
-	public $protocol		= "mail";	// mail/sendmail/smtp
-	public $smtp_host		= "";		// SMTP Server.  Example: mail.earthlink.net
-	public $smtp_user		= "";		// SMTP Username
-	public $smtp_pass		= "";		// SMTP Password
-	public $smtp_port		= "25";		// SMTP Port
-	public $smtp_timeout	= 5;		// SMTP Timeout in seconds
-	public $smtp_crypto	= "";		// SMTP Encryption. Can be null, tls or ssl.
-	public $wordwrap		= TRUE;		// TRUE/FALSE  Turns word-wrap on/off
-	public $wrapchars		= "76";		// Number of characters to wrap at.
-	public $mailtype		= "text";	// text/html  Defines email formatting
-	public $charset		= "utf-8";	// Default char set: iso-8859-1 or us-ascii
-	public $multipart		= "mixed";	// "mixed" (in the body) or "related" (separate)
-	public $alt_message	= '';		// Alternative message for HTML emails
-	public $validate		= FALSE;	// TRUE/FALSE.  Enables email validation
-	public $priority		= "3";		// Default priority (1 - 5)
-	public $newline		= "\n";		// Default newline. "\r\n" or "\n" (Use "\r\n" to comply with RFC 822)
-	public $crlf			= "\n";		// The RFC 2045 compliant CRLF for quoted-printable is "\r\n".  Apparently some servers,
+	public $useragent	= 'CodeIgniter';
+	public $mailpath	= '/usr/sbin/sendmail';	// Sendmail path
+	public $protocol	= 'mail';		// mail/sendmail/smtp
+	public $smtp_host	= '';			// SMTP Server. Example: mail.earthlink.net
+	public $smtp_user	= '';			// SMTP Username
+	public $smtp_pass	= '';			// SMTP Password
+	public $smtp_port	= 25;			// SMTP Port
+	public $smtp_timeout	= 5;			// SMTP Timeout in seconds
+	public $smtp_crypto	= '';			// SMTP Encryption. Can be null, tls or ssl.
+	public $wordwrap	= TRUE;			// TRUE/FALSE  Turns word-wrap on/off
+	public $wrapchars	= 76;			// Number of characters to wrap at.
+	public $mailtype	= 'text';		// text/html  Defines email formatting
+	public $charset		= 'utf-8';		// Default char set: iso-8859-1 or us-ascii
+	public $multipart	= 'mixed';		// "mixed" (in the body) or "related" (separate)
+	public $alt_message	= '';			// Alternative message for HTML emails
+	public $validate	= FALSE;		// TRUE/FALSE.  Enables email validation
+	public $priority	= 3;			// Default priority (1 - 5)
+	public $newline		= "\n";			// Default newline. "\r\n" or "\n" (Use "\r\n" to comply with RFC 822)
+	public $crlf		= "\n";			// The RFC 2045 compliant CRLF for quoted-printable is "\r\n".  Apparently some servers,
 									// even on the receiving end think they need to muck with CRLFs, so using "\n", while
 									// distasteful, is the only thing that seems to work for all environments.
+	public $dsn		= FALSE;		// Delivery Status Notification
 	public $send_multipart	= TRUE;		// TRUE/FALSE - Yahoo does not like multipart alternative, so this is an override.  Set to FALSE for Yahoo.
-	public $bcc_batch_mode	= FALSE;	// TRUE/FALSE  Turns on/off Bcc batch feature
+	public $bcc_batch_mode	= FALSE;	// TRUE/FALSE - Turns on/off Bcc batch feature
 	public $bcc_batch_size	= 200;		// If bcc_batch_mode = TRUE, sets max number of Bccs in each batch
-	private $_safe_mode		= FALSE;
-	private $_subject		= "";
-	private $_body			= "";
-	private $_finalbody		= "";
-	private $_alt_boundary	= "";
-	private $_atc_boundary	= "";
-	private $_header_str	= "";
-	private $_smtp_connect	= "";
-	private $_encoding		= "8bit";
-	private $_IP			= FALSE;
-	private $_smtp_auth		= FALSE;
-	private $_replyto_flag	= FALSE;
-	private $_debug_msg		= array();
-	private $_recipients	= array();
-	private $_cc_array		= array();
-	private $_bcc_array		= array();
-	private $_headers		= array();
-	private $_attach_name	= array();
-	private $_attach_type	= array();
-	private $_attach_disp	= array();
-	private $_protocols		= array('mail', 'sendmail', 'smtp');
-	private $_base_charsets	= array('us-ascii', 'iso-2022-');	// 7-bit charsets (excluding language suffix)
-	private $_bit_depths	= array('7bit', '8bit');
-	private $_priorities	= array('1 (Highest)', '2 (High)', '3 (Normal)', '4 (Low)', '5 (Lowest)');
 
+	protected $_safe_mode		= FALSE;
+	protected $_subject		= '';
+	protected $_body		= '';
+	protected $_finalbody		= '';
+	protected $_alt_boundary	= '';
+	protected $_atc_boundary	= '';
+	protected $_header_str		= '';
+	protected $_smtp_connect	= '';
+	protected $_encoding		= '8bit';
+	protected $_IP			= FALSE;
+	protected $_smtp_auth		= FALSE;
+	protected $_replyto_flag	= FALSE;
+	protected $_debug_msg		= array();
+	protected $_recipients		= array();
+	protected $_cc_array		= array();
+	protected $_bcc_array		= array();
+	protected $_headers		= array();
+	protected $_attach_name		= array();
+	protected $_attach_type		= array();
+	protected $_attach_disp		= array();
+	protected $_protocols		= array('mail', 'sendmail', 'smtp');
+	protected $_base_charsets	= array('us-ascii', 'iso-2022-');	// 7-bit charsets (excluding language suffix)
+	protected $_bit_depths		= array('7bit', '8bit');
+	protected $_priorities		= array('1 (Highest)', '2 (High)', '3 (Normal)', '4 (Low)', '5 (Lowest)');
 
 	/**
 	 * Constructor - Sets Email Preferences
 	 *
 	 * The constructor can be passed an array of config values
+	 *
+	 * @return	void
 	 */
 	public function __construct($config = array())
 	{
@@ -103,11 +104,11 @@
 		}
 		else
 		{
-			$this->_smtp_auth = ($this->smtp_user == '' AND $this->smtp_pass == '') ? FALSE : TRUE;
-			$this->_safe_mode = (bool) @ini_get("safe_mode");
+			$this->_smtp_auth = ! ($this->smtp_user === '' && $this->smtp_pass === '');
+			$this->_safe_mode = (bool) @ini_get('safe_mode');
 		}
 
-		log_message('debug', "Email Class Initialized");
+		log_message('debug', 'Email Class Initialized');
 	}
 
 	// --------------------------------------------------------------------
@@ -115,7 +116,6 @@
 	/**
 	 * Initialize preferences
 	 *
-	 * @access	public
 	 * @param	array
 	 * @return	void
 	 */
@@ -139,8 +139,8 @@
 		}
 		$this->clear();
 
-		$this->_smtp_auth = ($this->smtp_user == '' AND $this->smtp_pass == '') ? FALSE : TRUE;
-		$this->_safe_mode = (bool) @ini_get("safe_mode");
+		$this->_smtp_auth = ! ($this->smtp_user === '' && $this->smtp_pass === '');
+		$this->_safe_mode = (bool) @ini_get('safe_mode');
 
 		return $this;
 	}
@@ -150,25 +150,24 @@
 	/**
 	 * Initialize the Email Data
 	 *
-	 * @access	public
 	 * @param	bool
-	 * @return	void
+	 * @return	object
 	 */
 	public function clear($clear_attachments = FALSE)
 	{
-		$this->_subject		= "";
-		$this->_body		= "";
-		$this->_finalbody	= "";
-		$this->_header_str	= "";
-		$this->_replyto_flag = FALSE;
+		$this->_subject		= '';
+		$this->_body		= '';
+		$this->_finalbody	= '';
+		$this->_header_str	= '';
+		$this->_replyto_flag	= FALSE;
 		$this->_recipients	= array();
 		$this->_cc_array	= array();
 		$this->_bcc_array	= array();
 		$this->_headers		= array();
 		$this->_debug_msg	= array();
 
-		$this->_set_header('User-Agent', $this->useragent);
-		$this->_set_header('Date', $this->_set_date());
+		$this->set_header('User-Agent', $this->useragent);
+		$this->set_header('Date', $this->_set_date());
 
 		if ($clear_attachments !== FALSE)
 		{
@@ -185,14 +184,13 @@
 	/**
 	 * Set FROM
 	 *
-	 * @access	public
 	 * @param	string
 	 * @param	string
-	 * @return	void
+	 * @return	object
 	 */
 	public function from($from, $name = '')
 	{
-		if (preg_match( '/\<(.*)\>/', $from, $match))
+		if (preg_match('/\<(.*)\>/', $from, $match))
 		{
 			$from = $match[1];
 		}
@@ -203,7 +201,7 @@
 		}
 
 		// prepare the display name
-		if ($name != '')
+		if ($name !== '')
 		{
 			// only use Q encoding if there are characters that would require it
 			if ( ! preg_match('/[\200-\377]/', $name))
@@ -217,8 +215,8 @@
 			}
 		}
 
-		$this->_set_header('From', $name.' <'.$from.'>');
-		$this->_set_header('Return-Path', '<'.$from.'>');
+		$this->set_header('From', $name.' <'.$from.'>');
+		$this->set_header('Return-Path', '<'.$from.'>');
 
 		return $this;
 	}
@@ -228,14 +226,13 @@
 	/**
 	 * Set Reply-to
 	 *
-	 * @access	public
 	 * @param	string
 	 * @param	string
-	 * @return	void
+	 * @return	object
 	 */
 	public function reply_to($replyto, $name = '')
 	{
-		if (preg_match( '/\<(.*)\>/', $replyto, $match))
+		if (preg_match('/\<(.*)\>/', $replyto, $match))
 		{
 			$replyto = $match[1];
 		}
@@ -245,7 +242,7 @@
 			$this->validate_email($this->_str_to_array($replyto));
 		}
 
-		if ($name == '')
+		if ($name === '')
 		{
 			$name = $replyto;
 		}
@@ -255,7 +252,7 @@
 			$name = '"'.$name.'"';
 		}
 
-		$this->_set_header('Reply-To', $name.' <'.$replyto.'>');
+		$this->set_header('Reply-To', $name.' <'.$replyto.'>');
 		$this->_replyto_flag = TRUE;
 
 		return $this;
@@ -266,9 +263,8 @@
 	/**
 	 * Set Recipients
 	 *
-	 * @access	public
 	 * @param	string
-	 * @return	void
+	 * @return	object
 	 */
 	public function to($to)
 	{
@@ -282,17 +278,17 @@
 
 		if ($this->_get_protocol() !== 'mail')
 		{
-			$this->_set_header('To', implode(", ", $to));
+			$this->set_header('To', implode(', ', $to));
 		}
 
 		switch ($this->_get_protocol())
 		{
-			case 'smtp'		:
+			case 'smtp':
 				$this->_recipients = $to;
 			break;
-			case 'sendmail'	:
-			case 'mail'		:
-				$this->_recipients = implode(", ", $to);
+			case 'sendmail':
+			case 'mail':
+				$this->_recipients = implode(', ', $to);
 			break;
 		}
 
@@ -304,21 +300,19 @@
 	/**
 	 * Set CC
 	 *
-	 * @access	public
 	 * @param	string
-	 * @return	void
+	 * @return	object
 	 */
 	public function cc($cc)
 	{
-		$cc = $this->_str_to_array($cc);
-		$cc = $this->clean_email($cc);
+		$cc = $this->clean_email($this->_str_to_array($cc));
 
 		if ($this->validate)
 		{
 			$this->validate_email($cc);
 		}
 
-		$this->_set_header('Cc', implode(", ", $cc));
+		$this->set_header('Cc', implode(', ', $cc));
 
 		if ($this->_get_protocol() === 'smtp')
 		{
@@ -333,21 +327,19 @@
 	/**
 	 * Set BCC
 	 *
-	 * @access	public
 	 * @param	string
 	 * @param	string
-	 * @return	void
+	 * @return	object
 	 */
 	public function bcc($bcc, $limit = '')
 	{
-		if ($limit != '' && is_numeric($limit))
+		if ($limit !== '' && is_numeric($limit))
 		{
 			$this->bcc_batch_mode = TRUE;
 			$this->bcc_batch_size = $limit;
 		}
 
-		$bcc = $this->_str_to_array($bcc);
-		$bcc = $this->clean_email($bcc);
+		$bcc = $this->clean_email($this->_str_to_array($bcc));
 
 		if ($this->validate)
 		{
@@ -360,7 +352,7 @@
 		}
 		else
 		{
-			$this->_set_header('Bcc', implode(", ", $bcc));
+			$this->set_header('Bcc', implode(', ', $bcc));
 		}
 
 		return $this;
@@ -371,14 +363,13 @@
 	/**
 	 * Set Email Subject
 	 *
-	 * @access	public
 	 * @param	string
-	 * @return	void
+	 * @return	object
 	 */
 	public function subject($subject)
 	{
 		$subject = $this->_prep_q_encoding($subject);
-		$this->_set_header('Subject', $subject);
+		$this->set_header('Subject', $subject);
 		return $this;
 	}
 
@@ -387,13 +378,12 @@
 	/**
 	 * Set Body
 	 *
-	 * @access	public
 	 * @param	string
-	 * @return	void
+	 * @return	object
 	 */
 	public function message($body)
 	{
-		$this->_body = rtrim(str_replace("\r", "", $body));
+		$this->_body = rtrim(str_replace("\r", '', $body));
 
 		/* strip slashes only if magic quotes is ON
 		   if we do it with magic quotes OFF, it strips real, user-inputted chars.
@@ -414,15 +404,14 @@
 	/**
 	 * Assign file attachments
 	 *
-	 * @access	public
 	 * @param	string
-	 * @return	void
+	 * @return	object
 	 */
-	public function attach($filename, $disposition = '', $newname = NULL)
+	public function attach($filename, $disposition = '', $newname = NULL, $mime = '')
 	{
 		$this->_attach_name[] = array($filename, $newname);
-		$this->_attach_type[] = $this->_mime_types(pathinfo($filename, PATHINFO_EXTENSION));
 		$this->_attach_disp[] = empty($disposition) ? 'attachment' : $disposition; // Can also be 'inline'  Not sure if it matters
+		$this->_attach_type[] = $mime;
 		return $this;
 	}
 
@@ -431,12 +420,11 @@
 	/**
 	 * Add a Header Item
 	 *
-	 * @access	protected
 	 * @param	string
 	 * @param	string
 	 * @return	void
 	 */
-	protected function _set_header($header, $value)
+	public function set_header($header, $value)
 	{
 		$this->_headers[$header] = $value;
 	}
@@ -446,7 +434,6 @@
 	/**
 	 * Convert a String to an Array
 	 *
-	 * @access	protected
 	 * @param	string
 	 * @return	array
 	 */
@@ -454,16 +441,11 @@
 	{
 		if ( ! is_array($email))
 		{
-			if (strpos($email, ',') !== FALSE)
-			{
-				$email = preg_split('/[\s,]/', $email, -1, PREG_SPLIT_NO_EMPTY);
-			}
-			else
-			{
-				$email = trim($email);
-				settype($email, "array");
-			}
+			return (strpos($email, ',') !== FALSE)
+				? preg_split('/[\s,]/', $email, -1, PREG_SPLIT_NO_EMPTY)
+				: (array) trim($email);
 		}
+
 		return $email;
 	}
 
@@ -472,9 +454,8 @@
 	/**
 	 * Set Multipart Value
 	 *
-	 * @access	public
 	 * @param	string
-	 * @return	void
+	 * @return	object
 	 */
 	public function set_alt_message($str = '')
 	{
@@ -487,13 +468,12 @@
 	/**
 	 * Set Mailtype
 	 *
-	 * @access	public
 	 * @param	string
-	 * @return	void
+	 * @return	object
 	 */
 	public function set_mailtype($type = 'text')
 	{
-		$this->mailtype = ($type == 'html') ? 'html' : 'text';
+		$this->mailtype = ($type === 'html') ? 'html' : 'text';
 		return $this;
 	}
 
@@ -502,9 +482,8 @@
 	/**
 	 * Set Wordwrap
 	 *
-	 * @access	public
 	 * @param	bool
-	 * @return	void
+	 * @return	object
 	 */
 	public function set_wordwrap($wordwrap = TRUE)
 	{
@@ -517,13 +496,12 @@
 	/**
 	 * Set Protocol
 	 *
-	 * @access	public
 	 * @param	string
-	 * @return	void
+	 * @return	object
 	 */
 	public function set_protocol($protocol = 'mail')
 	{
-		$this->protocol = ( ! in_array($protocol, $this->_protocols, TRUE)) ? 'mail' : strtolower($protocol);
+		$this->protocol = in_array($protocol, $this->_protocols, TRUE) ? strtolower($protocol) : 'mail';
 		return $this;
 	}
 
@@ -532,19 +510,12 @@
 	/**
 	 * Set Priority
 	 *
-	 * @access	public
-	 * @param	integer
-	 * @return	void
+	 * @param	int
+	 * @return	object
 	 */
 	public function set_priority($n = 3)
 	{
-		if ( ! is_numeric($n) OR $n < 1 OR $n > 5)
-		{
-			$this->priority = 3;
-			return;
-		}
-
-		$this->priority = (int) $n;
+		$this->priority = preg_match('/^[1-5]$/', $n) ? (int) $n : 3;
 		return $this;
 	}
 
@@ -553,9 +524,8 @@
 	/**
 	 * Set Newline Character
 	 *
-	 * @access	public
 	 * @param	string
-	 * @return	void
+	 * @return	object
 	 */
 	public function set_newline($newline = "\n")
 	{
@@ -568,13 +538,12 @@
 	/**
 	 * Set CRLF
 	 *
-	 * @access	public
 	 * @param	string
-	 * @return	void
+	 * @return	object
 	 */
 	public function set_crlf($crlf = "\n")
 	{
-		$this->crlf = ($crlf !== "\n" AND $crlf !== "\r\n" AND $crlf !== "\r") ? "\n" : $crlf;
+		$this->crlf = ($crlf !== "\n" && $crlf !== "\r\n" && $crlf !== "\r") ? "\n" : $crlf;
 		return $this;
 	}
 
@@ -583,13 +552,12 @@
 	/**
 	 * Set Message Boundary
 	 *
-	 * @access	protected
 	 * @return	void
 	 */
 	protected function _set_boundaries()
 	{
-		$this->_alt_boundary = "B_ALT_".uniqid(''); // multipart/alternative
-		$this->_atc_boundary = "B_ATC_".uniqid(''); // attachment boundary
+		$this->_alt_boundary = 'B_ALT_'.uniqid(''); // multipart/alternative
+		$this->_atc_boundary = 'B_ATC_'.uniqid(''); // attachment boundary
 	}
 
 	// --------------------------------------------------------------------
@@ -597,14 +565,12 @@
 	/**
 	 * Get the Message ID
 	 *
-	 * @access	protected
 	 * @return	string
 	 */
 	protected function _get_message_id()
 	{
 		$from = str_replace(array('>', '<'), '', $this->_headers['Return-Path']);
-
-		return  "<".uniqid('').strstr($from, '@').">";
+		return '<'.uniqid('').strstr($from, '@').'>';
 	}
 
 	// --------------------------------------------------------------------
@@ -612,16 +578,15 @@
 	/**
 	 * Get Mail Protocol
 	 *
-	 * @access	protected
 	 * @param	bool
-	 * @return	string
+	 * @return	mixed
 	 */
 	protected function _get_protocol($return = TRUE)
 	{
 		$this->protocol = strtolower($this->protocol);
-		$this->protocol = ( ! in_array($this->protocol, $this->_protocols, TRUE)) ? 'mail' : $this->protocol;
+		in_array($this->protocol, $this->_protocols, TRUE) OR $this->protocol = 'mail';
 
-		if ($return == TRUE)
+		if ($return === TRUE)
 		{
 			return $this->protocol;
 		}
@@ -632,13 +597,12 @@
 	/**
 	 * Get Mail Encoding
 	 *
-	 * @access	protected
 	 * @param	bool
 	 * @return	string
 	 */
 	protected function _get_encoding($return = TRUE)
 	{
-		$this->_encoding = ( ! in_array($this->_encoding, $this->_bit_depths)) ? '8bit' : $this->_encoding;
+		in_array($this->_encoding, $this->_bit_depths) OR $this->_encoding = '8bit';
 
 		foreach ($this->_base_charsets as $charset)
 		{
@@ -648,7 +612,7 @@
 			}
 		}
 
-		if ($return == TRUE)
+		if ($return === TRUE)
 		{
 			return $this->_encoding;
 		}
@@ -659,18 +623,13 @@
 	/**
 	 * Get content type (text/html/attachment)
 	 *
-	 * @access	protected
 	 * @return	string
 	 */
 	protected function _get_content_type()
 	{
-		if ($this->mailtype === 'html' && count($this->_attach_name) === 0)
+		if ($this->mailtype === 'html')
 		{
-			return 'html';
-		}
-		elseif	($this->mailtype === 'html' && count($this->_attach_name) > 0)
-		{
-			return 'html-attach';
+			return (count($this->_attach_name) === 0) ? 'html' : 'html-attach';
 		}
 		elseif	($this->mailtype === 'text' && count($this->_attach_name) > 0)
 		{
@@ -687,17 +646,16 @@
 	/**
 	 * Set RFC 822 Date
 	 *
-	 * @access	protected
 	 * @return	string
 	 */
 	protected function _set_date()
 	{
-		$timezone = date("Z");
+		$timezone = date('Z');
 		$operator = (strncmp($timezone, '-', 1) === 0) ? '-' : '+';
 		$timezone = abs($timezone);
 		$timezone = floor($timezone/3600) * 100 + ($timezone % 3600) / 60;
 
-		return sprintf("%s %s%04d", date("D, j M Y H:i:s"), $operator, $timezone);
+		return sprintf('%s %s%04d', date('D, j M Y H:i:s'), $operator, $timezone);
 	}
 
 	// --------------------------------------------------------------------
@@ -705,12 +663,11 @@
 	/**
 	 * Mime message
 	 *
-	 * @access	protected
 	 * @return	string
 	 */
 	protected function _get_mime_message()
 	{
-		return "This is a multi-part message in MIME format.".$this->newline."Your email application may not support this format.";
+		return 'This is a multi-part message in MIME format.'.$this->newline.'Your email application may not support this format.';
 	}
 
 	// --------------------------------------------------------------------
@@ -718,7 +675,6 @@
 	/**
 	 * Validate Email Address
 	 *
-	 * @access	public
 	 * @param	string
 	 * @return	bool
 	 */
@@ -747,13 +703,12 @@
 	/**
 	 * Email Validation
 	 *
-	 * @access	public
 	 * @param	string
 	 * @return	bool
 	 */
 	public function valid_email($address)
 	{
-		return (bool) preg_match("/^([a-z0-9\+_\-]+)(\.[a-z0-9\+_\-]+)*@([a-z0-9\-]+\.)+[a-z]{2,6}$/ix", $address);
+		return (bool) preg_match('/^([a-z0-9\+_\-]+)(\.[a-z0-9\+_\-]+)*@([a-z0-9\-]+\.)+[a-z]{2,6}$/ix', $address);
 	}
 
 	// --------------------------------------------------------------------
@@ -761,7 +716,6 @@
 	/**
 	 * Clean Extended Email Address: Joe Smith <joe@smith.com>
 	 *
-	 * @access	public
 	 * @param	string
 	 * @return	string
 	 */
@@ -769,14 +723,14 @@
 	{
 		if ( ! is_array($email))
 		{
-			return (preg_match('/\<(.*)\>/', $email, $match)) ? $match[1] : $email;
+			return preg_match('/\<(.*)\>/', $email, $match) ? $match[1] : $email;
 		}
 
 		$clean_email = array();
 
 		foreach ($email as $addy)
 		{
-			$clean_email[] = (preg_match( '/\<(.*)\>/', $addy, $match)) ? $match[1] : $addy;
+			$clean_email[] = preg_match('/\<(.*)\>/', $addy, $match) ? $match[1] : $addy;
 		}
 
 		return $clean_email;
@@ -792,17 +746,16 @@
 	 * If the user hasn't specified his own alternative message
 	 * it creates one by stripping the HTML
 	 *
-	 * @access	protected
 	 * @return	string
 	 */
 	protected function _get_alt_message()
 	{
-		if ($this->alt_message != "")
+		if ($this->alt_message !== '')
 		{
 			return $this->word_wrap($this->alt_message, '76');
 		}
 
-		$body = (preg_match('/\<body.*?\>(.*)\<\/body\>/si', $this->_body, $match)) ? $match[1] : $this->_body;
+		$body = preg_match('/\<body.*?\>(.*)\<\/body\>/si', $this->_body, $match) ? $match[1] : $this->_body;
 		$body = str_replace("\t", '', preg_replace('#<!--(.*)--\>#', '', trim(strip_tags($body))));
 
 		for ($i = 20; $i >= 3; $i--)
@@ -818,21 +771,20 @@
 	/**
 	 * Word Wrap
 	 *
-	 * @access	public
 	 * @param	string
-	 * @param	integer
+	 * @param	int
 	 * @return	string
 	 */
 	public function word_wrap($str, $charlim = '')
 	{
 		// Se the character limit
-		if ($charlim == '')
+		if ($charlim === '')
 		{
-			$charlim = ($this->wrapchars == "") ? 76 : $this->wrapchars;
+			$charlim = ($this->wrapchars === '') ? 76 : $this->wrapchars;
 		}
 
 		// Reduce multiple spaces
-		$str = preg_replace("| +|", " ", $str);
+		$str = preg_replace('| +|', ' ', $str);
 
 		// Standardize newlines
 		if (strpos($str, "\r") !== FALSE)
@@ -843,22 +795,22 @@
 		// If the current word is surrounded by {unwrap} tags we'll
 		// strip the entire chunk and replace it with a marker.
 		$unwrap = array();
-		if (preg_match_all("|(\{unwrap\}.+?\{/unwrap\})|s", $str, $matches))
+		if (preg_match_all('|(\{unwrap\}.+?\{/unwrap\})|s', $str, $matches))
 		{
 			for ($i = 0, $c = count($matches[0]); $i < $c; $i++)
 			{
 				$unwrap[] = $matches[1][$i];
-				$str = str_replace($matches[1][$i], "{{unwrapped".$i."}}", $str);
+				$str = str_replace($matches[1][$i], '{{unwrapped'.$i.'}}', $str);
 			}
 		}
 
 		// Use PHP's native public function to do the initial wordwrap.
 		// We set the cut flag to FALSE so that any individual words that are
-		// too long get left alone.  In the next step we'll deal with them.
+		// too long get left alone. In the next step we'll deal with them.
 		$str = wordwrap($str, $charlim, "\n", FALSE);
 
 		// Split the string into individual lines of text and cycle through them
-		$output = "";
+		$output = '';
 		foreach (explode("\n", $str) as $line)
 		{
 			// Is the line within the allowed character count?
@@ -873,7 +825,7 @@
 			do
 			{
 				// If the over-length word is a URL we won't wrap it
-				if (preg_match("!\[url.+\]|://|wwww.!", $line))
+				if (preg_match('!\[url.+\]|://|wwww.!', $line))
 				{
 					break;
 				}
@@ -886,7 +838,7 @@
 
 			// If $temp contains data it means we had to split up an over-length
 			// word into smaller chunks so we'll add it back to our current line
-			if ($temp != '')
+			if ($temp !== '')
 			{
 				$output .= $temp.$this->newline;
 			}
@@ -899,7 +851,7 @@
 		{
 			foreach ($unwrap as $key => $val)
 			{
-				$output = str_replace("{{unwrapped".$key."}}", $val, $output);
+				$output = str_replace('{{unwrapped'.$key.'}}', $val, $output);
 			}
 		}
 
@@ -911,17 +863,15 @@
 	/**
 	 * Build final headers
 	 *
-	 * @access	protected
-	 * @param	string
 	 * @return	string
 	 */
 	protected function _build_headers()
 	{
-		$this->_set_header('X-Sender', $this->clean_email($this->_headers['From']));
-		$this->_set_header('X-Mailer', $this->useragent);
-		$this->_set_header('X-Priority', $this->_priorities[$this->priority - 1]);
-		$this->_set_header('Message-ID', $this->_get_message_id());
-		$this->_set_header('Mime-Version', '1.0');
+		$this->set_header('X-Sender', $this->clean_email($this->_headers['From']));
+		$this->set_header('X-Mailer', $this->useragent);
+		$this->set_header('X-Priority', $this->_priorities[$this->priority - 1]);
+		$this->set_header('Message-ID', $this->_get_message_id());
+		$this->set_header('Mime-Version', '1.0');
 	}
 
 	// --------------------------------------------------------------------
@@ -929,7 +879,6 @@
 	/**
 	 * Write Headers as a string
 	 *
-	 * @access	protected
 	 * @return	void
 	 */
 	protected function _write_headers()
@@ -941,15 +890,15 @@
 		}
 
 		reset($this->_headers);
-		$this->_header_str = "";
+		$this->_header_str = '';
 
 		foreach ($this->_headers as $key => $val)
 		{
 			$val = trim($val);
 
-			if ($val != "")
+			if ($val !== '')
 			{
-				$this->_header_str .= $key.": ".$val.$this->newline;
+				$this->_header_str .= $key.': '.$val.$this->newline;
 			}
 		}
 
@@ -964,12 +913,11 @@
 	/**
 	 * Build Final Body and attachments
 	 *
-	 * @access	protected
 	 * @return	void
 	 */
 	protected function _build_message()
 	{
-		if ($this->wordwrap === TRUE AND $this->mailtype !== 'html')
+		if ($this->wordwrap === TRUE && $this->mailtype !== 'html')
 		{
 			$this->_body = $this->word_wrap($this->_body);
 		}
@@ -984,8 +932,8 @@
 		{
 			case 'plain' :
 
-				$hdr .= "Content-Type: text/plain; charset=" . $this->charset . $this->newline
-					. "Content-Transfer-Encoding: " . $this->_get_encoding();
+				$hdr .= 'Content-Type: text/plain; charset='.$this->charset.$this->newline
+					.'Content-Transfer-Encoding: '.$this->_get_encoding();
 
 				if ($this->_get_protocol() === 'mail')
 				{
@@ -1003,25 +951,25 @@
 
 				if ($this->send_multipart === FALSE)
 				{
-					$hdr .= "Content-Type: text/html; charset=" . $this->charset . $this->newline
-						. "Content-Transfer-Encoding: quoted-printable";
+					$hdr .= 'Content-Type: text/html; charset='.$this->charset.$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.'"'.$this->newline.$this->newline;
 
-					$body .= $this->_get_mime_message() . $this->newline . $this->newline
-						. "--" . $this->_alt_boundary . $this->newline
+					$body .= $this->_get_mime_message().$this->newline.$this->newline
+						.'--'.$this->_alt_boundary.$this->newline
 
-						. "Content-Type: text/plain; charset=" . $this->charset . $this->newline
-						. "Content-Transfer-Encoding: " . $this->_get_encoding() . $this->newline . $this->newline
-						. $this->_get_alt_message() . $this->newline . $this->newline . "--" . $this->_alt_boundary . $this->newline
+						.'Content-Type: text/plain; charset='.$this->charset.$this->newline
+						.'Content-Transfer-Encoding: '.$this->_get_encoding().$this->newline.$this->newline
+						.$this->_get_alt_message().$this->newline.$this->newline.'--'.$this->_alt_boundary.$this->newline
 
-						. "Content-Type: text/html; charset=" . $this->charset . $this->newline
-						. "Content-Transfer-Encoding: quoted-printable" . $this->newline . $this->newline;
+						.'Content-Type: text/html; charset='.$this->charset.$this->newline
+						.'Content-Transfer-Encoding: quoted-printable'.$this->newline.$this->newline;
 				}
 
-				$this->_finalbody = $body . $this->_prep_quoted_printable($this->_body) . $this->newline . $this->newline;
+				$this->_finalbody = $body.$this->_prep_quoted_printable($this->_body).$this->newline.$this->newline;
 
 
 				if ($this->_get_protocol() === 'mail')
@@ -1030,59 +978,59 @@
 				}
 				else
 				{
-					$this->_finalbody = $hdr . $this->_finalbody;
+					$this->_finalbody = $hdr.$this->_finalbody;
 				}
 
 
 				if ($this->send_multipart !== FALSE)
 				{
-					$this->_finalbody .= "--" . $this->_alt_boundary . "--";
+					$this->_finalbody .= '--'.$this->_alt_boundary.'--';
 				}
 
 				return;
 
 			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.'"'.$this->newline.$this->newline;
 
 				if ($this->_get_protocol() === 'mail')
 				{
 					$this->_header_str .= $hdr;
 				}
 
-				$body .= $this->_get_mime_message() . $this->newline . $this->newline
-					. "--" . $this->_atc_boundary . $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-Type: text/plain; charset='.$this->charset.$this->newline
+					.'Content-Transfer-Encoding: '.$this->_get_encoding().$this->newline.$this->newline
 
-					. $this->_body . $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.'"'.$this->newline.$this->newline;
 
 				if ($this->_get_protocol() === 'mail')
 				{
 					$this->_header_str .= $hdr;
 				}
 
-				$body .= $this->_get_mime_message() . $this->newline . $this->newline
-					. "--" . $this->_atc_boundary . $this->newline
+				$body .= $this->_get_mime_message().$this->newline.$this->newline
+					.'--'.$this->_atc_boundary.$this->newline
 
-					. "Content-Type: multipart/alternative; boundary=\"" . $this->_alt_boundary . "\"" . $this->newline .$this->newline
-					. "--" . $this->_alt_boundary . $this->newline
+					.'Content-Type: multipart/alternative; boundary="'.$this->_alt_boundary.'"'.$this->newline.$this->newline
+					.'--'.$this->_alt_boundary.$this->newline
 
-					. "Content-Type: text/plain; charset=" . $this->charset . $this->newline
-					. "Content-Transfer-Encoding: " . $this->_get_encoding() . $this->newline . $this->newline
-					. $this->_get_alt_message() . $this->newline . $this->newline . "--" . $this->_alt_boundary . $this->newline
+					.'Content-Type: text/plain; charset='.$this->charset.$this->newline
+					.'Content-Transfer-Encoding: '.$this->_get_encoding().$this->newline.$this->newline
+					.$this->_get_alt_message().$this->newline.$this->newline.'--'.$this->_alt_boundary.$this->newline
 
-					. "Content-Type: text/html; charset=" . $this->charset . $this->newline
-					. "Content-Transfer-Encoding: quoted-printable" . $this->newline . $this->newline
+					.'Content-Type: text/html; charset='.$this->charset.$this->newline
+					.'Content-Transfer-Encoding: quoted-printable'.$this->newline.$this->newline
 
-					. $this->_prep_quoted_printable($this->_body) . $this->newline . $this->newline
-					. "--" . $this->_alt_boundary . "--" . $this->newline . $this->newline;
+					.$this->_prep_quoted_printable($this->_body).$this->newline.$this->newline
+					.'--'.$this->_alt_boundary.'--'.$this->newline.$this->newline;
 
 			break;
 		}
@@ -1091,35 +1039,46 @@
 		for ($i = 0, $c = count($this->_attach_name), $z = 0; $i < $c; $i++)
 		{
 			$filename = $this->_attach_name[$i][0];
-			$basename = (is_null($this->_attach_name[$i][1])) ? basename($filename) : $this->_attach_name[$i][1];
+			$basename = is_null($this->_attach_name[$i][1]) ? basename($filename) : $this->_attach_name[$i][1];
 			$ctype = $this->_attach_type[$i];
+			$file_content = '';
 
-			if ( ! file_exists($filename))
+			if ($this->_attach_type[$i] === '')
 			{
-				$this->_set_error_message('lang:email_attachment_missing', $filename);
-				return FALSE;
+				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->_attach_content[$i];
 			}
 
-			$attachment[$z++] = "--".$this->_atc_boundary.$this->newline
-				. "Content-type: ".$ctype."; "
-				. "name=\"".$basename."\"".$this->newline
-				. "Content-Disposition: ".$this->_attach_disp[$i].";".$this->newline
-				. "Content-Transfer-Encoding: base64".$this->newline;
+			$attachment[$z++] = '--'.$this->_atc_boundary.$this->newline
+				.'Content-type: '.$ctype.'; '
+				.'name="'.$basename.'"'.$this->newline
+				.'Content-Disposition: '.$this->_attach_disp[$i].';'.$this->newline
+				.'Content-Transfer-Encoding: base64'.$this->newline;
 
-			$file = filesize($filename) +1;
-
-			if ( ! $fp = fopen($filename, FOPEN_READ))
-			{
-				$this->_set_error_message('lang:email_attachment_unreadable', $filename);
-				return FALSE;
-			}
-
-			$attachment[$z++] = chunk_split(base64_encode(fread($fp, $file)));
-			fclose($fp);
+			$attachment[$z++] = chunk_split(base64_encode($file_content));
 		}
 
-		$body .= implode($this->newline, $attachment).$this->newline."--".$this->_atc_boundary."--";
-		$this->_finalbody = ($this->_get_protocol() === 'mail') ? $body : $hdr . $body;
+		$body .= implode($this->newline, $attachment).$this->newline.'--'.$this->_atc_boundary.'--';
+		$this->_finalbody = ($this->_get_protocol() === 'mail') ? $body : $hdr.$body;
 		return;
 	}
 
@@ -1131,9 +1090,8 @@
 	 * Prepares string for Quoted-Printable Content-Transfer-Encoding
 	 * Refer to RFC 2045 http://www.ietf.org/rfc/rfc2045.txt
 	 *
-	 * @access	protected
 	 * @param	string
-	 * @param	integer
+	 * @param	int
 	 * @return	string
 	 */
 	protected function _prep_quoted_printable($str, $charlim = '')
@@ -1141,13 +1099,13 @@
 		// Set the character limit
 		// Don't allow over 76, as that will make servers and MUAs barf
 		// all over quoted-printable data
-		if ($charlim == '' OR $charlim > 76)
+		if ($charlim === '' OR $charlim > 76)
 		{
 			$charlim = 76;
 		}
 
 		// Reduce multiple spaces & remove nulls
-		$str = preg_replace(array("| +|", '/\x00+/'), array(' ', ''), $str);
+		$str = preg_replace(array('| +|', '/\x00+/'), array(' ', ''), $str);
 
 		// Standardize newlines
 		if (strpos($str, "\r") !== FALSE)
@@ -1203,9 +1161,7 @@
 		}
 
 		// get rid of extra CRLF tacked onto the end
-		$output = substr($output, 0, strlen($this->crlf) * -1);
-
-		return $output;
+		return substr($output, 0, strlen($this->crlf) * -1);
 	}
 
 	// --------------------------------------------------------------------
@@ -1216,10 +1172,9 @@
 	 * Performs "Q Encoding" on a string for use in email headers.  It's related
 	 * but not identical to quoted-printable, so it has its own method
 	 *
-	 * @access	public
-	 * @param	str
-	 * @param	bool	// set to TRUE for processing From: headers
-	 * @return	str
+	 * @param	string
+	 * @param	bool	set to TRUE for processing From: headers
+	 * @return	string
 	 */
 	protected function _prep_q_encoding($str, $from = FALSE)
 	{
@@ -1271,13 +1226,9 @@
 			$temp .= $char;
 		}
 
-		$str = $output.$temp;
-
 		// wrap each line with the shebang, charset, and transfer encoding
 		// the preceding space on successive lines is required for header "folding"
-		$str = trim(preg_replace('/^(.*)$/m', ' =?'.$this->charset.'?Q?$1?=', $str));
-
-		return $str;
+		return trim(preg_replace('/^(.*)$/m', ' =?'.$this->charset.'?Q?$1?=', $output.$temp));
 	}
 
 	// --------------------------------------------------------------------
@@ -1285,19 +1236,18 @@
 	/**
 	 * Send Email
 	 *
-	 * @access	public
 	 * @return	bool
 	 */
 	public function send()
 	{
-		if ($this->_replyto_flag == FALSE)
+		if ($this->_replyto_flag === FALSE)
 		{
 			$this->reply_to($this->_headers['From']);
 		}
 
-		if (( ! isset($this->_recipients) AND ! isset($this->_headers['To']))  AND
-			( ! isset($this->_bcc_array) AND ! isset($this->_headers['Bcc'])) AND
-			( ! isset($this->_headers['Cc'])))
+		if ( ! isset($this->_recipients) && ! isset($this->_headers['To'])
+			&& ! isset($this->_bcc_array) && ! isset($this->_headers['Bcc'])
+			&& ! isset($this->_headers['Cc']))
 		{
 			$this->_set_error_message('lang:email_no_recipients');
 			return FALSE;
@@ -1305,44 +1255,40 @@
 
 		$this->_build_headers();
 
-		if ($this->bcc_batch_mode AND count($this->_bcc_array) > $this->bcc_batch_size)
+		if ($this->bcc_batch_mode && count($this->_bcc_array) > $this->bcc_batch_size)
 		{
 			return $this->batch_bcc_send();
 		}
 
 		$this->_build_message();
-
 		return $this->_spool_email();
 	}
 
 	// --------------------------------------------------------------------
 
 	/**
-	 * Batch Bcc Send.  Sends groups of BCCs in batches
+	 * Batch Bcc Send. Sends groups of BCCs in batches
 	 *
-	 * @access	public
-	 * @return	bool
+	 * @return	void
 	 */
 	public function batch_bcc_send()
 	{
-		$float = $this->bcc_batch_size -1;
-
-		$set = "";
-
+		$float = $this->bcc_batch_size - 1;
+		$set = '';
 		$chunk = array();
 
 		for ($i = 0, $c = count($this->_bcc_array); $i < $c; $i++)
 		{
 			if (isset($this->_bcc_array[$i]))
 			{
-				$set .= ", ".$this->_bcc_array[$i];
+				$set .= ', '.$this->_bcc_array[$i];
 			}
 
-			if ($i == $float)
+			if ($i === $float)
 			{
 				$chunk[] = substr($set, 1);
 				$float += $this->bcc_batch_size;
-				$set = "";
+				$set = '';
 			}
 
 			if ($i === $c-1)
@@ -1359,7 +1305,7 @@
 
 			if ($this->protocol !== 'smtp')
 			{
-				$this->_set_header('Bcc', implode(", ", $bcc));
+				$this->set_header('Bcc', implode(', ', $bcc));
 			}
 			else
 			{
@@ -1376,12 +1322,11 @@
 	/**
 	 * Unwrap special elements
 	 *
-	 * @access	protected
 	 * @return	void
 	 */
 	protected function _unwrap_specials()
 	{
-		$this->_finalbody = preg_replace_callback("/\{unwrap\}(.*?)\{\/unwrap\}/si", array($this, '_remove_nl_callback'), $this->_finalbody);
+		$this->_finalbody = preg_replace_callback('/\{unwrap\}(.*?)\{\/unwrap\}/si', array($this, '_remove_nl_callback'), $this->_finalbody);
 	}
 
 	// --------------------------------------------------------------------
@@ -1389,7 +1334,6 @@
 	/**
 	 * Strip line-breaks via callback
 	 *
-	 * @access	protected
 	 * @return	string
 	 */
 	protected function _remove_nl_callback($matches)
@@ -1407,17 +1351,17 @@
 	/**
 	 * Spool mail to the mail server
 	 *
-	 * @access	protected
 	 * @return	bool
 	 */
 	protected function _spool_email()
 	{
 		$this->_unwrap_specials();
 
-		$method = '_send_with_' . $this->_get_protocol();
+		$method = '_send_with_'.$this->_get_protocol();
 		if ( ! $this->$method())
 		{
-			$this->_set_error_message('lang:email_send_failure_' . ($this->_get_protocol() === 'mail' ? 'phpmail' : $this->_get_protocol()));
+			$this->_set_error_message('lang:email_send_failure_'.($this->_get_protocol() === 'mail' ? 'phpmail' : $this->_get_protocol()));
+			return FALSE;
 		}
 
 		$this->_set_error_message('lang:email_sent', $this->_get_protocol());
@@ -1429,12 +1373,11 @@
 	/**
 	 * Send using mail()
 	 *
-	 * @access	protected
 	 * @return	bool
 	 */
 	protected function _send_with_mail()
 	{
-		if ($this->_safe_mode == TRUE)
+		if ($this->_safe_mode === TRUE)
 		{
 			return mail($this->_recipients, $this->_subject, $this->_finalbody, $this->_header_str);
 		}
@@ -1442,7 +1385,7 @@
 		{
 			// most documentation of sendmail using the "-f" flag lacks a space after it, however
 			// we've encountered servers that seem to require it to be in place.
-			return mail($this->_recipients, $this->_subject, $this->_finalbody, $this->_header_str, "-f ".$this->clean_email($this->_headers['From']));
+			return mail($this->_recipients, $this->_subject, $this->_finalbody, $this->_header_str, '-f '.$this->clean_email($this->_headers['From']));
 		}
 	}
 
@@ -1451,12 +1394,11 @@
 	/**
 	 * Send using Sendmail
 	 *
-	 * @access	protected
 	 * @return	bool
 	 */
 	protected function _send_with_sendmail()
 	{
-		$fp = @popen($this->mailpath . " -oi -f ".$this->clean_email($this->_headers['From'])." -t", 'w');
+		$fp = @popen($this->mailpath.' -oi -f '.$this->clean_email($this->_headers['From']).' -t', 'w');
 
 		if ($fp === FALSE OR $fp === NULL)
 		{
@@ -1484,19 +1426,20 @@
 	/**
 	 * Send using SMTP
 	 *
-	 * @access	protected
 	 * @return	bool
 	 */
 	protected function _send_with_smtp()
 	{
-		if ($this->smtp_host == '')
+		if ($this->smtp_host === '')
 		{
 			$this->_set_error_message('lang:email_no_hostname');
 			return FALSE;
 		}
 
-		$this->_smtp_connect();
-		$this->_smtp_authenticate();
+		if ( ! $this->_smtp_connect() OR ! $this->_smtp_authenticate())
+		{
+			return FALSE;
+		}
 
 		$this->_send_command('from', $this->clean_email($this->_headers['From']));
 
@@ -1509,7 +1452,7 @@
 		{
 			foreach ($this->_cc_array as $val)
 			{
-				if ($val != "")
+				if ($val !== '')
 				{
 					$this->_send_command('to', $val);
 				}
@@ -1520,7 +1463,7 @@
 		{
 			foreach ($this->_bcc_array as $val)
 			{
-				if ($val != "")
+				if ($val !== '')
 				{
 					$this->_send_command('to', $val);
 				}
@@ -1530,7 +1473,7 @@
 		$this->_send_command('data');
 
 		// perform dot transformation on any lines that begin with a dot
-		$this->_send_data($this->_header_str . preg_replace('/^\./m', '..$1', $this->_finalbody));
+		$this->_send_data($this->_header_str.preg_replace('/^\./m', '..$1', $this->_finalbody));
 
 		$this->_send_data('.');
 
@@ -1553,29 +1496,28 @@
 	/**
 	 * SMTP Connect
 	 *
-	 * @access	protected
 	 * @param	string
 	 * @return	string
 	 */
 	protected function _smtp_connect()
 	{
-		$ssl = ($this->smtp_crypto == 'ssl') ? 'ssl://' : NULL;
+		$ssl = ($this->smtp_crypto === 'ssl') ? 'ssl://' : NULL;
 
 		$this->_smtp_connect = fsockopen($ssl.$this->smtp_host,
-										$this->smtp_port,
-										$errno,
-										$errstr,
-										$this->smtp_timeout);
+							$this->smtp_port,
+							$errno,
+							$errstr,
+							$this->smtp_timeout);
 
 		if ( ! is_resource($this->_smtp_connect))
 		{
-			$this->_set_error_message('lang:email_smtp_error', $errno." ".$errstr);
+			$this->_set_error_message('lang:email_smtp_error', $errno.' '.$errstr);
 			return FALSE;
 		}
 
 		$this->_set_error_message($this->_get_smtp_data());
 
-		if ($this->smtp_crypto == 'tls')
+		if ($this->smtp_crypto === 'tls')
 		{
 			$this->_send_command('hello');
 			$this->_send_command('starttls');
@@ -1597,7 +1539,6 @@
 	/**
 	 * Send SMTP command
 	 *
-	 * @access	protected
 	 * @param	string
 	 * @param	string
 	 * @return	string
@@ -1608,56 +1549,63 @@
 		{
 			case 'hello' :
 
-					if ($this->_smtp_auth OR $this->_get_encoding() == '8bit')
-						$this->_send_data('EHLO '.$this->_get_hostname());
-					else
-						$this->_send_data('HELO '.$this->_get_hostname());
+						if ($this->_smtp_auth OR $this->_get_encoding() === '8bit')
+						{
+							$this->_send_data('EHLO '.$this->_get_hostname());
+						}
+						else
+						{
+							$this->_send_data('HELO '.$this->_get_hostname());
+						}
 
 						$resp = 250;
 			break;
 			case 'starttls'	:
 
 						$this->_send_data('STARTTLS');
-
 						$resp = 220;
 			break;
 			case 'from' :
 
 						$this->_send_data('MAIL FROM:<'.$data.'>');
-
 						$resp = 250;
 			break;
-			case 'to'	:
+			case 'to' :
 
-						$this->_send_data('RCPT TO:<'.$data.'>');
+						if ($this->dsn)
+						{
+							$this->_send_data('RCPT TO:<'.$data.'> NOTIFY=SUCCESS,DELAY,FAILURE ORCPT=rfc822;'.$data);
+						}
+						else
+						{
+							$this->_send_data('RCPT TO:<'.$data.'>');
+						}
 
 						$resp = 250;
 			break;
 			case 'data'	:
 
 						$this->_send_data('DATA');
-
 						$resp = 354;
 			break;
 			case 'quit'	:
 
 						$this->_send_data('QUIT');
-
 						$resp = 221;
 			break;
 		}
 
 		$reply = $this->_get_smtp_data();
 
-		$this->_debug_msg[] = "<pre>".$cmd.": ".$reply."</pre>";
+		$this->_debug_msg[] = '<pre>'.$cmd.': '.$reply.'</pre>';
 
-		if (substr($reply, 0, 3) != $resp)
+		if ( (int) substr($reply, 0, 3) !== $resp)
 		{
 			$this->_set_error_message('lang:email_smtp_error', $reply);
 			return FALSE;
 		}
 
-		if ($cmd == 'quit')
+		if ($cmd === 'quit')
 		{
 			fclose($this->_smtp_connect);
 		}
@@ -1670,7 +1618,6 @@
 	/**
 	 *  SMTP Authenticate
 	 *
-	 * @access	protected
 	 * @return	bool
 	 */
 	protected function _smtp_authenticate()
@@ -1680,7 +1627,7 @@
 			return TRUE;
 		}
 
-		if ($this->smtp_user == ""  AND  $this->smtp_pass == "")
+		if ($this->smtp_user === '' && $this->smtp_pass === '')
 		{
 			$this->_set_error_message('lang:email_no_smtp_unpw');
 			return FALSE;
@@ -1724,7 +1671,6 @@
 	/**
 	 * Send SMTP data
 	 *
-	 * @access	protected
 	 * @return	bool
 	 */
 	protected function _send_data($data)
@@ -1743,18 +1689,17 @@
 	/**
 	 * Get SMTP data
 	 *
-	 * @access	protected
 	 * @return	string
 	 */
 	protected function _get_smtp_data()
 	{
-		$data = "";
+		$data = '';
 
 		while ($str = fgets($this->_smtp_connect, 512))
 		{
 			$data .= $str;
 
-			if ($str[3] == " ")
+			if ($str[3] === ' ')
 			{
 				break;
 			}
@@ -1768,12 +1713,11 @@
 	/**
 	 * Get Hostname
 	 *
-	 * @access	protected
 	 * @return	string
 	 */
 	protected function _get_hostname()
 	{
-		return (isset($_SERVER['SERVER_NAME'])) ? $_SERVER['SERVER_NAME'] : 'localhost.localdomain';
+		return isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : 'localhost.localdomain';
 	}
 
 	// --------------------------------------------------------------------
@@ -1781,7 +1725,6 @@
 	/**
 	 * Get IP
 	 *
-	 * @access	protected
 	 * @return	string
 	 */
 	protected function _get_ip()
@@ -1791,13 +1734,13 @@
 			return $this->_IP;
 		}
 
-		$cip = (isset($_SERVER['HTTP_CLIENT_IP']) AND $_SERVER['HTTP_CLIENT_IP'] != "") ? $_SERVER['HTTP_CLIENT_IP'] : FALSE;
-		$rip = (isset($_SERVER['REMOTE_ADDR']) AND $_SERVER['REMOTE_ADDR'] != "") ? $_SERVER['REMOTE_ADDR'] : FALSE;
+		$cip = ( ! empty($_SERVER['HTTP_CLIENT_IP'])) ? $_SERVER['HTTP_CLIENT_IP'] : FALSE;
+		$rip = ( ! empty($_SERVER['REMOTE_ADDR'])) ? $_SERVER['REMOTE_ADDR'] : FALSE;
 		if ($cip) $this->_IP = $cip;
 		elseif ($rip) $this->_IP = $rip;
 		else
 		{
-			$fip = (isset($_SERVER['HTTP_X_FORWARDED_FOR']) AND $_SERVER['HTTP_X_FORWARDED_FOR'] != "") ? $_SERVER['HTTP_X_FORWARDED_FOR'] : FALSE;
+			$fip = ( ! empty($_SERVER['HTTP_X_FORWARDED_FOR'])) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : FALSE;
 			if ($fip)
 			{
 				$this->_IP = $fip;
@@ -1810,7 +1753,7 @@
 			$this->_IP = end($x);
 		}
 
-		if ( ! preg_match( "/^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/", $this->_IP))
+		if ( ! preg_match('/^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/', $this->_IP))
 		{
 			$this->_IP = '0.0.0.0';
 		}
@@ -1823,7 +1766,6 @@
 	/**
 	 * Get Debug Message
 	 *
-	 * @access	public
 	 * @return	string
 	 */
 	public function print_debugger()
@@ -1838,8 +1780,7 @@
 			}
 		}
 
-		$msg .= "<pre>".$this->_header_str."\n".htmlspecialchars($this->_subject)."\n".htmlspecialchars($this->_finalbody).'</pre>';
-		return $msg;
+		return $msg.'<pre>'.$this->_header_str."\n".htmlspecialchars($this->_subject)."\n".htmlspecialchars($this->_finalbody).'</pre>';
 	}
 
 	// --------------------------------------------------------------------
@@ -1847,22 +1788,21 @@
 	/**
 	 * Set Message
 	 *
-	 * @access	protected
 	 * @param	string
-	 * @return	string
+	 * @return	void
 	 */
 	protected function _set_error_message($msg, $val = '')
 	{
 		$CI =& get_instance();
 		$CI->lang->load('email');
 
-		if (substr($msg, 0, 5) !== 'lang:' || FALSE === ($line = $CI->lang->line(substr($msg, 5))))
+		if (substr($msg, 0, 5) !== 'lang:' OR FALSE === ($line = $CI->lang->line(substr($msg, 5))))
 		{
-			$this->_debug_msg[] = str_replace('%s', $val, $msg)."<br />";
+			$this->_debug_msg[] = str_replace('%s', $val, $msg).'<br />';
 		}
 		else
 		{
-			$this->_debug_msg[] = str_replace('%s', $val, $line)."<br />";
+			$this->_debug_msg[] = str_replace('%s', $val, $line).'<br />';
 		}
 	}
 
@@ -1871,106 +1811,31 @@
 	/**
 	 * Mime Types
 	 *
-	 * @access	protected
 	 * @param	string
 	 * @return	string
 	 */
-	protected function _mime_types($ext = "")
+	protected function _mime_types($ext = '')
 	{
-		$mimes = array(	'hqx'	=>	'application/mac-binhex40',
-						'cpt'	=>	'application/mac-compactpro',
-						'doc'	=>	'application/msword',
-						'bin'	=>	'application/macbinary',
-						'dms'	=>	'application/octet-stream',
-						'lha'	=>	'application/octet-stream',
-						'lzh'	=>	'application/octet-stream',
-						'exe'	=>	'application/octet-stream',
-						'class'	=>	'application/octet-stream',
-						'psd'	=>	'application/octet-stream',
-						'so'	=>	'application/octet-stream',
-						'sea'	=>	'application/octet-stream',
-						'dll'	=>	'application/octet-stream',
-						'oda'	=>	'application/oda',
-						'pdf'	=>	'application/pdf',
-						'ai'	=>	'application/postscript',
-						'eps'	=>	'application/postscript',
-						'ps'	=>	'application/postscript',
-						'smi'	=>	'application/smil',
-						'smil'	=>	'application/smil',
-						'mif'	=>	'application/vnd.mif',
-						'xls'	=>	'application/vnd.ms-excel',
-						'ppt'	=>	'application/vnd.ms-powerpoint',
-						'wbxml'	=>	'application/vnd.wap.wbxml',
-						'wmlc'	=>	'application/vnd.wap.wmlc',
-						'dcr'	=>	'application/x-director',
-						'dir'	=>	'application/x-director',
-						'dxr'	=>	'application/x-director',
-						'dvi'	=>	'application/x-dvi',
-						'gtar'	=>	'application/x-gtar',
-						'php'	=>	'application/x-httpd-php',
-						'php4'	=>	'application/x-httpd-php',
-						'php3'	=>	'application/x-httpd-php',
-						'phtml'	=>	'application/x-httpd-php',
-						'phps'	=>	'application/x-httpd-php-source',
-						'js'	=>	'application/x-javascript',
-						'swf'	=>	'application/x-shockwave-flash',
-						'sit'	=>	'application/x-stuffit',
-						'tar'	=>	'application/x-tar',
-						'tgz'	=>	'application/x-tar',
-						'xhtml'	=>	'application/xhtml+xml',
-						'xht'	=>	'application/xhtml+xml',
-						'zip'	=>	'application/zip',
-						'mid'	=>	'audio/midi',
-						'midi'	=>	'audio/midi',
-						'mpga'	=>	'audio/mpeg',
-						'mp2'	=>	'audio/mpeg',
-						'mp3'	=>	'audio/mpeg',
-						'aif'	=>	'audio/x-aiff',
-						'aiff'	=>	'audio/x-aiff',
-						'aifc'	=>	'audio/x-aiff',
-						'ram'	=>	'audio/x-pn-realaudio',
-						'rm'	=>	'audio/x-pn-realaudio',
-						'rpm'	=>	'audio/x-pn-realaudio-plugin',
-						'ra'	=>	'audio/x-realaudio',
-						'rv'	=>	'video/vnd.rn-realvideo',
-						'wav'	=>	'audio/x-wav',
-						'bmp'	=>	'image/bmp',
-						'gif'	=>	'image/gif',
-						'jpeg'	=>	'image/jpeg',
-						'jpg'	=>	'image/jpeg',
-						'jpe'	=>	'image/jpeg',
-						'png'	=>	'image/png',
-						'tiff'	=>	'image/tiff',
-						'tif'	=>	'image/tiff',
-						'css'	=>	'text/css',
-						'html'	=>	'text/html',
-						'htm'	=>	'text/html',
-						'shtml'	=>	'text/html',
-						'txt'	=>	'text/plain',
-						'text'	=>	'text/plain',
-						'log'	=>	'text/plain',
-						'rtx'	=>	'text/richtext',
-						'rtf'	=>	'text/rtf',
-						'xml'	=>	'text/xml',
-						'xsl'	=>	'text/xml',
-						'mpeg'	=>	'video/mpeg',
-						'mpg'	=>	'video/mpeg',
-						'mpe'	=>	'video/mpeg',
-						'qt'	=>	'video/quicktime',
-						'mov'	=>	'video/quicktime',
-						'avi'	=>	'video/x-msvideo',
-						'movie'	=>	'video/x-sgi-movie',
-						'doc'	=>	'application/msword',
-						'word'	=>	'application/msword',
-						'xl'	=>	'application/excel',
-						'eml'	=>	'message/rfc822'
-					);
+		static $mimes;
 
-		return ( ! isset($mimes[strtolower($ext)])) ? "application/x-unknown-content-type" : $mimes[strtolower($ext)];
+		$ext = strtolower($ext);
+
+		if ( ! is_array($mimes))
+		{
+			$mimes =& get_mimes();
+		}
+
+		if (isset($mimes[$ext]))
+		{
+			return is_array($mimes[$ext])
+				? current($mimes[$ext])
+				: $mimes[$ext];
+		}
+
+		return 'application/x-unknown-content-type';
 	}
 
 }
-// END CI_Email class
 
 /* End of file Email.php */
-/* Location: ./system/libraries/Email.php */
+/* Location: ./system/libraries/Email.php */
\ No newline at end of file
diff --git a/system/libraries/Encrypt.php b/system/libraries/Encrypt.php
index 0b06189..ce5e030 100644
--- a/system/libraries/Encrypt.php
+++ b/system/libraries/Encrypt.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -38,15 +38,49 @@
  */
 class CI_Encrypt {
 
-	public $encryption_key	= '';
-	protected $_hash_type	= 'sha1';
-	protected $_mcrypt_exists = FALSE;
+	/**
+	 * Reference to the user's encryption key
+	 *
+	 * @var string
+	 */
+	public $encryption_key		= '';
+
+	/**
+	 * Type of hash operation
+	 *
+	 * @var string
+	 */
+	protected $_hash_type		= 'sha1';
+
+	/**
+	 * Flag for the existance of mcrypt
+	 *
+	 * @var bool
+	 */
+	protected $_mcrypt_exists	= FALSE;
+
+	/**
+	 * Current cipher to be used with mcrypt
+	 *
+	 * @var string
+	 */
 	protected $_mcrypt_cipher;
+
+	/**
+	 * Method for encrypting/decrypting data
+	 *
+	 * @var int
+	 */
 	protected $_mcrypt_mode;
 
+	/**
+	 * Initialize Encryption class
+	 *
+	 * @return	void
+	 */
 	public function __construct()
 	{
-		$this->_mcrypt_exists = ( ! function_exists('mcrypt_encrypt')) ? FALSE : TRUE;
+		$this->_mcrypt_exists = function_exists('mcrypt_encrypt');
 		log_message('debug', 'Encrypt Class Initialized');
 	}
 
@@ -63,15 +97,14 @@
 	 */
 	public function get_key($key = '')
 	{
-		if ($key == '')
+		if ($key === '')
 		{
-			if ($this->encryption_key != '')
+			if ($this->encryption_key !== '')
 			{
 				return $this->encryption_key;
 			}
 
-			$CI =& get_instance();
-			$key = $CI->config->item('encryption_key');
+			$key = config_item('encryption_key');
 
 			if ($key === FALSE)
 			{
@@ -349,8 +382,9 @@
 	 *
 	 * Function description
 	 *
-	 * @param	type
-	 * @return	type
+	 * @param	string	$data
+	 * @param	string	$key
+	 * @return	string
 	 */
 	protected function _remove_cipher_noise($data, $key)
 	{
@@ -382,8 +416,8 @@
 	/**
 	 * Set the Mcrypt Cipher
 	 *
-	 * @param	constant
-	 * @return	string
+	 * @param	int
+	 * @return	object
 	 */
 	public function set_cipher($cipher)
 	{
@@ -396,8 +430,8 @@
 	/**
 	 * Set the Mcrypt Mode
 	 *
-	 * @param	constant
-	 * @return	string
+	 * @param	int
+	 * @return	object
 	 */
 	public function set_mode($mode)
 	{
@@ -410,11 +444,11 @@
 	/**
 	 * Get Mcrypt cipher Value
 	 *
-	 * @return	string
+	 * @return	int
 	 */
 	protected function _get_cipher()
 	{
-		if ($this->_mcrypt_cipher == '')
+		if ($this->_mcrypt_cipher === NULL)
 		{
 			return $this->_mcrypt_cipher = MCRYPT_RIJNDAEL_256;
 		}
@@ -427,11 +461,11 @@
 	/**
 	 * Get Mcrypt Mode Value
 	 *
-	 * @return	string
+	 * @return	int
 	 */
 	protected function _get_mode()
 	{
-		if ($this->_mcrypt_mode == '')
+		if ($this->_mcrypt_mode === NULL)
 		{
 			return $this->_mcrypt_mode = MCRYPT_MODE_CBC;
 		}
@@ -464,7 +498,8 @@
 	{
 		return ($this->_hash_type === 'sha1') ? sha1($str) : md5($str);
 	}
+
 }
 
 /* End of file Encrypt.php */
-/* Location: ./system/libraries/Encrypt.php */
+/* Location: ./system/libraries/Encrypt.php */
\ No newline at end of file
diff --git a/system/libraries/Form_validation.php b/system/libraries/Form_validation.php
index 0a6a2af..77c968e 100644
--- a/system/libraries/Form_validation.php
+++ b/system/libraries/Form_validation.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * Form Validation Class
  *
@@ -38,23 +36,98 @@
  */
 class CI_Form_validation {
 
+	/**
+	 * Reference to the CodeIgniter instance
+	 *
+	 * @var object
+	 */
 	protected $CI;
-	protected $_field_data			= array();
-	protected $_config_rules		= array();
-	protected $_error_array			= array();
-	protected $_error_messages		= array();
-	protected $_error_prefix		= '<p>';
-	protected $_error_suffix		= '</p>';
-	protected $error_string			= '';
-	protected $_safe_form_data		= FALSE;
 
 	/**
-	 * Constructor
+	 * Validation data for the current form submission
+	 *
+	 * @var array
+	 */
+	protected $_field_data		= array();
+
+	/**
+	 * Validation rules for the current form
+	 *
+	 * @var array
+	 */
+	protected $_config_rules	= array();
+
+	/**
+	 * Array of validation errors
+	 *
+	 * @var array
+	 */
+	protected $_error_array		= array();
+
+	/**
+	 * Array of custom error messages
+	 *
+	 * @var array
+	 */
+	protected $_error_messages	= array();
+
+	/**
+	 * Start tag for error wrapping
+	 *
+	 * @var string
+	 */
+	protected $_error_prefix	= '<p>';
+
+	/**
+	 * End tag for error wrapping
+	 *
+	 * @var string
+	 */
+	protected $_error_suffix	= '</p>';
+
+	/**
+	 * Custom error message
+	 *
+	 * @var string
+	 */
+	protected $error_string		= '';
+
+	/**
+	 * Whether the form data has been validated as safe
+	 *
+	 * @var bool
+	 */
+	protected $_safe_form_data	= FALSE;
+
+	/**
+	 * Custom data to validate
+	 *
+	 * @var array
+	 */
+	protected $validation_data	= array();
+
+	/**
+	 * Initialize Form_Validation class
+	 *
+	 * @param	array	$rules
+	 * @return	void
 	 */
 	public function __construct($rules = array())
 	{
 		$this->CI =& get_instance();
 
+		// applies delimiters set in config file.
+		if (isset($rules['error_prefix']))
+		{
+			$this->_error_prefix = $rules['error_prefix'];
+			unset($rules['error_prefix']);
+		}
+		if (isset($rules['error_suffix']))
+		{
+			$this->_error_suffix = $rules['error_suffix'];
+			unset($rules['error_suffix']);
+		}
+
 		// Validation rules can be stored in a config file.
 		$this->_config_rules = $rules;
 
@@ -62,12 +135,12 @@
 		$this->CI->load->helper('form');
 
 		// Set the character encoding in MB.
-		if (function_exists('mb_internal_encoding'))
+		if (MB_ENABLED === TRUE)
 		{
 			mb_internal_encoding($this->CI->config->item('charset'));
 		}
 
-		log_message('debug', "Form Validation Class Initialized");
+		log_message('debug', 'Form Validation Class Initialized');
 	}
 
 	// --------------------------------------------------------------------
@@ -78,47 +151,50 @@
 	 * This function takes an array of field names and validation
 	 * rules as input, validates the info, and stores it
 	 *
-	 * @param	mixed
-	 * @param	string
-	 * @return	void
+	 * @param	mixed	$field
+	 * @param	string	$label
+	 * @param	mixed	$rules
+	 * @return	object
 	 */
 	public function set_rules($field, $label = '', $rules = '')
 	{
 		// No reason to set rules if we have no POST data
-		if (count($_POST) === 0)
+		// or a validation array has not been specified
+		if ($this->CI->input->method() !== 'post' && empty($this->validation_data))
 		{
 			return $this;
 		}
 
-		// If an array was passed via the first parameter instead of indidual string
+		// If an array was passed via the first parameter instead of individual string
 		// values we cycle through it and recursively call this function.
 		if (is_array($field))
 		{
 			foreach ($field as $row)
 			{
 				// Houston, we have a problem...
-				if ( ! isset($row['field']) OR ! isset($row['rules']))
+				if ( ! isset($row['field'], $row['rules']))
 				{
 					continue;
 				}
 
 				// If the field label wasn't passed we use the field name
-				$label = ( ! isset($row['label'])) ? $row['field'] : $row['label'];
+				$label = isset($row['label']) ? $row['label'] : $row['field'];
 
 				// Here we go!
 				$this->set_rules($row['field'], $label, $row['rules']);
 			}
+
 			return $this;
 		}
 
 		// No fields? Nothing to do...
-		if ( ! is_string($field) OR ! is_string($rules) OR $field == '')
+		if ( ! is_string($field) OR ! is_string($rules) OR $field === '')
 		{
 			return $this;
 		}
 
 		// If the field label wasn't passed we use the field name
-		$label = ($label == '') ? $field : $label;
+		$label = ($label === '') ? $field : $label;
 
 		// Is the field name an array? If it is an array, we break it apart
 		// into its components so that we can fetch the corresponding POST data later
@@ -131,7 +207,7 @@
 
 			for ($i = 0, $c = count($matches[0]); $i < $c; $i++)
 			{
-				if ($matches[1][$i] != '')
+				if ($matches[1][$i] !== '')
 				{
 					$indexes[] = $matches[1][$i];
 				}
@@ -147,13 +223,13 @@
 
 		// Build our master array
 		$this->_field_data[$field] = array(
-			'field'				=> $field,
-			'label'				=> $label,
-			'rules'				=> $rules,
-			'is_array'			=> $is_array,
-			'keys'				=> $indexes,
-			'postdata'			=> NULL,
-			'error'				=> ''
+			'field'		=> $field,
+			'label'		=> $label,
+			'rules'		=> $rules,
+			'is_array'	=> $is_array,
+			'keys'		=> $indexes,
+			'postdata'	=> NULL,
+			'error'		=> ''
 		);
 
 		return $this;
@@ -162,14 +238,37 @@
 	// --------------------------------------------------------------------
 
 	/**
+	 * By default, form validation uses the $_POST array to validate
+	 *
+	 * If an array is set through this method, then this array will
+	 * be used instead of the $_POST array
+	 *
+	 * Note that if you are validating multiple arrays, then the
+	 * reset_validation() function should be called after validating
+	 * each array due to the limitations of CI's singleton
+	 *
+	 * @param	array	$data
+	 * @return	void
+	 */
+	public function set_data($data = '')
+	{
+		if ( ! empty($data) && is_array($data))
+		{
+			$this->validation_data = $data;
+		}
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
 	 * Set Error Message
 	 *
-	 * Lets users set their own error messages on the fly.  Note:  The key
-	 * name has to match the  function name that it corresponds to.
+	 * Lets users set their own error messages on the fly. Note:
+	 * The key name has to match the function name that it corresponds to.
 	 *
+	 * @param	array
 	 * @param	string
-	 * @param	string
-	 * @return	string
+	 * @return	object
 	 */
 	public function set_message($lang, $val = '')
 	{
@@ -179,7 +278,6 @@
 		}
 
 		$this->_error_messages = array_merge($this->_error_messages, $lang);
-
 		return $this;
 	}
 
@@ -192,13 +290,12 @@
 	 *
 	 * @param	string
 	 * @param	string
-	 * @return	void
+	 * @return	object
 	 */
 	public function set_error_delimiters($prefix = '<p>', $suffix = '</p>')
 	{
 		$this->_error_prefix = $prefix;
 		$this->_error_suffix = $suffix;
-
 		return $this;
 	}
 
@@ -210,21 +307,23 @@
 	 * Gets the error message associated with a particular field
 	 *
 	 * @param	string	the field name
-	 * @return	void
+	 * @param	string	the html start tag
+	 * @param 	strign	the html end tag
+	 * @return	string
 	 */
 	public function error($field = '', $prefix = '', $suffix = '')
 	{
-		if ( ! isset($this->_field_data[$field]['error']) OR $this->_field_data[$field]['error'] == '')
+		if (empty($this->_field_data[$field]['error']))
 		{
 			return '';
 		}
 
-		if ($prefix == '')
+		if ($prefix === '')
 		{
 			$prefix = $this->_error_prefix;
 		}
 
-		if ($suffix == '')
+		if ($suffix === '')
 		{
 			$suffix = $this->_error_suffix;
 		}
@@ -235,13 +334,27 @@
 	// --------------------------------------------------------------------
 
 	/**
+	 * Get Array of Error Messages
+	 *
+	 * Returns the error messages as an array
+	 *
+	 * @return	array
+	 */
+	public function error_array()
+	{
+		return $this->_error_array;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
 	 * Error String
 	 *
 	 * Returns the error messages as a string, wrapped in the error delimiters
 	 *
 	 * @param	string
 	 * @param	string
-	 * @return	str
+	 * @return	string
 	 */
 	public function error_string($prefix = '', $suffix = '')
 	{
@@ -251,12 +364,12 @@
 			return '';
 		}
 
-		if ($prefix == '')
+		if ($prefix === '')
 		{
 			$prefix = $this->_error_prefix;
 		}
 
-		if ($suffix == '')
+		if ($suffix === '')
 		{
 			$suffix = $this->_error_suffix;
 		}
@@ -265,7 +378,7 @@
 		$str = '';
 		foreach ($this->_error_array as $val)
 		{
-			if ($val != '')
+			if ($val !== '')
 			{
 				$str .= $prefix.$val.$suffix."\n";
 			}
@@ -281,12 +394,14 @@
 	 *
 	 * This function does all the work.
 	 *
+	 * @param	string	$group
 	 * @return	bool
 	 */
 	public function run($group = '')
 	{
 		// Do we even have any data to process?  Mm?
-		if (count($_POST) === 0)
+		$validation_array = empty($this->validation_data) ? $_POST : $this->validation_data;
+		if (count($validation_array) === 0)
 		{
 			return FALSE;
 		}
@@ -302,9 +417,9 @@
 			}
 
 			// Is there a validation rule for the particular URI being accessed?
-			$uri = ($group == '') ? trim($this->CI->uri->ruri_string(), '/') : $group;
+			$uri = ($group === '') ? trim($this->CI->uri->ruri_string(), '/') : $group;
 
-			if ($uri != '' AND isset($this->_config_rules[$uri]))
+			if ($uri !== '' && isset($this->_config_rules[$uri]))
 			{
 				$this->set_rules($this->_config_rules[$uri]);
 			}
@@ -313,10 +428,10 @@
 				$this->set_rules($this->_config_rules);
 			}
 
-			// We're we able to set the rules correctly?
+			// Were we able to set the rules correctly?
 			if (count($this->_field_data) === 0)
 			{
-				log_message('debug', "Unable to find validation rules");
+				log_message('debug', 'Unable to find validation rules');
 				return FALSE;
 			}
 		}
@@ -328,19 +443,15 @@
 		// corresponding $_POST item and test for errors
 		foreach ($this->_field_data as $field => $row)
 		{
-			// Fetch the data from the corresponding $_POST array and cache it in the _field_data array.
+			// Fetch the data from the corresponding $_POST or validation array and cache it in the _field_data array.
 			// Depending on whether the field name is an array or a string will determine where we get it from.
-
 			if ($row['is_array'] === TRUE)
 			{
-				$this->_field_data[$field]['postdata'] = $this->_reduce_array($_POST, $row['keys']);
+				$this->_field_data[$field]['postdata'] = $this->_reduce_array($validation_array, $row['keys']);
 			}
-			else
+			elseif (isset($validation_array[$field]) && $validation_array[$field] !== '')
 			{
-				if (isset($_POST[$field]) AND $_POST[$field] != "")
-				{
-					$this->_field_data[$field]['postdata'] = $_POST[$field];
-				}
+				$this->_field_data[$field]['postdata'] = $validation_array[$field];
 			}
 
 			$this->_execute($row, explode('|', $row['rules']), $this->_field_data[$field]['postdata']);
@@ -348,7 +459,6 @@
 
 		// Did we end up with any errors?
 		$total_errors = count($this->_error_array);
-
 		if ($total_errors > 0)
 		{
 			$this->_safe_form_data = TRUE;
@@ -367,7 +477,7 @@
 	 *
 	 * @param	array
 	 * @param	array
-	 * @param	integer
+	 * @param	int
 	 * @return	mixed
 	 */
 	protected function _reduce_array($array, $keys, $i = 0)
@@ -385,7 +495,7 @@
 	/**
 	 * Re-populate the _POST array with our finalized and processed data
 	 *
-	 * @return	null
+	 * @return	void
 	 */
 	protected function _reset_post_array()
 	{
@@ -445,7 +555,7 @@
 	 * @param	array
 	 * @param	array
 	 * @param	mixed
-	 * @param	integer
+	 * @param	int
 	 * @return	mixed
 	 */
 	protected function _execute($row, $rules, $postdata = NULL, $cycles = 0)
@@ -462,17 +572,15 @@
 			return;
 		}
 
-		// --------------------------------------------------------------------
-
 		// If the field is blank, but NOT required, no further tests are necessary
 		$callback = FALSE;
-		if ( ! in_array('required', $rules) AND is_null($postdata))
+		if ( ! in_array('required', $rules) && is_null($postdata))
 		{
 			// Before we bail out, does the rule contain a callback?
-			if (preg_match("/(callback_\w+(\[.*?\])?)/", implode(' ', $rules), $match))
+			if (preg_match('/(callback_\w+(\[.*?\])?)/', implode(' ', $rules), $match))
 			{
 				$callback = TRUE;
-				$rules = (array('1' => $match[1]));
+				$rules = array(1 => $match[1]);
 			}
 			else
 			{
@@ -480,27 +588,22 @@
 			}
 		}
 
-		// --------------------------------------------------------------------
-
 		// Isset Test. Typically this rule will only apply to checkboxes.
-		if (is_null($postdata) AND $callback === FALSE)
+		if (is_null($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';
+				$type = in_array('required', $rules) ? 'required' : 'isset';
 
-				if ( ! isset($this->_error_messages[$type]))
-				{
-					if (FALSE === ($line = $this->CI->lang->line($type)))
-					{
-						$line = 'The field was not set';
-					}
-				}
-				else
+				if (isset($this->_error_messages[$type]))
 				{
 					$line = $this->_error_messages[$type];
 				}
+				elseif (FALSE === ($line = $this->CI->lang->line($type)))
+				{
+					$line = 'The field was not set';
+				}
 
 				// Build the error message
 				$message = sprintf($line, $this->_translate_fieldname($row['label']));
@@ -520,13 +623,13 @@
 		// --------------------------------------------------------------------
 
 		// Cycle through each rule and run it
-		foreach ($rules As $rule)
+		foreach ($rules as $rule)
 		{
 			$_in_array = FALSE;
 
 			// We set the $postdata variable with the current data in our master array so that
 			// each cycle of the loop is dealing with the processed data from the last cycle
-			if ($row['is_array'] == TRUE AND is_array($this->_field_data[$row['field']]['postdata']))
+			if ($row['is_array'] === TRUE && is_array($this->_field_data[$row['field']]['postdata']))
 			{
 				// We shouldn't need this safety, but just in case there isn't an array index
 				// associated with this cycle we'll bail out
@@ -543,11 +646,9 @@
 				$postdata = $this->_field_data[$row['field']]['postdata'];
 			}
 
-			// --------------------------------------------------------------------
-
 			// Is the rule a callback?
 			$callback = FALSE;
-			if (substr($rule, 0, 9) == 'callback_')
+			if (strpos($rule, 'callback_') === 0)
 			{
 				$rule = substr($rule, 9);
 				$callback = TRUE;
@@ -556,7 +657,7 @@
 			// Strip the parameter (if exists) from the rule
 			// Rules can contain a parameter: max_length[5]
 			$param = FALSE;
-			if (preg_match("/(.*?)\[(.*)\]/", $rule, $match))
+			if (preg_match('/(.*?)\[(.*)\]/', $rule, $match))
 			{
 				$rule	= $match[1];
 				$param	= $match[2];
@@ -567,68 +668,69 @@
 			{
 				if ( ! method_exists($this->CI, $rule))
 				{
-					continue;
+					log_message('debug', 'Unable to find callback validation rule: '.$rule);
+					$result = FALSE;
 				}
-
-				// Run the function and grab the result
-				$result = $this->CI->$rule($postdata, $param);
+				else
+				{
+					// Run the function and grab the result
+					$result = $this->CI->$rule($postdata, $param);
+				}
 
 				// Re-assign the result to the master data array
 				if ($_in_array === TRUE)
 				{
-					$this->_field_data[$row['field']]['postdata'][$cycles] = (is_bool($result)) ? $postdata : $result;
+					$this->_field_data[$row['field']]['postdata'][$cycles] = is_bool($result) ? $postdata : $result;
 				}
 				else
 				{
-					$this->_field_data[$row['field']]['postdata'] = (is_bool($result)) ? $postdata : $result;
+					$this->_field_data[$row['field']]['postdata'] = is_bool($result) ? $postdata : $result;
 				}
 
 				// If the field isn't required and we just processed a callback we'll move on...
-				if ( ! in_array('required', $rules, TRUE) AND $result !== FALSE)
+				if ( ! in_array('required', $rules, TRUE) && $result !== FALSE)
 				{
 					continue;
 				}
 			}
+			elseif ( ! method_exists($this, $rule))
+			{
+				// If our own wrapper function doesn't exist we see if a native PHP function does.
+				// Users can use any native PHP function call that has one param.
+				if (function_exists($rule))
+				{
+					$result = ($param !== FALSE) ? $rule($postdata, $param) : $rule($postdata);
+
+					if ($_in_array === TRUE)
+					{
+						$this->_field_data[$row['field']]['postdata'][$cycles] = is_bool($result) ? $postdata : $result;
+					}
+					else
+					{
+						$this->_field_data[$row['field']]['postdata'] = is_bool($result) ? $postdata : $result;
+					}
+				}
+				else
+				{
+					log_message('debug', 'Unable to find validation rule: '.$rule);
+					$result = FALSE;
+				}
+			}
 			else
 			{
-				if ( ! method_exists($this, $rule))
-				{
-					// If our own wrapper function doesn't exist we see if a native PHP function does.
-					// Users can use any native PHP function call that has one param.
-					if (function_exists($rule))
-					{
-						$result = $rule($postdata);
-
-						if ($_in_array === TRUE)
-						{
-							$this->_field_data[$row['field']]['postdata'][$cycles] = (is_bool($result)) ? $postdata : $result;
-						}
-						else
-						{
-							$this->_field_data[$row['field']]['postdata'] = (is_bool($result)) ? $postdata : $result;
-						}
-					}
-					else
-					{
-						log_message('debug', "Unable to find validation rule: ".$rule);
-					}
-
-					continue;
-				}
-
 				$result = $this->$rule($postdata, $param);
 
 				if ($_in_array === TRUE)
 				{
-					$this->_field_data[$row['field']]['postdata'][$cycles] = (is_bool($result)) ? $postdata : $result;
+					$this->_field_data[$row['field']]['postdata'][$cycles] = is_bool($result) ? $postdata : $result;
 				}
 				else
 				{
-					$this->_field_data[$row['field']]['postdata'] = (is_bool($result)) ? $postdata : $result;
+					$this->_field_data[$row['field']]['postdata'] = is_bool($result) ? $postdata : $result;
 				}
 			}
 
-			// Did the rule test negatively?  If so, grab the error.
+			// Did the rule test negatively? If so, grab the error.
 			if ($result === FALSE)
 			{
 				if ( ! isset($this->_error_messages[$rule]))
@@ -644,7 +746,7 @@
 				}
 
 				// Is the parameter we are inserting into the error message the name
-				// of another field?  If so we need to grab its "field label"
+				// of another field? If so we need to grab its "field label"
 				if (isset($this->_field_data[$param], $this->_field_data[$param]['label']))
 				{
 					$param = $this->_translate_fieldname($this->_field_data[$param]['label']);
@@ -678,7 +780,7 @@
 	{
 		// Do we need to translate the field name?
 		// We look for the prefix lang: to determine this
-		if (substr($fieldname, 0, 5) === 'lang:')
+		if (strpos($fieldname, 'lang:') === 0)
 		{
 			// Grab the variable
 			$line = substr($fieldname, 5);
@@ -703,11 +805,11 @@
 	 *
 	 * @param	string	the field name
 	 * @param	string
-	 * @return	void
+	 * @return	string
 	 */
 	public function set_value($field = '', $default = '')
 	{
-		if ( ! isset($this->_field_data[$field]))
+		if ( ! isset($this->_field_data[$field], $this->_field_data[$field]['postdata']))
 		{
 			return $default;
 		}
@@ -732,21 +834,17 @@
 	 *
 	 * @param	string
 	 * @param	string
+	 * @param	bool
 	 * @return	string
 	 */
 	public function set_select($field = '', $value = '', $default = FALSE)
 	{
-		if ( ! isset($this->_field_data[$field]) OR ! isset($this->_field_data[$field]['postdata']))
+		if ( ! isset($this->_field_data[$field], $this->_field_data[$field]['postdata']))
 		{
-			if ($default === TRUE AND count($this->_field_data) === 0)
-			{
-				return ' selected="selected"';
-			}
-			return '';
+			return ($default === TRUE && count($this->_field_data) === 0) ? ' selected="selected"' : '';
 		}
 
 		$field = $this->_field_data[$field]['postdata'];
-
 		if (is_array($field))
 		{
 			if ( ! in_array($value, $field))
@@ -754,12 +852,9 @@
 				return '';
 			}
 		}
-		else
+		elseif (($field === '' OR $value === '') OR ($field !== $value))
 		{
-			if (($field == '' OR $value == '') OR ($field != $value))
-			{
-				return '';
-			}
+			return '';
 		}
 
 		return ' selected="selected"';
@@ -775,21 +870,17 @@
 	 *
 	 * @param	string
 	 * @param	string
+	 * @param	bool
 	 * @return	string
 	 */
 	public function set_radio($field = '', $value = '', $default = FALSE)
 	{
-		if ( ! isset($this->_field_data[$field]) OR ! isset($this->_field_data[$field]['postdata']))
+		if ( ! isset($this->_field_data[$field], $this->_field_data[$field]['postdata']))
 		{
-			if ($default === TRUE AND count($this->_field_data) === 0)
-			{
-				return ' checked="checked"';
-			}
-			return '';
+			return ($default === TRUE && count($this->_field_data) === 0) ? ' checked="checked"' : '';
 		}
 
 		$field = $this->_field_data[$field]['postdata'];
-
 		if (is_array($field))
 		{
 			if ( ! in_array($value, $field))
@@ -797,12 +888,9 @@
 				return '';
 			}
 		}
-		else
+		elseif (($field === '' OR $value === '') OR ($field !== $value))
 		{
-			if (($field == '' OR $value == '') OR ($field != $value))
-			{
-				return '';
-			}
+			return '';
 		}
 
 		return ' checked="checked"';
@@ -818,6 +906,7 @@
 	 *
 	 * @param	string
 	 * @param	string
+	 * @param	bool
 	 * @return	string
 	 */
 	public function set_checkbox($field = '', $value = '', $default = FALSE)
@@ -836,7 +925,7 @@
 	 */
 	public function required($str)
 	{
-		return ( ! is_array($str)) ? (trim($str) !== '') : ( ! empty($str));
+		return is_array($str) ? (bool) count($str) : (trim($str) !== '');
 	}
 
 	// --------------------------------------------------------------------
@@ -845,7 +934,7 @@
 	 * Performs a Regular Expression match test.
 	 *
 	 * @param	string
-	 * @param	regex
+	 * @param	string	regex
 	 * @return	bool
 	 */
 	public function regex_match($str, $regex)
@@ -859,19 +948,14 @@
 	 * Match one field to another
 	 *
 	 * @param	string
-	 * @param	field
+	 * @param	string	field
 	 * @return	bool
 	 */
 	public function matches($str, $field)
 	{
-		if ( ! isset($_POST[$field]))
-		{
-			return FALSE;
-		}
+		$validation_array = empty($this->validation_data) ? $_POST : $this->validation_data;
 
-		$field = $_POST[$field];
-
-		return ($str === $field);
+		return isset($validation_array[$field]) ? ($str === $validation_array[$field]) : FALSE;
 	}
 
 	// --------------------------------------------------------------------
@@ -883,7 +967,7 @@
 	 * in the specified database field.
 	 *
 	 * @param	string
-	 * @param	field
+	 * @param	string	field
 	 * @return	bool
 	 */
 	public function is_unique($str, $field)
@@ -903,22 +987,19 @@
 	 * Minimum Length
 	 *
 	 * @param	string
-	 * @param	value
+	 * @param	int
 	 * @return	bool
 	 */
 	public function min_length($str, $val)
 	{
-		if (preg_match("/[^0-9]/", $val))
+		if (preg_match('/[^0-9]/', $val))
 		{
 			return FALSE;
 		}
 
-		if (function_exists('mb_strlen'))
-		{
-			return ! (mb_strlen($str) < $val);
-		}
-
-		return ! (strlen($str) < $val);
+		return (MB_ENABLED === TRUE)
+			? ($val <= mb_strlen($str))
+			: ($val <= strlen($str));
 	}
 
 	// --------------------------------------------------------------------
@@ -927,22 +1008,19 @@
 	 * Max Length
 	 *
 	 * @param	string
-	 * @param	value
+	 * @param	int
 	 * @return	bool
 	 */
 	public function max_length($str, $val)
 	{
-		if (preg_match("/[^0-9]/", $val))
+		if (preg_match('/[^0-9]/', $val))
 		{
 			return FALSE;
 		}
 
-		if (function_exists('mb_strlen'))
-		{
-			return ! (mb_strlen($str) > $val);
-		}
-
-		return ! (strlen($str) > $val);
+		return (MB_ENABLED === TRUE)
+			? ($val >= mb_strlen($str))
+			: ($val >= strlen($str));
 	}
 
 	// --------------------------------------------------------------------
@@ -951,22 +1029,19 @@
 	 * Exact Length
 	 *
 	 * @param	string
-	 * @param	value
+	 * @param	int
 	 * @return	bool
 	 */
 	public function exact_length($str, $val)
 	{
-		if (preg_match("/[^0-9]/", $val))
+		if (preg_match('/[^0-9]/', $val))
 		{
 			return FALSE;
 		}
 
-		if (function_exists('mb_strlen'))
-		{
-			return (mb_strlen($str) == $val);
-		}
-
-		return (strlen($str) == $val);
+		return (MB_ENABLED === TRUE)
+			? (mb_strlen($str) === $val)
+			: (strlen($str) === $val);
 	}
 
 	// --------------------------------------------------------------------
@@ -1014,11 +1089,12 @@
 	 * Validate IP Address
 	 *
 	 * @param	string
+	 * @param	string	'ipv4' or 'ipv6' to validate a specific IP format
 	 * @return	bool
 	 */
-	public function valid_ip($ip)
+	public function valid_ip($ip, $which = '')
 	{
-		return $this->CI->input->valid_ip($ip);
+		return $this->CI->input->valid_ip($ip, $which);
 	}
 
 	// --------------------------------------------------------------------
@@ -1077,19 +1153,6 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 * Is Numeric
-	 *
-	 * @param	string
-	 * @return	bool
-	 */
-	public function is_numeric($str)
-	{
-		return is_numeric($str);
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
 	 * Integer
 	 *
 	 * @param	string
@@ -1116,18 +1179,29 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 * Greather than
+	 * Greater than
 	 *
 	 * @param	string
+	 * @param	int
 	 * @return	bool
 	 */
 	public function greater_than($str, $min)
 	{
-		if ( ! is_numeric($str))
-		{
-			return FALSE;
-		}
-		return $str > $min;
+		return is_numeric($str) ? ($str > $min) : FALSE;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Equal to or Greater than
+	 *
+	 * @param	string
+	 * @param	int
+	 * @return	bool
+	 */
+	public function greater_than_equal_to($str, $min)
+	{
+		return is_numeric($str) ? ($str >= $min) : FALSE;
 	}
 
 	// --------------------------------------------------------------------
@@ -1136,15 +1210,26 @@
 	 * Less than
 	 *
 	 * @param	string
+	 * @param	int
 	 * @return	bool
 	 */
 	public function less_than($str, $max)
 	{
-		if ( ! is_numeric($str))
-		{
-			return FALSE;
-		}
-		return $str < $max;
+		return is_numeric($str) ? ($str < $max) : FALSE;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Equal to or Less than
+	 *
+	 * @param	string
+	 * @param	int
+	 * @return	bool
+	 */
+	public function less_than_equal_to($str, $max)
+	{
+		return is_numeric($str) ? ($str <= $max) : FALSE;
 	}
 
 	// --------------------------------------------------------------------
@@ -1170,7 +1255,7 @@
 	 */
 	public function is_natural_no_zero($str)
 	{
-		return ($str != 0 AND preg_match('/^[0-9]+$/', $str));
+		return ($str !== 0 && preg_match('/^[0-9]+$/', $str));
 	}
 
 	// --------------------------------------------------------------------
@@ -1186,7 +1271,7 @@
 	 */
 	public function valid_base64($str)
 	{
-		return (bool) ! preg_match('/[^a-zA-Z0-9\/\+=]/', $str);
+		return ! preg_match('/[^a-zA-Z0-9\/\+=]/', $str);
 	}
 
 	// --------------------------------------------------------------------
@@ -1212,12 +1297,12 @@
 			return $data;
 		}
 
-		if ($this->_safe_form_data == FALSE OR $data === '')
+		if ($this->_safe_form_data === FALSE OR $data === '')
 		{
 			return $data;
 		}
 
-		return str_replace(array("'", '"', '<', '>'), array("&#39;", "&quot;", '&lt;', '&gt;'), stripslashes($data));
+		return str_replace(array("'", '"', '<', '>'), array('&#39;', '&quot;', '&lt;', '&gt;'), stripslashes($data));
 	}
 
 	// --------------------------------------------------------------------
@@ -1230,14 +1315,14 @@
 	 */
 	public function prep_url($str = '')
 	{
-		if ($str == 'http://' OR $str == '')
+		if ($str === 'http://' OR $str === '')
 		{
 			return '';
 		}
 
-		if (substr($str, 0, 7) !== 'http://' && substr($str, 0, 8) !== 'https://')
+		if (strpos($str, 'http://') !== 0 && strpos($str, 'https://') !== 0)
 		{
-			$str = 'http://'.$str;
+			return 'http://'.$str;
 		}
 
 		return $str;
@@ -1282,8 +1367,26 @@
 		return str_replace(array('<?php', '<?PHP', '<?', '?>'),  array('&lt;?php', '&lt;?PHP', '&lt;?', '?&gt;'), $str);
 	}
 
+	// --------------------------------------------------------------------
+
+	/**
+	 * Reset validation vars
+	 *
+	 * Prevents subsequent validation routines from being affected by the
+	 * results of any previous validation routine due to the CI singleton.
+	 *
+	 * @return	void
+	 */
+	public function reset_validation()
+	{
+		$this->_field_data = array();
+		$this->_config_rules = array();
+		$this->_error_array = array();
+		$this->_error_messages = array();
+		$this->error_string = '';
+	}
+
 }
-// END Form Validation Class
 
 /* End of file Form_validation.php */
-/* Location: ./system/libraries/Form_validation.php */
+/* Location: ./system/libraries/Form_validation.php */
\ No newline at end of file
diff --git a/system/libraries/Ftp.php b/system/libraries/Ftp.php
index ab395b0..461e884 100644
--- a/system/libraries/Ftp.php
+++ b/system/libraries/Ftp.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * FTP Class
  *
@@ -42,16 +40,10 @@
 	public $username	= '';
 	public $password	= '';
 	public $port		= 21;
-	public $passive	= TRUE;
+	public $passive		= TRUE;
 	public $debug		= FALSE;
-	public $conn_id	= FALSE;
+	public $conn_id		= FALSE;
 
-
-	/**
-	 * Constructor - Sets Preferences
-	 *
-	 * The constructor can be passed an array of config values
-	 */
 	public function __construct($config = array())
 	{
 		if (count($config) > 0)
@@ -59,7 +51,7 @@
 			$this->initialize($config);
 		}
 
-		log_message('debug', "FTP Class Initialized");
+		log_message('debug', 'FTP Class Initialized');
 	}
 
 	// --------------------------------------------------------------------
@@ -67,7 +59,6 @@
 	/**
 	 * Initialize preferences
 	 *
-	 * @access	public
 	 * @param	array
 	 * @return	void
 	 */
@@ -90,7 +81,6 @@
 	/**
 	 * FTP Connect
 	 *
-	 * @access	public
 	 * @param	array	 the connection values
 	 * @return	bool
 	 */
@@ -103,7 +93,7 @@
 
 		if (FALSE === ($this->conn_id = @ftp_connect($this->hostname, $this->port)))
 		{
-			if ($this->debug == TRUE)
+			if ($this->debug === TRUE)
 			{
 				$this->_error('ftp_unable_to_connect');
 			}
@@ -112,7 +102,7 @@
 
 		if ( ! $this->_login())
 		{
-			if ($this->debug == TRUE)
+			if ($this->debug === TRUE)
 			{
 				$this->_error('ftp_unable_to_login');
 			}
@@ -120,7 +110,7 @@
 		}
 
 		// Set passive mode if needed
-		if ($this->passive == TRUE)
+		if ($this->passive === TRUE)
 		{
 			ftp_pasv($this->conn_id, TRUE);
 		}
@@ -133,10 +123,9 @@
 	/**
 	 * FTP Login
 	 *
-	 * @access	private
 	 * @return	bool
 	 */
-	private function _login()
+	protected function _login()
 	{
 		return @ftp_login($this->conn_id, $this->username, $this->password);
 	}
@@ -146,14 +135,13 @@
 	/**
 	 * Validates the connection ID
 	 *
-	 * @access	private
 	 * @return	bool
 	 */
-	private function _is_conn()
+	protected function _is_conn()
 	{
 		if ( ! is_resource($this->conn_id))
 		{
-			if ($this->debug == TRUE)
+			if ($this->debug === TRUE)
 			{
 				$this->_error('ftp_no_connection');
 			}
@@ -164,24 +152,22 @@
 
 	// --------------------------------------------------------------------
 
-
 	/**
 	 * Change directory
 	 *
 	 * The second parameter lets us momentarily turn off debugging so that
 	 * this function can be used to test for the existence of a folder
-	 * without throwing an error.  There's no FTP equivalent to is_dir()
+	 * without throwing an error. There's no FTP equivalent to is_dir()
 	 * so we do it by trying to change to a particular directory.
 	 * Internally, this parameter is only used by the "mirror" function below.
 	 *
-	 * @access	public
 	 * @param	string
 	 * @param	bool
 	 * @return	bool
 	 */
 	public function changedir($path = '', $supress_debug = FALSE)
 	{
-		if ($path == '' OR ! $this->_is_conn())
+		if ($path === '' OR ! $this->_is_conn())
 		{
 			return FALSE;
 		}
@@ -190,7 +176,7 @@
 
 		if ($result === FALSE)
 		{
-			if ($this->debug == TRUE AND $supress_debug == FALSE)
+			if ($this->debug === TRUE && $supress_debug === FALSE)
 			{
 				$this->_error('ftp_unable_to_changedir');
 			}
@@ -205,13 +191,13 @@
 	/**
 	 * Create a directory
 	 *
-	 * @access	public
 	 * @param	string
+	 * @param	int
 	 * @return	bool
 	 */
 	public function mkdir($path = '', $permissions = NULL)
 	{
-		if ($path == '' OR ! $this->_is_conn())
+		if ($path === '' OR ! $this->_is_conn())
 		{
 			return FALSE;
 		}
@@ -220,7 +206,7 @@
 
 		if ($result === FALSE)
 		{
-			if ($this->debug == TRUE)
+			if ($this->debug === TRUE)
 			{
 				$this->_error('ftp_unable_to_makdir');
 			}
@@ -230,7 +216,7 @@
 		// Set file permissions if needed
 		if ( ! is_null($permissions))
 		{
-			$this->chmod($path, (int)$permissions);
+			$this->chmod($path, (int) $permissions);
 		}
 
 		return TRUE;
@@ -241,10 +227,10 @@
 	/**
 	 * Upload a file to the server
 	 *
-	 * @access	public
 	 * @param	string
 	 * @param	string
 	 * @param	string
+	 * @param	int
 	 * @return	bool
 	 */
 	public function upload($locpath, $rempath, $mode = 'auto', $permissions = NULL)
@@ -274,7 +260,7 @@
 
 		if ($result === FALSE)
 		{
-			if ($this->debug == TRUE)
+			if ($this->debug === TRUE)
 			{
 				$this->_error('ftp_unable_to_upload');
 			}
@@ -284,7 +270,7 @@
 		// Set file permissions if needed
 		if ( ! is_null($permissions))
 		{
-			$this->chmod($rempath, (int)$permissions);
+			$this->chmod($rempath, (int) $permissions);
 		}
 
 		return TRUE;
@@ -295,7 +281,6 @@
 	/**
 	 * Download a file from a remote server to the local server
 	 *
-	 * @access	public
 	 * @param	string
 	 * @param	string
 	 * @param	string
@@ -322,7 +307,7 @@
 
 		if ($result === FALSE)
 		{
-			if ($this->debug == TRUE)
+			if ($this->debug === TRUE)
 			{
 				$this->_error('ftp_unable_to_download');
 			}
@@ -337,7 +322,6 @@
 	/**
 	 * Rename (or move) a file
 	 *
-	 * @access	public
 	 * @param	string
 	 * @param	string
 	 * @param	bool
@@ -354,9 +338,9 @@
 
 		if ($result === FALSE)
 		{
-			if ($this->debug == TRUE)
+			if ($this->debug === TRUE)
 			{
-				$this->_error('ftp_unable_to_' . ($move == FALSE ? 'rename' : 'move'));
+				$this->_error('ftp_unable_to_' . ($move === FALSE ? 'rename' : 'move'));
 			}
 			return FALSE;
 		}
@@ -369,7 +353,6 @@
 	/**
 	 * Move a file
 	 *
-	 * @access	public
 	 * @param	string
 	 * @param	string
 	 * @return	bool
@@ -384,7 +367,6 @@
 	/**
 	 * Rename (or move) a file
 	 *
-	 * @access	public
 	 * @param	string
 	 * @return	bool
 	 */
@@ -399,7 +381,7 @@
 
 		if ($result === FALSE)
 		{
-			if ($this->debug == TRUE)
+			if ($this->debug === TRUE)
 			{
 				$this->_error('ftp_unable_to_delete');
 			}
@@ -415,7 +397,6 @@
 	 * Delete a folder and recursively delete everything (including sub-folders)
 	 * containted within it.
 	 *
-	 * @access	public
 	 * @param	string
 	 * @return	bool
 	 */
@@ -427,11 +408,11 @@
 		}
 
 		// Add a trailing slash to the file path if needed
-		$filepath = preg_replace("/(.+?)\/*$/", "\\1/",  $filepath);
+		$filepath = preg_replace('/(.+?)\/*$/', '\\1/',  $filepath);
 
 		$list = $this->list_files($filepath);
 
-		if ($list !== FALSE AND count($list) > 0)
+		if ($list !== FALSE && count($list) > 0)
 		{
 			foreach ($list as $item)
 			{
@@ -448,7 +429,7 @@
 
 		if ($result === FALSE)
 		{
-			if ($this->debug == TRUE)
+			if ($this->debug === TRUE)
 			{
 				$this->_error('ftp_unable_to_delete');
 			}
@@ -463,7 +444,6 @@
 	/**
 	 * Set file permissions
 	 *
-	 * @access	public
 	 * @param	string	the file path
 	 * @param	string	the permissions
 	 * @return	bool
@@ -479,7 +459,7 @@
 
 		if ($result === FALSE)
 		{
-			if ($this->debug == TRUE)
+			if ($this->debug === TRUE)
 			{
 				$this->_error('ftp_unable_to_chmod');
 			}
@@ -494,7 +474,6 @@
 	/**
 	 * FTP List files in the specified directory
 	 *
-	 * @access	public
 	 * @return	array
 	 */
 	public function list_files($path = '.')
@@ -512,11 +491,11 @@
 	/**
 	 * Read a directory and recreate it remotely
 	 *
-	 * This function recursively reads a folder and everything it contains (including
-	 * sub-folders) and creates a mirror via FTP based on it.  Whatever the directory structure
-	 * of the original file path will be recreated on the server.
+	 * This function recursively reads a folder and everything it contains
+	 * (including sub-folders) and creates a mirror via FTP based on it.
+	 * Whatever the directory structure of the original file path will be
+	 * recreated on the server.
 	 *
-	 * @access	public
 	 * @param	string	path to source with trailing slash
 	 * @param	string	path to destination - include the base folder with trailing slash
 	 * @return	bool
@@ -532,7 +511,7 @@
 		if ($fp = @opendir($locpath))
 		{
 			// Attempt to open the remote file path and try to create it, if it doesn't exist
-			if ( ! $this->changedir($rempath, TRUE) AND ( ! $this->mkdir($rempath) OR ! $this->changedir($rempath)))
+			if ( ! $this->changedir($rempath, TRUE) && ( ! $this->mkdir($rempath) OR ! $this->changedir($rempath)))
 			{
 				return FALSE;
 			}
@@ -542,9 +521,9 @@
 			{
 				if (@is_dir($locpath.$file) && $file[0] !== '.')
 				{
-					$this->mirror($locpath.$file."/", $rempath.$file."/");
+					$this->mirror($locpath.$file.'/', $rempath.$file.'/');
 				}
-				elseif ($file[0] !== ".")
+				elseif ($file[0] !== '.')
 				{
 					// Get the file extension so we can se the upload type
 					$ext = $this->_getext($file);
@@ -559,17 +538,15 @@
 		return FALSE;
 	}
 
-
 	// --------------------------------------------------------------------
 
 	/**
 	 * Extract the file extension
 	 *
-	 * @access	private
 	 * @param	string
 	 * @return	string
 	 */
-	private function _getext($filename)
+	protected function _getext($filename)
 	{
 		if (FALSE === strpos($filename, '.'))
 		{
@@ -580,36 +557,34 @@
 		return end($x);
 	}
 
-
 	// --------------------------------------------------------------------
 
 	/**
 	 * Set the upload type
 	 *
-	 * @access	private
 	 * @param	string
 	 * @return	string
 	 */
-	private function _settype($ext)
+	protected function _settype($ext)
 	{
 		$text_types = array(
-							'txt',
-							'text',
-							'php',
-							'phps',
-							'php4',
-							'js',
-							'css',
-							'htm',
-							'html',
-							'phtml',
-							'shtml',
-							'log',
-							'xml'
-							);
+					'txt',
+					'text',
+					'php',
+					'phps',
+					'php4',
+					'js',
+					'css',
+					'htm',
+					'html',
+					'phtml',
+					'shtml',
+					'log',
+					'xml'
+				);
 
 
-		return (in_array($ext, $text_types)) ? 'ascii' : 'binary';
+		return in_array($ext, $text_types) ? 'ascii' : 'binary';
 	}
 
 	// ------------------------------------------------------------------------
@@ -617,7 +592,6 @@
 	/**
 	 * Close the connection
 	 *
-	 * @access	public
 	 * @return	bool
 	 */
 	public function close()
@@ -635,20 +609,17 @@
 	/**
 	 * Display error message
 	 *
-	 * @access	private
 	 * @param	string
 	 * @return	void
 	 */
-	private function _error($line)
+	protected function _error($line)
 	{
 		$CI =& get_instance();
 		$CI->lang->load('ftp');
 		show_error($CI->lang->line($line));
 	}
 
-
 }
-// END FTP Class
 
 /* End of file Ftp.php */
-/* Location: ./system/libraries/Ftp.php */
+/* Location: ./system/libraries/Ftp.php */
\ No newline at end of file
diff --git a/system/libraries/Image_lib.php b/system/libraries/Image_lib.php
index a226ae8..4735dfd 100644
--- a/system/libraries/Image_lib.php
+++ b/system/libraries/Image_lib.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * Image Manipulation class
  *
@@ -38,60 +36,334 @@
  */
 class CI_Image_lib {
 
-	public $image_library		= 'gd2';	// Can be:  imagemagick, netpbm, gd, gd2
+	/**
+	 * PHP extension/library to use for image manipulation
+	 * Can be: imagemagick, netpbm, gd, gd2
+	 *
+	 * @var string
+	 */
+	public $image_library		= 'gd2';
+
+	/**
+	 * Path to the graphic library (if applicable)
+	 *
+	 * @var string
+	 */
 	public $library_path		= '';
-	public $dynamic_output		= FALSE;	// Whether to send to browser or write to disk
+
+	/**
+	 * Whether to send to browser or write to disk
+	 *
+	 * @var bool
+	 */
+	public $dynamic_output		= FALSE;
+
+	/**
+	 * Path to original image
+	 *
+	 * @var string
+	 */
 	public $source_image		= '';
-	public $new_image			= '';
-	public $width				= '';
-	public $height				= '';
-	public $quality			= '90';
+
+	/**
+	 * Path to the modified image
+	 *
+	 * @var string
+	 */
+	public $new_image		= '';
+
+	/**
+	 * Image width
+	 *
+	 * @var int
+	 */
+	public $width			= '';
+
+	/**
+	 * Image height
+	 *
+	 * @var int
+	 */
+	public $height			= '';
+
+	/**
+	 * Quality percentage of new image
+	 *
+	 * @var int
+	 */
+	public $quality			= 90;
+
+	/**
+	 * Whether to create a thumbnail
+	 *
+	 * @var bool
+	 */
 	public $create_thumb		= FALSE;
+
+	/**
+	 * String to add to thumbnail version of image
+	 *
+	 * @var string
+	 */
 	public $thumb_marker		= '_thumb';
-	public $maintain_ratio		= TRUE;		// Whether to maintain aspect ratio when resizing or use hard values
-	public $master_dim			= 'auto';	// auto, height, or width.  Determines what to use as the master dimension
+
+	/**
+	 * Whether to maintain aspect ratio when resizing or use hard values
+	 *
+	 * @var bool
+	 */
+	public $maintain_ratio		= TRUE;
+
+	/**
+	 * auto, height, or width.  Determines what to use as the master dimension
+	 *
+	 * @var string
+	 */
+	public $master_dim		= 'auto';
+
+	/**
+	 * Angle at to rotate image
+	 *
+	 * @var string
+	 */
 	public $rotation_angle		= '';
-	public $x_axis				= '';
-	public $y_axis				= '';
 
+	/**
+	 * X Coordinate for manipulation of the current image
+	 *
+	 * @var int
+	 */
+	public $x_axis			= '';
+
+	/**
+	 * Y Coordinate for manipulation of the current image
+	 *
+	 * @var int
+	 */
+	public $y_axis			= '';
+
+	// --------------------------------------------------------------------------
 	// Watermark Vars
-	public $wm_text			= '';			// Watermark text if graphic is not used
-	public $wm_type			= 'text';		// Type of watermarking.  Options:  text/overlay
-	public $wm_x_transp		= 4;
-	public $wm_y_transp		= 4;
-	public $wm_overlay_path	= '';			// Watermark image path
-	public $wm_font_path		= '';			// TT font
-	public $wm_font_size		= 17;			// Font size (different versions of GD will either use points or pixels)
-	public $wm_vrt_alignment	= 'B';			// Vertical alignment:   T M B
-	public $wm_hor_alignment	= 'C';			// Horizontal alignment: L R C
-	public $wm_padding			= 0;			// Padding around text
-	public $wm_hor_offset		= 0;			// Lets you push text to the right
-	public $wm_vrt_offset		= 0;			// Lets you push  text down
-	protected $wm_font_color		= '#ffffff';	// Text color
-	protected $wm_shadow_color		= '';	// Dropshadow color
-	public $wm_shadow_distance	= 2;			// Dropshadow distance
-	public $wm_opacity			= 50;			// Image opacity: 1 - 100  Only works with image
+	// --------------------------------------------------------------------------
 
+	/**
+	 * Watermark text if graphic is not used
+	 *
+	 * @var string
+	 */
+	public $wm_text			= '';
+
+	/**
+	 * Type of watermarking.  Options:  text/overlay
+	 *
+	 * @var string
+	 */
+	public $wm_type			= 'text';
+
+	/**
+	 * Default transparency for watermark
+	 *
+	 * @var int
+	 */
+	public $wm_x_transp		= 4;
+
+	/**
+	 * Default transparency for watermark
+	 *
+	 * @var int
+	 */
+	public $wm_y_transp		= 4;
+
+	/**
+	 * Watermark image path
+	 *
+	 * @var string
+	 */
+	public $wm_overlay_path		= '';
+
+	/**
+	 * TT font
+	 *
+	 * @var string
+	 */
+	public $wm_font_path		= '';
+
+	/**
+	 * Font size (different versions of GD will either use points or pixels)
+	 *
+	 * @var int
+	 */
+	public $wm_font_size		= 17;
+
+	/**
+	 * Vertical alignment:   T M B
+	 *
+	 * @var string
+	 */
+	public $wm_vrt_alignment	= 'B';
+
+	/**
+	 * Horizontal alignment: L R C
+	 *
+	 * @var string
+	 */
+	public $wm_hor_alignment	= 'C';
+
+	/**
+	 * Padding around text
+	 *
+	 * @var int
+	 */
+	public $wm_padding			= 0;
+
+	/**
+	 * Lets you push text to the right
+	 *
+	 * @var int
+	 */
+	public $wm_hor_offset		= 0;
+
+	/**
+	 * Lets you push text down
+	 *
+	 * @var int
+	 */
+	public $wm_vrt_offset		= 0;
+
+	/**
+	 * Text color
+	 *
+	 * @var string
+	 */
+	protected $wm_font_color	= '#ffffff';
+
+	/**
+	 * Dropshadow color
+	 *
+	 * @var string
+	 */
+	protected $wm_shadow_color	= '';
+
+	/**
+	 * Dropshadow distance
+	 *
+	 * @var int
+	 */
+	public $wm_shadow_distance	= 2;
+
+	/**
+	 * Image opacity: 1 - 100  Only works with image
+	 *
+	 * @var int
+	 */
+	public $wm_opacity		= 50;
+
+	// --------------------------------------------------------------------------
 	// Private Vars
+	// --------------------------------------------------------------------------
+
+	/**
+	 * Source image folder
+	 *
+	 * @var string
+	 */
 	public $source_folder		= '';
+
+	/**
+	 * Destination image folder
+	 *
+	 * @var string
+	 */
 	public $dest_folder		= '';
-	public $mime_type			= '';
-	public $orig_width			= '';
+
+	/**
+	 * Image mime-type
+	 *
+	 * @var string
+	 */
+	public $mime_type		= '';
+
+	/**
+	 * Original image width
+	 *
+	 * @var int
+	 */
+	public $orig_width		= '';
+
+	/**
+	 * Original image height
+	 *
+	 * @var int
+	 */
 	public $orig_height		= '';
-	public $image_type			= '';
-	public $size_str			= '';
+
+	/**
+	 * Image format
+	 *
+	 * @var string
+	 */
+	public $image_type		= '';
+
+	/**
+	 * Size of current image
+	 *
+	 * @var string
+	 */
+	public $size_str		= '';
+
+	/**
+	 * Full path to source image
+	 *
+	 * @var string
+	 */
 	public $full_src_path		= '';
+
+	/**
+	 * Full path to destination image
+	 *
+	 * @var string
+	 */
 	public $full_dst_path		= '';
-	public $create_fnc			= 'imagecreatetruecolor';
-	public $copy_fnc			= 'imagecopyresampled';
-	public $error_msg			= array();
+
+	/**
+	 * Name of function to create image
+	 *
+	 * @var string
+	 */
+	public $create_fnc		= 'imagecreatetruecolor';
+
+	/**
+	 * Name of function to copy image
+	 *
+	 * @var string
+	 */
+	public $copy_fnc		= 'imagecopyresampled';
+
+	/**
+	 * Error messages
+	 *
+	 * @var array
+	 */
+	public $error_msg		= array();
+
+	/**
+	 * Whether to have a drop shadow on watermark
+	 *
+	 * @var bool
+	 */
 	protected $wm_use_drop_shadow	= FALSE;
+
+	/**
+	 * Whether to use truetype fonts
+	 *
+	 * @var bool
+	 */
 	public $wm_use_truetype	= FALSE;
 
 	/**
-	 * Constructor
+	 * Initialize Image Library
 	 *
-	 * @param	string
+	 * @param	array	$props
 	 * @return	void
 	 */
 	public function __construct($props = array())
@@ -101,7 +373,7 @@
 			$this->initialize($props);
 		}
 
-		log_message('debug', "Image Lib Class Initialized");
+		log_message('debug', 'Image Lib Class Initialized');
 	}
 
 	// --------------------------------------------------------------------
@@ -124,7 +396,7 @@
 
 		$this->image_library 		= 'gd2';
 		$this->dynamic_output 		= FALSE;
-		$this->quality 				= '90';
+		$this->quality 				= 90;
 		$this->create_thumb 		= FALSE;
 		$this->thumb_marker 		= '_thumb';
 		$this->maintain_ratio 		= TRUE;
@@ -158,9 +430,7 @@
 	 */
 	public function initialize($props = array())
 	{
-		/*
-		 * Convert array elements into class variables
-		 */
+		// Convert array elements into class variables
 		if (count($props) > 0)
 		{
 			foreach ($props as $key => $val)
@@ -195,25 +465,18 @@
 			}
 		}
 
-		/*
-		 * Is there a source image?
-		 *
-		 * If not, there's no reason to continue
-		 *
-		 */
-		if ($this->source_image == '')
+		// Is there a source image? If not, there's no reason to continue
+		if ($this->source_image === '')
 		{
 			$this->set_error('imglib_source_image_required');
 			return FALSE;
 		}
 
-		/*
-		 * Is getimagesize() Available?
+		/* Is getimagesize() available?
 		 *
 		 * We use it to determine the image properties (width/height).
-		 * Note:  We need to figure out how to determine image
+		 * Note: We need to figure out how to determine image
 		 * properties using ImageMagick and NetPBM
-		 *
 		 */
 		if ( ! function_exists('getimagesize'))
 		{
@@ -223,17 +486,15 @@
 
 		$this->image_library = strtolower($this->image_library);
 
-		/*
-		 * Set the full server path
+		/* Set the full server path
 		 *
 		 * The source image may or may not contain a path.
 		 * Either way, we'll try use realpath to generate the
 		 * full server path in order to more reliably read it.
-		 *
 		 */
-		if (function_exists('realpath') AND @realpath($this->source_image) !== FALSE)
+		if (function_exists('realpath') && @realpath($this->source_image) !== FALSE)
 		{
-			$full_source_path = str_replace("\\", "/", realpath($this->source_image));
+			$full_source_path = str_replace('\\', '/', realpath($this->source_image));
 		}
 		else
 		{
@@ -255,64 +516,58 @@
 		 *
 		 * If the user has set a "new_image" name it means
 		 * we are making a copy of the source image. If not
-		 * it means we are altering the original.  We'll
+		 * it means we are altering the original. We'll
 		 * set the destination filename and path accordingly.
-		 *
 		 */
-		if ($this->new_image == '')
+		if ($this->new_image === '')
 		{
 			$this->dest_image = $this->source_image;
 			$this->dest_folder = $this->source_folder;
 		}
+		elseif (strpos($this->new_image, '/') === FALSE)
+		{
+			$this->dest_folder = $this->source_folder;
+			$this->dest_image = $this->new_image;
+		}
 		else
 		{
-			if (strpos($this->new_image, '/') === FALSE)
+			if (strpos($this->new_image, '/') === FALSE && strpos($this->new_image, '\\') === FALSE)
 			{
-				$this->dest_folder = $this->source_folder;
-				$this->dest_image = $this->new_image;
+				$full_dest_path = str_replace('\\', '/', realpath($this->new_image));
 			}
 			else
 			{
-				if (function_exists('realpath') AND @realpath($this->new_image) !== FALSE)
-				{
-					$full_dest_path = str_replace("\\", "/", realpath($this->new_image));
-				}
-				else
-				{
-					$full_dest_path = $this->new_image;
-				}
+				$full_dest_path = $this->new_image;
+			}
 
-				// Is there a file name?
-				if ( ! preg_match("#\.(jpg|jpeg|gif|png)$#i", $full_dest_path))
-				{
-					$this->dest_folder = $full_dest_path.'/';
-					$this->dest_image = $this->source_image;
-				}
-				else
-				{
-					$x = explode('/', $full_dest_path);
-					$this->dest_image = end($x);
-					$this->dest_folder = str_replace($this->dest_image, '', $full_dest_path);
-				}
+			// Is there a file name?
+			if ( ! preg_match('#\.(jpg|jpeg|gif|png)$#i', $full_dest_path))
+			{
+				$this->dest_folder = $full_dest_path.'/';
+				$this->dest_image = $this->source_image;
+			}
+			else
+			{
+				$x = explode('/', $full_dest_path);
+				$this->dest_image = end($x);
+				$this->dest_folder = str_replace($this->dest_image, '', $full_dest_path);
 			}
 		}
 
-		/*
-		 * Compile the finalized filenames/paths
+		/* Compile the finalized filenames/paths
 		 *
 		 * We'll create two master strings containing the
 		 * full server path to the source image and the
 		 * full server path to the destination image.
 		 * We'll also split the destination image name
 		 * so we can insert the thumbnail marker if needed.
-		 *
 		 */
-		if ($this->create_thumb === FALSE OR $this->thumb_marker == '')
+		if ($this->create_thumb === FALSE OR $this->thumb_marker === '')
 		{
 			$this->thumb_marker = '';
 		}
 
-		$xp	= $this->explode_name($this->dest_image);
+		$xp = $this->explode_name($this->dest_image);
 
 		$filename = $xp['name'];
 		$file_ext = $xp['ext'];
@@ -320,59 +575,60 @@
 		$this->full_src_path = $this->source_folder.$this->source_image;
 		$this->full_dst_path = $this->dest_folder.$filename.$this->thumb_marker.$file_ext;
 
-		/*
-		 * Should we maintain image proportions?
+		/* Should we maintain image proportions?
 		 *
 		 * When creating thumbs or copies, the target width/height
 		 * might not be in correct proportion with the source
-		 * image's width/height.  We'll recalculate it here.
-		 *
+		 * image's width/height. We'll recalculate it here.
 		 */
-		if ($this->maintain_ratio === TRUE && ($this->width != '' AND $this->height != ''))
+		if ($this->maintain_ratio === TRUE && ($this->width !== 0 OR $this->height !== 0))
 		{
 			$this->image_reproportion();
 		}
 
-		/*
-		 * Was a width and height specified?
+		/* Was a width and height specified?
 		 *
-		 * If the destination width/height was
-		 * not submitted we will use the values
-		 * from the actual file
-		 *
+		 * If the destination width/height was not submitted we
+		 * will use the values from the actual file
 		 */
-		if ($this->width == '')
-			$this->width = $this->orig_width;
-
-		if ($this->height == '')
-			$this->height = $this->orig_height;
-
-		// Set the quality
-		$this->quality = trim(str_replace("%", "", $this->quality));
-
-		if ($this->quality == '' OR $this->quality == 0 OR ! is_numeric($this->quality))
-			$this->quality = 90;
-
-		// Set the x/y coordinates
-		$this->x_axis = ($this->x_axis == '' OR ! is_numeric($this->x_axis)) ? 0 : $this->x_axis;
-		$this->y_axis = ($this->y_axis == '' OR ! is_numeric($this->y_axis)) ? 0 : $this->y_axis;
-
-		// Watermark-related Stuff...
-		if ($this->wm_overlay_path != '')
+		if ($this->width === '')
 		{
-			$this->wm_overlay_path = str_replace("\\", "/", realpath($this->wm_overlay_path));
+			$this->width = $this->orig_width;
 		}
 
-		if ($this->wm_shadow_color != '')
+		if ($this->height === '')
+		{
+			$this->height = $this->orig_height;
+		}
+
+		// Set the quality
+		$this->quality = trim(str_replace('%', '', $this->quality));
+
+		if ($this->quality === '' OR $this->quality === 0 OR ! preg_match('/^[0-9]+$/', $this->quality))
+		{
+			$this->quality = 90;
+		}
+
+		// Set the x/y coordinates
+		is_numeric($this->x_axis) OR $this->x_axis = 0;
+		is_numeric($this->y_axis) OR $this->y_axis = 0;
+
+		// Watermark-related Stuff...
+		if ($this->wm_overlay_path !== '')
+		{
+			$this->wm_overlay_path = str_replace('\\', '/', realpath($this->wm_overlay_path));
+		}
+
+		if ($this->wm_shadow_color !== '')
 		{
 			$this->wm_use_drop_shadow = TRUE;
 		}
-		elseif ($this->wm_use_drop_shadow == TRUE AND $this->wm_shadow_color == '')
+		elseif ($this->wm_use_drop_shadow === TRUE && $this->wm_shadow_color === '')
 		{
 			$this->wm_use_drop_shadow = FALSE;
 		}
 
-		if ($this->wm_font_path != '')
+		if ($this->wm_font_path !== '')
 		{
 			$this->wm_use_truetype = TRUE;
 		}
@@ -427,14 +683,14 @@
 		// Allowed rotation values
 		$degs = array(90, 180, 270, 'vrt', 'hor');
 
-		if ($this->rotation_angle == '' OR ! in_array($this->rotation_angle, $degs))
+		if ($this->rotation_angle === '' OR ! in_array($this->rotation_angle, $degs))
 		{
 			$this->set_error('imglib_rotation_angle_required');
 			return FALSE;
 		}
 
 		// Reassign the width and height
-		if ($this->rotation_angle == 90 OR $this->rotation_angle == 270)
+		if ($this->rotation_angle === 90 OR $this->rotation_angle === 270)
 		{
 			$this->width	= $this->orig_height;
 			$this->height	= $this->orig_width;
@@ -445,22 +701,16 @@
 			$this->height	= $this->orig_height;
 		}
 
-
 		// Choose resizing function
-		if ($this->image_library == 'imagemagick' OR $this->image_library == 'netpbm')
+		if ($this->image_library === 'imagemagick' OR $this->image_library === 'netpbm')
 		{
 			$protocol = 'image_process_'.$this->image_library;
 			return $this->$protocol('rotate');
 		}
 
-		if ($this->rotation_angle == 'hor' OR $this->rotation_angle == 'vrt')
-		{
-			return $this->image_mirror_gd();
-		}
-		else
-		{
-			return $this->image_rotate_gd();
-		}
+		return ($this->rotation_angle === 'hor' OR $this->rotation_angle === 'vrt')
+			? $this->image_mirror_gd()
+			: $this->image_rotate_gd();
 	}
 
 	// --------------------------------------------------------------------
@@ -479,9 +729,9 @@
 
 		// If the target width/height match the source, AND if the new file name is not equal to the old file name
 		// we'll simply make a copy of the original with the new name... assuming dynamic rendering is off.
-		if ($this->dynamic_output === FALSE AND $this->orig_width == $this->width AND $this->orig_height == $this->height)
+		if ($this->dynamic_output === FALSE && $this->orig_width === $this->width && $this->orig_height === $this->height)
 		{
-			if ($this->source_image != $this->new_image AND @copy($this->full_src_path, $this->full_dst_path))
+			if ($this->source_image !== $this->new_image && @copy($this->full_src_path, $this->full_dst_path))
 			{
 				@chmod($this->full_dst_path, FILE_WRITE_MODE);
 			}
@@ -490,9 +740,9 @@
 		}
 
 		// Let's set up our values based on the action
-		if ($action == 'crop')
+		if ($action === 'crop')
 		{
-			//  Reassign the source width/height if cropping
+			// Reassign the source width/height if cropping
 			$this->orig_width  = $this->width;
 			$this->orig_height = $this->height;
 
@@ -500,7 +750,7 @@
 			if ($this->gd_version() !== FALSE)
 			{
 				$gd_version = str_replace('0', '', $this->gd_version());
-				$v2_override = ($gd_version == 2) ? TRUE : FALSE;
+				$v2_override = ($gd_version === 2);
 			}
 		}
 		else
@@ -516,14 +766,15 @@
 			return FALSE;
 		}
 
-		//  Create The Image
-		//
-		//  old conditional which users report cause problems with shared GD libs who report themselves as "2.0 or greater"
-		//  it appears that this is no longer the issue that it was in 2004, so we've removed it, retaining it in the comment
-		//  below should that ever prove inaccurate.
-		//
-		//  if ($this->image_library == 'gd2' AND function_exists('imagecreatetruecolor') AND $v2_override == FALSE)
-		if ($this->image_library == 'gd2' AND function_exists('imagecreatetruecolor'))
+		/* Create the image
+		 *
+		 * Old conditional which users report cause problems with shared GD libs who report themselves as "2.0 or greater"
+		 * it appears that this is no longer the issue that it was in 2004, so we've removed it, retaining it in the comment
+		 * below should that ever prove inaccurate.
+		 *
+		 * if ($this->image_library === 'gd2' && function_exists('imagecreatetruecolor') && $v2_override === FALSE)
+		 */
+		if ($this->image_library === 'gd2' && function_exists('imagecreatetruecolor'))
 		{
 			$create	= 'imagecreatetruecolor';
 			$copy	= 'imagecopyresampled';
@@ -536,7 +787,7 @@
 
 		$dst_img = $create($this->width, $this->height);
 
-		if ($this->image_type == 3) // png we can actually preserve transparency
+		if ($this->image_type === 3) // png we can actually preserve transparency
 		{
 			imagealphablending($dst_img, FALSE);
 			imagesavealpha($dst_img, TRUE);
@@ -544,21 +795,17 @@
 
 		$copy($dst_img, $src_img, 0, 0, $this->x_axis, $this->y_axis, $this->width, $this->height, $this->orig_width, $this->orig_height);
 
-		//  Show the image
-		if ($this->dynamic_output == TRUE)
+		// Show the image
+		if ($this->dynamic_output === TRUE)
 		{
 			$this->image_display_gd($dst_img);
 		}
-		else
+		elseif ( ! $this->image_save_gd($dst_img)) // Or save it
 		{
-			// Or save it
-			if ( ! $this->image_save_gd($dst_img))
-			{
-				return FALSE;
-			}
+			return FALSE;
 		}
 
-		//  Kill the file handles
+		// Kill the file handles
 		imagedestroy($dst_img);
 		imagedestroy($src_img);
 
@@ -581,48 +828,40 @@
 	public function image_process_imagemagick($action = 'resize')
 	{
 		//  Do we have a vaild library path?
-		if ($this->library_path == '')
+		if ($this->library_path === '')
 		{
 			$this->set_error('imglib_libpath_invalid');
 			return FALSE;
 		}
 
-		if ( ! preg_match("/convert$/i", $this->library_path))
+		if ( ! preg_match('/convert$/i', $this->library_path))
 		{
 			$this->library_path = rtrim($this->library_path, '/').'/convert';
 		}
 
 		// Execute the command
-		$cmd = $this->library_path." -quality ".$this->quality;
+		$cmd = $this->library_path.' -quality '.$this->quality;
 
-		if ($action == 'crop')
+		if ($action === 'crop')
 		{
-			$cmd .= " -crop ".$this->width."x".$this->height."+".$this->x_axis."+".$this->y_axis." \"$this->full_src_path\" \"$this->full_dst_path\" 2>&1";
+			$cmd .= ' -crop '.$this->width.'x'.$this->height.'+'.$this->x_axis.'+'.$this->y_axis.' "'.$this->full_src_path.'" "'.$this->full_dst_path .'" 2>&1';
 		}
-		elseif ($action == 'rotate')
+		elseif ($action === 'rotate')
 		{
-			switch ($this->rotation_angle)
-			{
-				case 'hor'	: $angle = '-flop';
-					break;
-				case 'vrt'	: $angle = '-flip';
-					break;
-				default		: $angle = '-rotate '.$this->rotation_angle;
-					break;
-			}
+			$angle = ($this->rotation_angle === 'hor' OR $this->rotation_angle === 'vrt')
+					? '-flop' : '-rotate '.$this->rotation_angle;
 
-			$cmd .= " ".$angle." \"$this->full_src_path\" \"$this->full_dst_path\" 2>&1";
+			$cmd .= ' '.$angle.' "'.$this->full_src_path.'" "'.$this->full_dst_path.'" 2>&1';
 		}
-		else  // Resize
+		else // Resize
 		{
-			$cmd .= " -resize ".$this->width."x".$this->height." \"$this->full_src_path\" \"$this->full_dst_path\" 2>&1";
+			$cmd .= ' -resize '.$this->width.'x'.$this->height.' "'.$this->full_src_path.'" "'.$this->full_dst_path.'" 2>&1';
 		}
 
 		$retval = 1;
-
 		@exec($cmd, $output, $retval);
 
-		//	Did it work?
+		// Did it work?
 		if ($retval > 0)
 		{
 			$this->set_error('imglib_image_process_failed');
@@ -647,46 +886,46 @@
 	 */
 	public function image_process_netpbm($action = 'resize')
 	{
-		if ($this->library_path == '')
+		if ($this->library_path === '')
 		{
 			$this->set_error('imglib_libpath_invalid');
 			return FALSE;
 		}
 
-		//  Build the resizing command
+		// Build the resizing command
 		switch ($this->image_type)
 		{
 			case 1 :
-						$cmd_in		= 'giftopnm';
-						$cmd_out	= 'ppmtogif';
+				$cmd_in		= 'giftopnm';
+				$cmd_out	= 'ppmtogif';
 				break;
 			case 2 :
-						$cmd_in		= 'jpegtopnm';
-						$cmd_out	= 'ppmtojpeg';
+				$cmd_in		= 'jpegtopnm';
+				$cmd_out	= 'ppmtojpeg';
 				break;
 			case 3 :
-						$cmd_in		= 'pngtopnm';
-						$cmd_out	= 'ppmtopng';
+				$cmd_in		= 'pngtopnm';
+				$cmd_out	= 'ppmtopng';
 				break;
 		}
 
-		if ($action == 'crop')
+		if ($action === 'crop')
 		{
 			$cmd_inner = 'pnmcut -left '.$this->x_axis.' -top '.$this->y_axis.' -width '.$this->width.' -height '.$this->height;
 		}
-		elseif ($action == 'rotate')
+		elseif ($action === 'rotate')
 		{
 			switch ($this->rotation_angle)
 			{
-				case 90		:	$angle = 'r270';
+				case 90:	$angle = 'r270';
 					break;
-				case 180	:	$angle = 'r180';
+				case 180:	$angle = 'r180';
 					break;
-				case 270	:	$angle = 'r90';
+				case 270:	$angle = 'r90';
 					break;
-				case 'vrt'	:	$angle = 'tb';
+				case 'vrt':	$angle = 'tb';
 					break;
-				case 'hor'	:	$angle = 'lr';
+				case 'hor':	$angle = 'lr';
 					break;
 			}
 
@@ -700,10 +939,9 @@
 		$cmd = $this->library_path.$cmd_in.' '.$this->full_src_path.' | '.$cmd_inner.' | '.$cmd_out.' > '.$this->dest_folder.'netpbm.tmp';
 
 		$retval = 1;
-
 		@exec($cmd, $output, $retval);
 
-		//  Did it work?
+		// Did it work?
 		if ($retval > 0)
 		{
 			$this->set_error('imglib_image_process_failed');
@@ -714,7 +952,7 @@
 		// If you try manipulating the original it fails so
 		// we have to rename the temp file.
 		copy ($this->dest_folder.'netpbm.tmp', $this->full_dst_path);
-		unlink ($this->dest_folder.'netpbm.tmp');
+		unlink($this->dest_folder.'netpbm.tmp');
 		@chmod($this->full_dst_path, FILE_WRITE_MODE);
 
 		return TRUE;
@@ -729,7 +967,7 @@
 	 */
 	public function image_rotate_gd()
 	{
-		//  Create the image handle
+		// Create the image handle
 		if ( ! ($src_img = $this->image_create_gd()))
 		{
 			return FALSE;
@@ -742,29 +980,24 @@
 
 		$white	= imagecolorallocate($src_img, 255, 255, 255);
 
-		//  Rotate it!
+		// Rotate it!
 		$dst_img = imagerotate($src_img, $this->rotation_angle, $white);
 
-		//  Save the Image
-		if ($this->dynamic_output == TRUE)
+		// Show the image
+		if ($this->dynamic_output === TRUE)
 		{
 			$this->image_display_gd($dst_img);
 		}
-		else
+		elseif ( ! $this->image_save_gd($dst_img)) // ... or save it
 		{
-			// Or save it
-			if ( ! $this->image_save_gd($dst_img))
-			{
-				return FALSE;
-			}
+			return FALSE;
 		}
 
-		//  Kill the file handles
+		// Kill the file handles
 		imagedestroy($dst_img);
 		imagedestroy($src_img);
 
 		// Set the file to 777
-
 		@chmod($this->full_dst_path, FILE_WRITE_MODE);
 
 		return TRUE;
@@ -789,7 +1022,7 @@
 		$width  = $this->orig_width;
 		$height = $this->orig_height;
 
-		if ($this->rotation_angle == 'hor')
+		if ($this->rotation_angle === 'hor')
 		{
 			for ($i = 0; $i < $height; $i++, $left = 0, $right = $width-1)
 			{
@@ -824,21 +1057,17 @@
 			}
 		}
 
-		//  Show the image
-		if ($this->dynamic_output == TRUE)
+		// Show the image
+		if ($this->dynamic_output === TRUE)
 		{
 			$this->image_display_gd($src_img);
 		}
-		else
+		elseif ( ! $this->image_save_gd($src_img)) // ... or save it
 		{
-			// Or save it
-			if ( ! $this->image_save_gd($src_img))
-			{
-				return FALSE;
-			}
+			return FALSE;
 		}
 
-		//  Kill the file handles
+		// Kill the file handles
 		imagedestroy($src_img);
 
 		// Set the file to 777
@@ -855,19 +1084,11 @@
 	 * This is a wrapper function that chooses the type
 	 * of watermarking based on the specified preference.
 	 *
-	 * @param	string
 	 * @return	bool
 	 */
 	public function watermark()
 	{
-		if ($this->wm_type == 'overlay')
-		{
-			return $this->overlay_watermark();
-		}
-		else
-		{
-			return $this->text_watermark();
-		}
+		return ($this->wm_type === 'overlay') ? $this->overlay_watermark() : $this->text_watermark();
 	}
 
 	// --------------------------------------------------------------------
@@ -885,63 +1106,61 @@
 			return FALSE;
 		}
 
-		//  Fetch source image properties
+		// Fetch source image properties
 		$this->get_image_properties();
 
-		//  Fetch watermark image properties
-		$props			= $this->get_image_properties($this->wm_overlay_path, TRUE);
+		// Fetch watermark image properties
+		$props		= $this->get_image_properties($this->wm_overlay_path, TRUE);
 		$wm_img_type	= $props['image_type'];
-		$wm_width		= $props['width'];
-		$wm_height		= $props['height'];
+		$wm_width	= $props['width'];
+		$wm_height	= $props['height'];
 
-		//  Create two image resources
+		// Create two image resources
 		$wm_img  = $this->image_create_gd($this->wm_overlay_path, $wm_img_type);
 		$src_img = $this->image_create_gd($this->full_src_path);
 
 		// Reverse the offset if necessary
 		// When the image is positioned at the bottom
 		// we don't want the vertical offset to push it
-		// further down.  We want the reverse, so we'll
-		// invert the offset.  Same with the horizontal
+		// further down. We want the reverse, so we'll
+		// invert the offset. Same with the horizontal
 		// offset when the image is at the right
 
-		$this->wm_vrt_alignment = strtoupper(substr($this->wm_vrt_alignment, 0, 1));
-		$this->wm_hor_alignment = strtoupper(substr($this->wm_hor_alignment, 0, 1));
+		$this->wm_vrt_alignment = strtoupper($this->wm_vrt_alignment[0]);
+		$this->wm_hor_alignment = strtoupper($this->wm_hor_alignment[0]);
 
-		if ($this->wm_vrt_alignment == 'B')
+		if ($this->wm_vrt_alignment === 'B')
 			$this->wm_vrt_offset = $this->wm_vrt_offset * -1;
 
-		if ($this->wm_hor_alignment == 'R')
+		if ($this->wm_hor_alignment === 'R')
 			$this->wm_hor_offset = $this->wm_hor_offset * -1;
 
-		//  Set the base x and y axis values
+		// Set the base x and y axis values
 		$x_axis = $this->wm_hor_offset + $this->wm_padding;
 		$y_axis = $this->wm_vrt_offset + $this->wm_padding;
 
-		//  Set the vertical position
-		switch ($this->wm_vrt_alignment)
+		// Set the vertical position
+		if ($this->wm_vrt_alignment === 'M')
 		{
-			case 'T':
-				break;
-			case 'M':	$y_axis += ($this->orig_height / 2) - ($wm_height / 2);
-				break;
-			case 'B':	$y_axis += $this->orig_height - $wm_height;
-				break;
+			$y_axis += ($this->orig_height / 2) - ($wm_height / 2);
+		}
+		elseif ($this->wm_vrt_alignment === 'B')
+		{
+			$y_axis += $this->orig_height - $wm_height;
 		}
 
-		//  Set the horizontal position
-		switch ($this->wm_hor_alignment)
+		// Set the horizontal position
+		if ($this->wm_hor_alignment === 'C')
 		{
-			case 'L':
-				break;
-			case 'C':	$x_axis += ($this->orig_width / 2) - ($wm_width / 2);
-				break;
-			case 'R':	$x_axis += $this->orig_width - $wm_width;
-				break;
+			$x_axis += ($this->orig_width / 2) - ($wm_width / 2);
+		}
+		elseif ($this->wm_hor_alignment === 'R')
+		{
+			$x_axis += $this->orig_width - $wm_width;
 		}
 
 		//  Build the finalized image
-		if ($wm_img_type == 3 AND function_exists('imagealphablending'))
+		if ($wm_img_type === 3 && function_exists('imagealphablending'))
 		{
 			@imagealphablending($src_img, TRUE);
 		}
@@ -963,12 +1182,12 @@
 			imagecopymerge($src_img, $wm_img, $x_axis, $y_axis, 0, 0, $wm_width, $wm_height, $this->wm_opacity);
 		}
 
-		//  Output the image
-		if ($this->dynamic_output == TRUE)
+		// Output the image
+		if ($this->dynamic_output === TRUE)
 		{
 			$this->image_display_gd($src_img);
 		}
-		elseif ( ! $this->image_save_gd($src_img))
+		elseif ( ! $this->image_save_gd($src_img)) // ... or save it
 		{
 			return FALSE;
 		}
@@ -993,34 +1212,34 @@
 			return FALSE;
 		}
 
-		if ($this->wm_use_truetype == TRUE AND ! file_exists($this->wm_font_path))
+		if ($this->wm_use_truetype === TRUE && ! file_exists($this->wm_font_path))
 		{
 			$this->set_error('imglib_missing_font');
 			return FALSE;
 		}
 
-		//  Fetch source image properties
+		// Fetch source image properties
 		$this->get_image_properties();
 
 		// Reverse the vertical offset
 		// When the image is positioned at the bottom
 		// we don't want the vertical offset to push it
-		// further down.  We want the reverse, so we'll
-		// invert the offset.  Note: The horizontal
+		// further down. We want the reverse, so we'll
+		// invert the offset. Note: The horizontal
 		// offset flips itself automatically
 
-		if ($this->wm_vrt_alignment == 'B')
+		if ($this->wm_vrt_alignment === 'B')
 			$this->wm_vrt_offset = $this->wm_vrt_offset * -1;
 
-		if ($this->wm_hor_alignment == 'R')
+		if ($this->wm_hor_alignment === 'R')
 			$this->wm_hor_offset = $this->wm_hor_offset * -1;
 
 		// Set font width and height
 		// These are calculated differently depending on
 		// whether we are using the true type font or not
-		if ($this->wm_use_truetype == TRUE)
+		if ($this->wm_use_truetype === TRUE)
 		{
-			if ($this->wm_font_size == '')
+			if ($this->wm_font_size === '')
 			{
 				$this->wm_font_size = 17;
 			}
@@ -1039,49 +1258,39 @@
 		$x_axis = $this->wm_hor_offset + $this->wm_padding;
 		$y_axis = $this->wm_vrt_offset + $this->wm_padding;
 
-		// Set verticle alignment
-		if ($this->wm_use_drop_shadow == FALSE)
+		if ($this->wm_use_drop_shadow === FALSE)
 			$this->wm_shadow_distance = 0;
 
 		$this->wm_vrt_alignment = strtoupper(substr($this->wm_vrt_alignment, 0, 1));
 		$this->wm_hor_alignment = strtoupper(substr($this->wm_hor_alignment, 0, 1));
 
-		switch ($this->wm_vrt_alignment)
+		// Set verticle alignment
+		if ($this->wm_vrt_alignment === 'M')
 		{
-			case 'T':
-				break;
-			case 'M':	$y_axis += ($this->orig_height/2)+($fontheight/2);
-				break;
-			case 'B':	$y_axis += ($this->orig_height - $fontheight - $this->wm_shadow_distance - ($fontheight/2));
-				break;
+			$y_axis += ($this->orig_height / 2) + ($fontheight / 2);
+		}
+		elseif ($this->wm_vrt_alignment === 'B')
+		{
+			$y_axis += $this->orig_height - $fontheight - $this->wm_shadow_distance - ($fontheight / 2);
 		}
 
 		$x_shad = $x_axis + $this->wm_shadow_distance;
 		$y_shad = $y_axis + $this->wm_shadow_distance;
 
-		// Set horizontal alignment
-		switch ($this->wm_hor_alignment)
-		{
-			case 'L':
-				break;
-			case 'R':
-				if ($this->wm_use_drop_shadow)
-				{
-					$x_shad += ($this->orig_width - $fontwidth*strlen($this->wm_text));
-					$x_axis += ($this->orig_width - $fontwidth*strlen($this->wm_text));
-				}
-				break;
-			case 'C':
-				if ($this->wm_use_drop_shadow)
-				{
-					$x_shad += floor(($this->orig_width - $fontwidth*strlen($this->wm_text))/2);
-					$x_axis += floor(($this->orig_width - $fontwidth*strlen($this->wm_text))/2);
-				}
-				break;
-		}
-
 		if ($this->wm_use_drop_shadow)
 		{
+			// Set horizontal alignment
+			if ($this->wm_hor_alignment === 'R')
+			{
+				$x_shad += $this->orig_width - ($fontwidth * strlen($this->wm_text));
+				$x_axis += $this->orig_width - ($fontwidth * strlen($this->wm_text));
+			}
+			elseif ($this->wm_hor_alignment === 'C')
+			{
+				$x_shad += floor(($this->orig_width - ($fontwidth * strlen($this->wm_text))) / 2);
+				$x_axis += floor(($this->orig_width - ($fontwidth * strlen($this->wm_text))) / 2);
+			}
+
 			/* Set RGB values for text and shadow
 			 *
 			 * First character is #, so we don't really need it.
@@ -1093,7 +1302,7 @@
 			$drp_color = str_split(substr($this->wm_shadow_color, 1, 6), 2);
 			$drp_color = imagecolorclosest($src_img, hexdec($drp_color[0]), hexdec($drp_color[1]), hexdec($drp_color[2]));
 
-			//  Add the text to the source image
+			// Add the text to the source image
 			if ($this->wm_use_truetype)
 			{
 				imagettftext($src_img, $this->wm_font_size, 0, $x_shad, $y_shad, $drp_color, $this->wm_font_path, $this->wm_text);
@@ -1106,8 +1315,8 @@
 			}
 		}
 
-		//  Output the final image
-		if ($this->dynamic_output == TRUE)
+		// Output the final image
+		if ($this->dynamic_output === TRUE)
 		{
 			$this->image_display_gd($src_img);
 		}
@@ -1130,14 +1339,15 @@
 	 * based on the type of image being processed
 	 *
 	 * @param	string
+	 * @param	string
 	 * @return	resource
 	 */
 	public function image_create_gd($path = '', $image_type = '')
 	{
-		if ($path == '')
+		if ($path === '')
 			$path = $this->full_src_path;
 
-		if ($image_type == '')
+		if ($image_type === '')
 			$image_type = $this->image_type;
 
 
@@ -1192,49 +1402,49 @@
 	{
 		switch ($this->image_type)
 		{
-			case 1 :
-						if ( ! function_exists('imagegif'))
-						{
-							$this->set_error(array('imglib_unsupported_imagecreate', 'imglib_gif_not_supported'));
-							return FALSE;
-						}
+			case 1:
+				if ( ! function_exists('imagegif'))
+				{
+					$this->set_error(array('imglib_unsupported_imagecreate', 'imglib_gif_not_supported'));
+					return FALSE;
+				}
 
-						if ( ! @imagegif($resource, $this->full_dst_path))
-						{
-							$this->set_error('imglib_save_failed');
-							return FALSE;
-						}
-				break;
-			case 2	:
-						if ( ! function_exists('imagejpeg'))
-						{
-							$this->set_error(array('imglib_unsupported_imagecreate', 'imglib_jpg_not_supported'));
-							return FALSE;
-						}
+				if ( ! @imagegif($resource, $this->full_dst_path))
+				{
+					$this->set_error('imglib_save_failed');
+					return FALSE;
+				}
+			break;
+			case 2:
+				if ( ! function_exists('imagejpeg'))
+				{
+					$this->set_error(array('imglib_unsupported_imagecreate', 'imglib_jpg_not_supported'));
+					return FALSE;
+				}
 
-						if ( ! @imagejpeg($resource, $this->full_dst_path, $this->quality))
-						{
-							$this->set_error('imglib_save_failed');
-							return FALSE;
-						}
-				break;
-			case 3	:
-						if ( ! function_exists('imagepng'))
-						{
-							$this->set_error(array('imglib_unsupported_imagecreate', 'imglib_png_not_supported'));
-							return FALSE;
-						}
+				if ( ! @imagejpeg($resource, $this->full_dst_path, $this->quality))
+				{
+					$this->set_error('imglib_save_failed');
+					return FALSE;
+				}
+			break;
+			case 3:
+				if ( ! function_exists('imagepng'))
+				{
+					$this->set_error(array('imglib_unsupported_imagecreate', 'imglib_png_not_supported'));
+					return FALSE;
+				}
 
-						if ( ! @imagepng($resource, $this->full_dst_path))
-						{
-							$this->set_error('imglib_save_failed');
-							return FALSE;
-						}
-				break;
-			default		:
-							$this->set_error(array('imglib_unsupported_imagecreate'));
-							return FALSE;
-				break;
+				if ( ! @imagepng($resource, $this->full_dst_path))
+				{
+					$this->set_error('imglib_save_failed');
+					return FALSE;
+				}
+			break;
+			default:
+				$this->set_error(array('imglib_unsupported_imagecreate'));
+				return FALSE;
+			break;
 		}
 
 		return TRUE;
@@ -1250,20 +1460,20 @@
 	 */
 	public function image_display_gd($resource)
 	{
-		header("Content-Disposition: filename={$this->source_image};");
-		header("Content-Type: {$this->mime_type}");
+		header('Content-Disposition: filename='.$this->source_image.';');
+		header('Content-Type: '.$this->mime_type);
 		header('Content-Transfer-Encoding: binary');
 		header('Last-Modified: '.gmdate('D, d M Y H:i:s', time()).' GMT');
 
 		switch ($this->image_type)
 		{
-			case 1		:	imagegif($resource);
+			case 1	:	imagegif($resource);
 				break;
-			case 2		:	imagejpeg($resource, '', $this->quality);
+			case 2	:	imagejpeg($resource, '', $this->quality);
 				break;
-			case 3		:	imagepng($resource);
+			case 3	:	imagepng($resource);
 				break;
-			default		:	echo 'Unable to display the image';
+			default:	echo 'Unable to display the image';
 				break;
 		}
 	}
@@ -1284,33 +1494,43 @@
 	 */
 	public function image_reproportion()
 	{
-		if ( ! is_numeric($this->width) OR ! is_numeric($this->height) OR $this->width == 0 OR $this->height == 0)
-			return;
-
-		if ( ! is_numeric($this->orig_width) OR ! is_numeric($this->orig_height) OR $this->orig_width == 0 OR $this->orig_height == 0)
-			return;
-
-		$new_width	= ceil($this->orig_width*$this->height/$this->orig_height);
-		$new_height	= ceil($this->width*$this->orig_height/$this->orig_width);
-
-		$ratio = (($this->orig_height/$this->orig_width) - ($this->height/$this->width));
-
-		if ($this->master_dim != 'width' AND $this->master_dim != 'height')
+		if (($this->width === 0 && $this->height === 0) OR $this->orig_width === 0 OR $this->orig_height === 0
+			OR ( ! preg_match('/^[0-9]+$/', $this->width) && ! preg_match('/^[0-9]+$/', $this->height))
+			OR ! preg_match('/^[0-9]+$/', $this->orig_width) OR ! preg_match('/^[0-9]+$/', $this->orig_height))
 		{
-			$this->master_dim = ($ratio < 0) ? 'width' : 'height';
+			return;
 		}
 
-		if (($this->width != $new_width) AND ($this->height != $new_height))
+		// Sanitize so we don't call preg_match() anymore
+		$this->width = (int) $this->width;
+		$this->height = (int) $this->height;
+
+		if ($this->master_dim !== 'width' && $this->master_dim !== 'height')
 		{
-			if ($this->master_dim == 'height')
+			if ($this->width > 0 && $this->height > 0)
 			{
-				$this->width = $new_width;
+				$this->master_dim = ((($this->orig_height/$this->orig_width) - ($this->height/$this->width)) < 0)
+							? 'width' : 'height';
 			}
 			else
 			{
-				$this->height = $new_height;
+				$this->master_dim = ($this->height === 0) ? 'width' : 'height';
 			}
 		}
+		elseif (($this->master_dim === 'width' && $this->width === 0)
+			OR ($this->master_dim === 'height' && $this->height === 0))
+		{
+			return;
+		}
+
+		if ($this->master_dim === 'width')
+		{
+			$this->height = (int) ceil($this->width*$this->orig_height/$this->orig_width);
+		}
+		else
+		{
+			$this->width = (int) ceil($this->orig_width*$this->height/$this->orig_height);
+		}
 	}
 
 	// --------------------------------------------------------------------
@@ -1321,6 +1541,7 @@
 	 * A helper function that gets info about the file
 	 *
 	 * @param	string
+	 * @param	bool
 	 * @return	mixed
 	 */
 	public function get_image_properties($path = '', $return = FALSE)
@@ -1328,8 +1549,10 @@
 		// For now we require GD but we should
 		// find a way to determine this using IM or NetPBM
 
-		if ($path == '')
+		if ($path === '')
+		{
 			$path = $this->full_src_path;
+		}
 
 		if ( ! file_exists($path))
 		{
@@ -1341,7 +1564,7 @@
 		$types = array(1 => 'gif', 2 => 'jpeg', 3 => 'png');
 		$mime = (isset($types[$vals[2]])) ? 'image/'.$types[$vals[2]] : 'image/jpg';
 
-		if ($return == TRUE)
+		if ($return === TRUE)
 		{
 			return array(
 					'width' =>	$vals[0],
@@ -1367,15 +1590,15 @@
 	 * Size calculator
 	 *
 	 * This function takes a known width x height and
-	 * recalculates it to a new size.  Only one
+	 * recalculates it to a new size. Only one
 	 * new variable needs to be known
 	 *
 	 *	$props = array(
-	 *					'width'			=> $width,
-	 *					'height'		=> $height,
-	 *					'new_width'		=> 40,
-	 *					'new_height'	=> ''
-	 *				  );
+	 *			'width'		=> $width,
+	 *			'height'	=> $height,
+	 *			'new_width'	=> 40,
+	 *			'new_height'	=> ''
+	 *		);
 	 *
 	 * @param	array
 	 * @return	array
@@ -1391,20 +1614,22 @@
 
 		foreach ($allowed as $item)
 		{
-			if ( ! isset($vals[$item]) OR $vals[$item] == '')
+			if (empty($vals[$item]))
+			{
 				$vals[$item] = 0;
+			}
 		}
 
-		if ($vals['width'] == 0 OR $vals['height'] == 0)
+		if ($vals['width'] === 0 OR $vals['height'] === 0)
 		{
 			return $vals;
 		}
 
-		if ($vals['new_width'] == 0)
+		if ($vals['new_width'] === 0)
 		{
 			$vals['new_width'] = ceil($vals['width']*$vals['new_height']/$vals['height']);
 		}
-		elseif ($vals['new_height'] == 0)
+		elseif ($vals['new_height'] === 0)
 		{
 			$vals['new_height'] = ceil($vals['new_width']*$vals['height']/$vals['width']);
 		}
@@ -1419,7 +1644,7 @@
 	 *
 	 * This is a helper function that extracts the extension
 	 * from the source_image.  This function lets us deal with
-	 * source_images with multiple periods, like:  my.cool.jpg
+	 * source_images with multiple periods, like: my.cool.jpg
 	 * It returns an associative array with two elements:
 	 * $array['ext']  = '.jpg';
 	 * $array['name'] = 'my.cool';
@@ -1449,7 +1674,7 @@
 			/* As it is stated in the PHP manual, dl() is not always available
 			 * and even if so - it could generate an E_WARNING message on failure
 			 */
-			return (function_exists('dl') AND @dl('gd.so'));
+			return (function_exists('dl') && @dl('gd.so'));
 		}
 
 		return TRUE;
@@ -1467,9 +1692,7 @@
 		if (function_exists('gd_info'))
 		{
 			$gd_version = @gd_info();
-			$gd_version = preg_replace("/\D/", "", $gd_version['GD Version']);
-
-			return $gd_version;
+			return preg_replace('/\D/', '', $gd_version['GD Version']);
 		}
 
 		return FALSE;
@@ -1492,15 +1715,14 @@
 		{
 			foreach ($msg as $val)
 			{
-
-				$msg = ($CI->lang->line($val) == FALSE) ? $val : $CI->lang->line($val);
+				$msg = ($CI->lang->line($val) === FALSE) ? $val : $CI->lang->line($val);
 				$this->error_msg[] = $msg;
 				log_message('error', $msg);
 			}
 		}
 		else
 		{
-			$msg = ($CI->lang->line($msg) == FALSE) ? $msg : $CI->lang->line($msg);
+			$msg = ($CI->lang->line($msg) === FALSE) ? $msg : $CI->lang->line($msg);
 			$this->error_msg[] = $msg;
 			log_message('error', $msg);
 		}
@@ -1512,15 +1734,15 @@
 	 * Show error messages
 	 *
 	 * @param	string
+	 * @param	string
 	 * @return	string
 	 */
 	public function display_errors($open = '<p>', $close = '</p>')
 	{
-		return (count($this->error_msg) > 0) ? $open . implode($close . $open, $this->error_msg) . $close : '';
+		return (count($this->error_msg) > 0) ? $open.implode($close.$open, $this->error_msg).$close : '';
 	}
 
 }
-// END Image_lib Class
 
 /* End of file Image_lib.php */
-/* Location: ./system/libraries/Image_lib.php */
+/* Location: ./system/libraries/Image_lib.php */
\ No newline at end of file
diff --git a/system/libraries/Javascript.php b/system/libraries/Javascript.php
index 33df600..98fec61 100644
--- a/system/libraries/Javascript.php
+++ b/system/libraries/Javascript.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * Javascript Class
  *
@@ -46,7 +44,7 @@
 
 		foreach ($defaults as $key => $val)
 		{
-			if (isset($params[$key]) && $params[$key] !== "")
+			if (isset($params[$key]) && $params[$key] !== '')
 			{
 				$defaults[$key] = $params[$key];
 			}
@@ -61,7 +59,7 @@
 		// make js to refer to current library
 		$this->js =& $this->CI->$js_library_driver;
 
-		log_message('debug', "Javascript Class Initialized and loaded.  Driver used: $js_library_driver");
+		log_message('debug', 'Javascript Class Initialized and loaded. Driver used: '.$js_library_driver);
 	}
 
 	// --------------------------------------------------------------------
@@ -107,7 +105,7 @@
 	 *
 	 * @param	string	The element to attach the event to
 	 * @param	string	The code to execute
-	 * @param	boolean	whether or not to return false
+	 * @param	bool	whether or not to return false
 	 * @return	string
 	 */
 	public function click($element = 'this', $js = '', $ret_false = TRUE)
@@ -375,7 +373,6 @@
 	// Effects
 	// --------------------------------------------------------------------
 
-
 	/**
 	 * Add Class
 	 *
@@ -618,12 +615,9 @@
 		{
 			$this->_javascript_location = $external_file;
 		}
-		else
+		elseif ($this->CI->config->item('javascript_location') !== '')
 		{
-			if ($this->CI->config->item('javascript_location') != '')
-			{
-				$this->_javascript_location = $this->CI->config->item('javascript_location');
-			}
+			$this->_javascript_location = $this->CI->config->item('javascript_location');
 		}
 
 		if ($relative === TRUE OR strncmp($external_file, 'http://', 7) === 0 OR strncmp($external_file, 'https://', 8) === 0)
@@ -650,13 +644,13 @@
 	 * Outputs a <script> tag
 	 *
 	 * @param	string	The element to attach the event to
-	 * @param	boolean	If a CDATA section should be added
+	 * @param	bool	If a CDATA section should be added
 	 * @return	string
 	 */
 	public function inline($script, $cdata = TRUE)
 	{
 		return $this->_open_script()
-			. ($cdata ? "\n// <![CDATA[\n{$script}\n// ]]>\n" : "\n{$script}\n")
+			. ($cdata ? "\n// <![CDATA[\n".$script."\n// ]]>\n" : "\n".$script."\n")
 			. $this->_close_script();
 	}
 
@@ -673,7 +667,7 @@
 	protected function _open_script($src = '')
 	{
 		return '<script type="text/javascript" charset="'.strtolower($this->CI->config->item('charset')).'"'
-			. ($src == '' ? '>' : ' src="'.$src.'">');
+			.($src === '' ? '>' : ' src="'.$src.'">');
 	}
 
 	// --------------------------------------------------------------------
@@ -688,15 +682,12 @@
 	 */
 	protected function _close_script($extra = "\n")
 	{
-		return "</script>$extra";
+		return '</script>'.$extra;
 	}
 
-
-	// --------------------------------------------------------------------
 	// --------------------------------------------------------------------
 	// AJAX-Y STUFF - still a testbed
 	// --------------------------------------------------------------------
-	// --------------------------------------------------------------------
 
 	/**
 	 * Update
@@ -732,7 +723,7 @@
 		{
 			if (is_object($result))
 			{
-				$json_result = $result->result_array();
+				$json_result = is_callable(array($result, 'result_array')) ? $result->result_array() : (array) $result;
 			}
 			elseif (is_array($result))
 			{
@@ -751,9 +742,9 @@
 		$json = array();
 		$_is_assoc = TRUE;
 
-		if ( ! is_array($json_result) AND empty($json_result))
+		if ( ! is_array($json_result) && empty($json_result))
 		{
-			show_error("Generate JSON Failed - Illegal key, value pair.");
+			show_error('Generate JSON Failed - Illegal key, value pair.');
 		}
 		elseif ($match_array_type)
 		{
@@ -774,7 +765,7 @@
 
 		$json = implode(',', $json);
 
-		return $_is_assoc ? "{".$json."}" : "[".$json."]";
+		return $_is_assoc ? '{'.$json.'}' : '['.$json.']';
 
 	}
 
@@ -785,8 +776,8 @@
 	 *
 	 * Checks for an associative array
 	 *
-	 * @param	type
-	 * @return	type
+	 * @param	array
+	 * @return	bool
 	 */
 	protected function _is_associative_array($arr)
 	{
@@ -808,8 +799,8 @@
 	 *
 	 * Ensures a standard json value and escapes values
 	 *
-	 * @param	type
-	 * @return	type
+	 * @param	mixed
+	 * @return	string
 	 */
 	protected function _prep_args($result, $is_key = FALSE)
 	{
@@ -831,9 +822,7 @@
 		}
 	}
 
-	// --------------------------------------------------------------------
 }
-// END Javascript Class
 
 /* End of file Javascript.php */
-/* Location: ./system/libraries/Javascript.php */
+/* Location: ./system/libraries/Javascript.php */
\ No newline at end of file
diff --git a/system/libraries/Log.php b/system/libraries/Log.php
index 944173f..baac801 100644
--- a/system/libraries/Log.php
+++ b/system/libraries/Log.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * Logging Class
  *
@@ -38,22 +36,65 @@
  */
 class CI_Log {
 
+	/**
+	 * Path to save log files
+	 *
+	 * @var string
+	 */
 	protected $_log_path;
-	protected $_threshold		= 1;
-	protected $_threshold_max	= 0;
-	protected $_threshold_array	= array();
-	protected $_date_fmt		= 'Y-m-d H:i:s';
-	protected $_enabled			= TRUE;
-	protected $_levels			= array('ERROR' => 1, 'DEBUG' => 2,  'INFO' => 3, 'ALL' => 4);
 
 	/**
-	 * Constructor
+	 * Level of logging
+	 *
+	 * @var int
+	 */
+	protected $_threshold		= 1;
+
+	/**
+	 * Highest level of logging
+	 *
+	 * @var int
+	 */
+	protected $_threshold_max	= 0;
+
+	/**
+	 * Array of threshold levels to log
+	 *
+	 * @var array
+	 */
+	protected $_threshold_array	= array();
+
+	/**
+	 * Format of timestamp for log files
+	 *
+	 * @var string
+	 */
+	protected $_date_fmt		= 'Y-m-d H:i:s';
+
+	/**
+	 * Whether or not the logger can write to the log files
+	 *
+	 * @var bool
+	 */
+	protected $_enabled		= TRUE;
+
+	/**
+	 * Predefined logging levels
+	 *
+	 * @var array
+	 */
+	protected $_levels		= array('ERROR' => 1, 'DEBUG' => 2,  'INFO' => 3, 'ALL' => 4);
+
+	/**
+	 * Initialize Logging class
+	 *
+	 * @return	void
 	 */
 	public function __construct()
 	{
 		$config =& get_config();
 
-		$this->_log_path = ($config['log_path'] != '') ? $config['log_path'] : APPPATH.'logs/';
+		$this->_log_path = ($config['log_path'] !== '') ? $config['log_path'] : APPPATH.'logs/';
 
 		if ( ! is_dir($this->_log_path) OR ! is_really_writable($this->_log_path))
 		{
@@ -70,7 +111,7 @@
 			$this->_threshold_array = array_flip($config['log_threshold']);
 		}
 
-		if ($config['log_date_format'] != '')
+		if ($config['log_date_format'] !== '')
 		{
 			$this->_date_fmt = $config['log_date_format'];
 		}
@@ -98,7 +139,7 @@
 		$level = strtoupper($level);
 
 		if (( ! isset($this->_levels[$level]) OR ($this->_levels[$level] > $this->_threshold))
-			AND ! isset($this->_threshold_array[$this->_levels[$level]]))
+			&& ! isset($this->_threshold_array[$this->_levels[$level]]))
 		{
 			return FALSE;
 		}
@@ -110,7 +151,7 @@
 		if ( ! file_exists($filepath))
 		{
 			$newfile = TRUE;
-			$message .= "<"."?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); ?".">\n\n";
+			$message .= '<'."?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); ?".">\n\n";
 		}
 
 		if ( ! $fp = @fopen($filepath, FOPEN_WRITE_CREATE))
@@ -118,22 +159,22 @@
 			return FALSE;
 		}
 
-		$message .= $level.' '.(($level == 'INFO') ? ' -' : '-').' '.date($this->_date_fmt). ' --> '.$msg."\n";
+		$message .= $level.' '.($level === 'INFO' ? ' -' : '-').' '.date($this->_date_fmt).' --> '.$msg."\n";
 
 		flock($fp, LOCK_EX);
 		fwrite($fp, $message);
 		flock($fp, LOCK_UN);
 		fclose($fp);
 
-		if (isset($newfile) AND $newfile === TRUE)
+		if (isset($newfile) && $newfile === TRUE)
 		{
 			@chmod($filepath, FILE_WRITE_MODE);
 		}
+
 		return TRUE;
 	}
 
 }
-// END Log Class
 
 /* End of file Log.php */
-/* Location: ./system/libraries/Log.php */
+/* Location: ./system/libraries/Log.php */
\ No newline at end of file
diff --git a/system/libraries/Migration.php b/system/libraries/Migration.php
index d070972..4391b23 100644
--- a/system/libraries/Migration.php
+++ b/system/libraries/Migration.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * Migration Class
  *
@@ -41,14 +39,54 @@
  */
 class CI_Migration {
 
+	/**
+	 * Whether the library is enabled
+	 *
+	 * @var bool
+	 */
 	protected $_migration_enabled = FALSE;
+
+	/**
+	 * Path to migration classes
+	 *
+	 * @var string
+	 */
 	protected $_migration_path = NULL;
+
+	/**
+	 * Current migration version
+	 *
+	 * @var mixed
+	 */
 	protected $_migration_version = 0;
+
+	/**
+	 * Database table with migration info
+	 *
+	 * @var string
+	 */
 	protected $_migration_table = 'migrations';
+
+	/**
+	 * Whether to automatically run migrations
+	 *
+	 * @var bool
+	 */
 	protected $_migration_auto_latest = FALSE;
 
+	/**
+	 * Error message
+	 *
+	 * @var string
+	 */
 	protected $_error_string = '';
 
+	/**
+	 * Initialize Migration Class
+	 *
+	 * @param	array
+	 * @return	void
+	 */
 	public function __construct($config = array())
 	{
 		# Only run this constructor on main library load
@@ -59,7 +97,7 @@
 
 		foreach ($config as $key => $val)
 		{
-			$this->{'_' . $key} = $val;
+			$this->{'_'.$key} = $val;
 		}
 
 		log_message('debug', 'Migrations class initialized');
@@ -71,7 +109,7 @@
 		}
 
 		// If not set, set it
-		$this->_migration_path == '' AND $this->_migration_path = APPPATH.'migrations/';
+		$this->_migration_path !== '' OR $this->_migration_path = APPPATH.'migrations/';
 
 		// Add trailing slash if not set
 		$this->_migration_path = rtrim($this->_migration_path, '/').'/';
@@ -101,7 +139,7 @@
 		}
 
 		// Do we auto migrate to the latest migration?
-		if ($this->_migration_auto_latest === TRUE AND ! $this->latest())
+		if ($this->_migration_auto_latest === TRUE && ! $this->latest())
 		{
 			show_error($this->error_string());
 		}
@@ -115,8 +153,7 @@
 	 * Calls each migration step required to get to the schema version of
 	 * choice
 	 *
-	 * @access	public
-	 * @param $version integer	Target schema version
+	 * @param	int	Target schema version
 	 * @return	mixed	TRUE if already latest, FALSE if failed, int if upgraded
 	 */
 	public function version($target_version)
@@ -142,7 +179,7 @@
 
 		// We now prepare to actually DO the migrations
 		// But first let's make sure that everything is the way it should be
-		for ($i = $start; $i != $stop; $i += $step)
+		for ($i = $start; $i !== $stop; $i += $step)
 		{
 			$f = glob(sprintf($this->_migration_path.'%03d_*.php', $i));
 
@@ -241,7 +278,6 @@
 	/**
 	 * Set's the schema to the latest migration
 	 *
-	 * @access	public
 	 * @return	mixed	true if already latest, false if failed, int if upgraded
 	 */
 	public function latest()
@@ -264,7 +300,6 @@
 	/**
 	 * Set's the schema to the migration version set in config
 	 *
-	 * @access	public
 	 * @return	mixed	true if already current, false if failed, int if upgraded
 	 */
 	public function current()
@@ -277,7 +312,6 @@
 	/**
 	 * Error string
 	 *
-	 * @access	public
 	 * @return	string	Error message returned as a string
 	 */
 	public function error_string()
@@ -290,7 +324,6 @@
 	/**
 	 * Set's the schema to the latest migration
 	 *
-	 * @access	protected
 	 * @return	mixed	true if already latest, false if failed, int if upgraded
 	 */
 	protected function find_migrations()
@@ -308,7 +341,6 @@
 		}
 
 		sort($files);
-
 		return $files;
 	}
 
@@ -317,8 +349,7 @@
 	/**
 	 * Retrieves current schema version
 	 *
-	 * @access	protected
-	 * @return	integer	Current Migration
+	 * @return	int	Current Migration
 	 */
 	protected function _get_version()
 	{
@@ -331,9 +362,8 @@
 	/**
 	 * Stores the current schema version
 	 *
-	 * @access	protected
-	 * @param $migrations integer	Migration reached
-	 * @return	void					Outputs a report of the migration
+	 * @param	int	Migration reached
+	 * @return	void	Outputs a report of the migration
 	 */
 	protected function _update_version($migrations)
 	{
@@ -347,15 +377,15 @@
 	/**
 	 * Enable the use of CI super-global
 	 *
-	 * @access	public
-	 * @param $var
+	 * @param	$var
 	 * @return	mixed
 	 */
 	public function __get($var)
 	{
 		return get_instance()->$var;
 	}
+
 }
 
 /* End of file Migration.php */
-/* Location: ./system/libraries/Migration.php */
+/* Location: ./system/libraries/Migration.php */
\ No newline at end of file
diff --git a/system/libraries/Pagination.php b/system/libraries/Pagination.php
index 35ac541..a91159c 100644
--- a/system/libraries/Pagination.php
+++ b/system/libraries/Pagination.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * Pagination Class
  *
@@ -74,13 +72,13 @@
 	/**
 	 * Constructor
 	 *
-	 * @access	public
 	 * @param	array	initialization parameters
+	 * @return	void
 	 */
 	public function __construct($params = array())
 	{
 		$this->initialize($params);
-		log_message('debug', "Pagination Class Initialized");
+		log_message('debug', 'Pagination Class Initialized');
 	}
 
 	// --------------------------------------------------------------------
@@ -88,7 +86,6 @@
 	/**
 	 * Initialize Preferences
 	 *
-	 * @access	public
 	 * @param	array	initialization parameters
 	 * @return	void
 	 */
@@ -98,17 +95,16 @@
 		{
 			foreach ($params as $key => $val)
 			{
-				if (isset($this->$key))
+				if ($key === 'anchor_class')
+				{
+					$this->anchor_class = ($val !== '') ? 'class="'.$val.'" ' : '';
+				}
+				elseif (isset($this->$key))
 				{
 					$this->$key = $val;
 				}
 			}
 		}
-
-		if ($this->anchor_class != '')
-		{
-			$this->anchor_class = 'class="'.$this->anchor_class.'" ';
-		}
 	}
 
 	// --------------------------------------------------------------------
@@ -116,13 +112,12 @@
 	/**
 	 * Generate the pagination links
 	 *
-	 * @access	public
 	 * @return	string
 	 */
 	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)
+		if ($this->total_rows === 0 OR $this->per_page === 0)
 		{
 			return '';
 		}
@@ -143,25 +138,25 @@
 		$CI =& get_instance();
 
 		// See if we are using a prefix or suffix on links
-		if ($this->prefix != '' OR $this->suffix != '')
+		if ($this->prefix !== '' OR $this->suffix !== '')
 		{
 			$this->cur_page = (int) str_replace(array($this->prefix, $this->suffix), '', $CI->uri->segment($this->uri_segment));
 		}
 
 		if ($CI->config->item('enable_query_strings') === TRUE OR $this->page_query_string === TRUE)
 		{
-			if ($CI->input->get($this->query_string_segment) != $base_page)
+			if ($CI->input->get($this->query_string_segment) !== $base_page)
 			{
 				$this->cur_page = (int) $CI->input->get($this->query_string_segment);
 			}
 		}
-		elseif ( ! $this->cur_page AND $CI->uri->segment($this->uri_segment) != $base_page)
+		elseif ( ! $this->cur_page && $CI->uri->segment($this->uri_segment) !== $base_page)
 		{
 			$this->cur_page = (int) $CI->uri->segment($this->uri_segment);
 		}
 
 		// Set current page to 1 if it's not valid or if using page numbers instead of offset
-		if ( ! is_numeric($this->cur_page) OR ($this->use_page_numbers AND $this->cur_page == 0))
+		if ( ! is_numeric($this->cur_page) OR ($this->use_page_numbers && $this->cur_page === 0))
 		{
 			$this->cur_page = $base_page;
 		}
@@ -182,12 +177,9 @@
 				$this->cur_page = $num_pages;
 			}
 		}
-		else
+		elseif ($this->cur_page > $this->total_rows)
 		{
-			if ($this->cur_page > $this->total_rows)
-			{
-				$this->cur_page = ($num_pages - 1) * $this->per_page;
-			}
+			$this->cur_page = ($num_pages - 1) * $this->per_page;
 		}
 
 		$uri_page_number = $this->cur_page;
@@ -199,10 +191,10 @@
 
 		// Calculate the start and end numbers. These determine
 		// which number to start and end the digit links with
-		$start = (($this->cur_page - $this->num_links) > 0) ? $this->cur_page - ($this->num_links - 1) : 1;
-		$end   = (($this->cur_page + $this->num_links) < $num_pages) ? $this->cur_page + $this->num_links : $num_pages;
+		$start	= (($this->cur_page - $this->num_links) > 0) ? $this->cur_page - ($this->num_links - 1) : 1;
+		$end	= (($this->cur_page + $this->num_links) < $num_pages) ? $this->cur_page + $this->num_links : $num_pages;
 
-		// Is pagination being used over GET or POST?  If get, add a per_page query
+		// Is pagination being used over GET or POST? If get, add a per_page query
 		// string. If post, add a trailing slash to the base URL if needed
 		if ($CI->config->item('enable_query_strings') === TRUE OR $this->page_query_string === TRUE)
 		{
@@ -217,24 +209,24 @@
 		$output = '';
 
 		// Render the "First" link
-		if  ($this->first_link !== FALSE AND $this->cur_page > ($this->num_links + 1))
+		if ($this->first_link !== FALSE && $this->cur_page > ($this->num_links + 1))
 		{
-			$first_url = ($this->first_url == '') ? $this->base_url : $this->first_url;
+			$first_url = ($this->first_url === '') ? $this->base_url : $this->first_url;
 			$output .= $this->first_tag_open.'<a '.$this->anchor_class.'href="'.$first_url.'">'.$this->first_link.'</a>'.$this->first_tag_close;
 		}
 
 		// Render the "previous" link
-		if  ($this->prev_link !== FALSE AND $this->cur_page != 1)
+		if  ($this->prev_link !== FALSE && $this->cur_page !== 1)
 		{
 			$i = ($this->use_page_numbers) ? $uri_page_number - 1 : $uri_page_number - $this->per_page;
 
-			if ($i == $base_page AND $this->first_url != '')
+			if ($i === $base_page && $this->first_url !== '')
 			{
 				$output .= $this->prev_tag_open.'<a '.$this->anchor_class.'href="'.$this->first_url.'">'.$this->prev_link.'</a>'.$this->prev_tag_close;
 			}
 			else
 			{
-				$i = ($i == $base_page) ? '' : $this->prefix.$i.$this->suffix;
+				$i = ($i === $base_page) ? '' : $this->prefix.$i.$this->suffix;
 				$output .= $this->prev_tag_open.'<a '.$this->anchor_class.'href="'.$this->base_url.$i.'">'.$this->prev_link.'</a>'.$this->prev_tag_close;
 			}
 
@@ -250,21 +242,21 @@
 
 				if ($i >= $base_page)
 				{
-					if ($this->cur_page == $loop)
+					if ($this->cur_page === $loop)
 					{
 						$output .= $this->cur_tag_open.$loop.$this->cur_tag_close; // Current page
 					}
 					else
 					{
-						$n = ($i == $base_page) ? '' : $i;
+						$n = ($i === $base_page) ? '' : $i;
 
-						if ($n == '' && $this->first_url != '')
+						if ($n === '' && $this->first_url !== '')
 						{
 							$output .= $this->num_tag_open.'<a '.$this->anchor_class.'href="'.$this->first_url.'">'.$loop.'</a>'.$this->num_tag_close;
 						}
 						else
 						{
-							$n = ($n == '') ? '' : $this->prefix.$n.$this->suffix;
+							$n = ($n === '') ? '' : $this->prefix.$n.$this->suffix;
 
 							$output .= $this->num_tag_open.'<a '.$this->anchor_class.'href="'.$this->base_url.$n.'">'.$loop.'</a>'.$this->num_tag_close;
 						}
@@ -274,7 +266,7 @@
 		}
 
 		// Render the "next" link
-		if ($this->next_link !== FALSE AND $this->cur_page < $num_pages)
+		if ($this->next_link !== FALSE && $this->cur_page < $num_pages)
 		{
 			$i = ($this->use_page_numbers) ? $this->cur_page + 1 : $this->cur_page * $this->per_page;
 
@@ -282,7 +274,7 @@
 		}
 
 		// Render the "Last" link
-		if ($this->last_link !== FALSE AND ($this->cur_page + $this->num_links) < $num_pages)
+		if ($this->last_link !== FALSE && ($this->cur_page + $this->num_links) < $num_pages)
 		{
 			$i = ($this->use_page_numbers) ? $num_pages : ($num_pages * $this->per_page) - $this->per_page;
 
@@ -291,15 +283,13 @@
 
 		// Kill double slashes. Note: Sometimes we can end up with a double slash
 		// in the penultimate link so we'll kill all double slashes.
-		$output = preg_replace("#([^:])//+#", "\\1/", $output);
+		$output = preg_replace('#([^:])//+#', '\\1/', $output);
 
 		// Add the wrapper HTML if exists
-		$output = $this->full_tag_open.$output.$this->full_tag_close;
-
-		return $output;
+		return $this->full_tag_open.$output.$this->full_tag_close;
 	}
+
 }
-// END Pagination Class
 
 /* End of file Pagination.php */
-/* Location: ./system/libraries/Pagination.php */
+/* Location: ./system/libraries/Pagination.php */
\ No newline at end of file
diff --git a/system/libraries/Parser.php b/system/libraries/Parser.php
index 3212482..b64c782 100644
--- a/system/libraries/Parser.php
+++ b/system/libraries/Parser.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * Parser Class
  *
@@ -38,18 +36,33 @@
  */
 class CI_Parser {
 
+	/**
+	 * Left delimeter character for psuedo vars
+	 *
+	 * @var string
+	 */
 	public $l_delim = '{';
-	public $r_delim = '}';
-	public $object;
-	private $CI;
 
 	/**
-	 *  Parse a template
+	 * Right delimeter character for psuedo vars
+	 *
+	 * @var string
+	 */
+	public $r_delim = '}';
+
+	/**
+	 * Reference to CodeIgniter instance
+	 *
+	 * @var object
+	 */
+	protected $CI;
+
+	/**
+	 * Parse a template
 	 *
 	 * Parses pseudo-variables contained in the specified template view,
 	 * replacing them with the data in the second param
 	 *
-	 * @access	public
 	 * @param	string
 	 * @param	array
 	 * @param	bool
@@ -66,12 +79,11 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 *  Parse a String
+	 * Parse a String
 	 *
 	 * Parses pseudo-variables contained in the specified string,
 	 * replacing them with the data in the second param
 	 *
-	 * @access	public
 	 * @param	string
 	 * @param	array
 	 * @param	bool
@@ -85,37 +97,31 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 *  Parse a template
+	 * Parse a template
 	 *
 	 * Parses pseudo-variables contained in the specified template,
 	 * replacing them with the data in the second param
 	 *
-	 * @access	private
 	 * @param	string
 	 * @param	array
 	 * @param	bool
 	 * @return	string
 	 */
-	private function _parse($template, $data, $return = FALSE)
+	protected function _parse($template, $data, $return = FALSE)
 	{
-		if ($template == '')
+		if ($template === '')
 		{
 			return FALSE;
 		}
 
 		foreach ($data as $key => $val)
 		{
-			if (is_array($val))
-			{
-				$template = $this->_parse_pair($key, $val, $template);
-			}
-			else
-			{
-				$template = $this->_parse_single($key, (string)$val, $template);
-			}
+			$template = is_array($val)
+					? $this->_parse_pair($key, $val, $template)
+					: $template = $this->_parse_single($key, (string) $val, $template);
 		}
 
-		if ($return == FALSE)
+		if ($return === FALSE)
 		{
 			$this->CI->output->append_output($template);
 		}
@@ -126,9 +132,8 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 *  Set the left/right variable delimiters
+	 * Set the left/right variable delimiters
 	 *
-	 * @access	public
 	 * @param	string
 	 * @param	string
 	 * @return	void
@@ -142,15 +147,14 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 *  Parse a single key/value
+	 * Parse a single key/value
 	 *
-	 * @access	private
 	 * @param	string
 	 * @param	string
 	 * @param	string
 	 * @return	string
 	 */
-	private function _parse_single($key, $val, $string)
+	protected function _parse_single($key, $val, $string)
 	{
 		return str_replace($this->l_delim.$key.$this->r_delim, (string) $val, $string);
 	}
@@ -158,17 +162,16 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 *  Parse a tag pair
+	 * Parse a tag pair
 	 *
-	 * Parses tag pairs:  {some_tag} string... {/some_tag}
+	 * Parses tag pairs: {some_tag} string... {/some_tag}
 	 *
-	 * @access	private
 	 * @param	string
 	 * @param	array
 	 * @param	string
 	 * @return	string
 	 */
-	private function _parse_pair($variable, $data, $string)
+	protected function _parse_pair($variable, $data, $string)
 	{
 		if (FALSE === ($match = $this->_match_pair($string, $variable)))
 		{
@@ -181,14 +184,9 @@
 			$temp = $match[1];
 			foreach ($row as $key => $val)
 			{
-				if ( ! is_array($val))
-				{
-					$temp = $this->_parse_single($key, $val, $temp);
-				}
-				else
-				{
-					$temp = $this->_parse_pair($key, $val, $temp);
-				}
+				$temp = is_array($val)
+						? $this->_parse_pair($key, $val, $temp)
+						: $this->_parse_single($key, $val, $temp);
 			}
 
 			$str .= $temp;
@@ -200,25 +198,20 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 *  Matches a variable pair
+	 * Matches a variable pair
 	 *
-	 * @access	private
 	 * @param	string
 	 * @param	string
 	 * @return	mixed
 	 */
-	private function _match_pair($string, $variable)
+	protected function _match_pair($string, $variable)
 	{
-		if ( ! 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 FALSE;
-		}
-
-		return $match;
+		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)
+			? $match : FALSE;
 	}
 
 }
-// END Parser Class
 
 /* End of file Parser.php */
-/* Location: ./system/libraries/Parser.php */
+/* Location: ./system/libraries/Parser.php */
\ No newline at end of file
diff --git a/system/libraries/Profiler.php b/system/libraries/Profiler.php
index 89c6165..d96088c 100644
--- a/system/libraries/Profiler.php
+++ b/system/libraries/Profiler.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * CodeIgniter Profiler Class
  *
@@ -44,25 +42,45 @@
  */
 class CI_Profiler {
 
+	/**
+	 * List of profiler sections available to show
+	 *
+	 * @var array
+	 */
 	protected $_available_sections = array(
-										'benchmarks',
-										'get',
-										'memory_usage',
-										'post',
-										'uri_string',
-										'controller_info',
-										'queries',
-										'http_headers',
-										'session_data',
-										'config'
-										);
+		'benchmarks',
+		'get',
+		'memory_usage',
+		'post',
+		'uri_string',
+		'controller_info',
+		'queries',
+		'http_headers',
+		'session_data',
+		'config'
+	);
 
+	/**
+	 * Number of queries to show before making the additional queries togglable
+	 *
+	 * @var int
+	 */
 	protected $_query_toggle_count = 25;
 
+	/**
+	 * Reference to the CodeIgniter singleton
+	 *
+	 * @var object
+	 */
 	protected $CI;
 
-	// --------------------------------------------------------------------
-
+	/**
+	 * Constructor
+	 *
+	 * Initialize Profiler
+	 *
+	 * @param array $config
+	 */
 	public function __construct($config = array())
 	{
 		$this->CI =& get_instance();
@@ -102,7 +120,7 @@
 		{
 			if (in_array($method, $this->_available_sections))
 			{
-				$this->_compile_{$method} = ($enable !== FALSE) ? TRUE : FALSE;
+				$this->_compile_{$method} = ($enable !== FALSE);
 			}
 		}
 	}
@@ -127,7 +145,7 @@
 			// We match the "end" marker so that the list ends
 			// up in the order that it was defined
 			if (preg_match('/(.+?)_end/i', $key, $match)
-				AND isset($this->CI->benchmark->marker[$match[1].'_end'], $this->CI->benchmark->marker[$match[1].'_start']))
+				&& isset($this->CI->benchmark->marker[$match[1].'_end'], $this->CI->benchmark->marker[$match[1].'_start']))
 			{
 				$profile[$match[1]] = $this->CI->benchmark->elapsed_time($match[1].'_start', $key);
 			}
@@ -135,18 +153,20 @@
 
 		// Build a table containing the profile data.
 		// Note: At some point we should turn this into a template that can
-		// be modified.  We also might want to make this data available to be logged
+		// be modified. We also might want to make this data available to be logged
 
 		$output = "\n\n"
-			. '<fieldset id="ci_profiler_benchmarks" style="border:1px solid #900;padding:6px 10px 10px 10px;margin:20px 0 20px 0;background-color:#eee">'
-			. "\n"
-			. '<legend style="color:#900;">&nbsp;&nbsp;'.$this->CI->lang->line('profiler_benchmarks').'&nbsp;&nbsp;</legend>'
-			. "\n\n\n<table style='width:100%'>\n";
+			.'<fieldset id="ci_profiler_benchmarks" style="border:1px solid #900;padding:6px 10px 10px 10px;margin:20px 0 20px 0;background-color:#eee;">'
+			."\n"
+			.'<legend style="color:#900;">&nbsp;&nbsp;'.$this->CI->lang->line('profiler_benchmarks')."&nbsp;&nbsp;</legend>"
+			."\n\n\n<table style=\"width:100%;\">\n";
 
 		foreach ($profile as $key => $val)
 		{
 			$key = ucwords(str_replace(array('_', '-'), ' ', $key));
-			$output .= "<tr><td style='padding:5px;width:50%;color:#000;font-weight:bold;background-color:#ddd;'>".$key."&nbsp;&nbsp;</td><td style='padding:5px;width:50%;color:#900;font-weight:normal;background-color:#ddd;'>".$val."</td></tr>\n";
+			$output .= '<tr><td style="padding:5px;width:50%;color:#000;font-weight:bold;background-color:#ddd;">'
+					.$key.'&nbsp;&nbsp;</td><td style="padding:5px;width:50%;color:#900;font-weight:normal;background-color:#ddd;">'
+					.$val."</td></tr>\n";
 		}
 
 		return $output."</table>\n</fieldset>";
@@ -166,7 +186,7 @@
 		// Let's determine which databases are currently connected to
 		foreach (get_object_vars($this->CI) as $CI_object)
 		{
-			if (is_object($CI_object) && is_subclass_of(get_class($CI_object), 'CI_DB') )
+			if (is_object($CI_object) && is_subclass_of(get_class($CI_object), 'CI_DB'))
 			{
 				$dbs[] = $CI_object;
 			}
@@ -175,13 +195,13 @@
 		if (count($dbs) === 0)
 		{
 			return "\n\n"
-				. '<fieldset id="ci_profiler_queries" style="border:1px solid #0000FF;padding:6px 10px 10px 10px;margin:20px 0 20px 0;background-color:#eee;">'
-				. "\n"
-				. '<legend style="color:#0000FF;">&nbsp;&nbsp;'.$this->CI->lang->line('profiler_queries').'&nbsp;&nbsp;</legend>'
-				. "\n\n\n<table style='border:none; width:100%;'>\n"
-				. '<tr><td style="width:100%;color:#0000FF;font-weight:normal;background-color:#eee;padding:5px;">'
-				. $this->CI->lang->line('profiler_no_db')
-				. "</td></tr>\n</table>\n</fieldset>";
+				.'<fieldset id="ci_profiler_queries" style="border:1px solid #0000FF;padding:6px 10px 10px 10px;margin:20px 0 20px 0;background-color:#eee;">'
+				."\n"
+				.'<legend style="color:#0000FF;">&nbsp;&nbsp;'.$this->CI->lang->line('profiler_queries').'&nbsp;&nbsp;</legend>'
+				."\n\n\n<table style=\"border:none; width:100%;\">\n"
+				.'<tr><td style="width:100%;color:#0000FF;font-weight:normal;background-color:#eee;padding:5px;">'
+				.$this->CI->lang->line('profiler_no_db')
+				."</td></tr>\n</table>\n</fieldset>";
 		}
 
 		// Load the text helper so we can highlight the SQL
@@ -191,7 +211,6 @@
 		$highlight = array('SELECT', 'DISTINCT', 'FROM', 'WHERE', 'AND', 'LEFT&nbsp;JOIN', 'ORDER&nbsp;BY', 'GROUP&nbsp;BY', 'LIMIT', 'INSERT', 'INTO', 'VALUES', 'UPDATE', 'OR&nbsp;', 'HAVING', 'OFFSET', 'NOT&nbsp;IN', 'IN', 'LIKE', 'NOT&nbsp;LIKE', 'COUNT', 'MAX', 'MIN', 'ON', 'AS', 'AVG', 'SUM', '(', ')');
 
 		$output  = "\n\n";
-
 		$count = 0;
 
 		foreach ($dbs as $db)
@@ -200,26 +219,28 @@
 
 			$show_hide_js = '(<span style="cursor: pointer;" onclick="var s=document.getElementById(\'ci_profiler_queries_db_'.$count.'\').style;s.display=s.display==\'none\'?\'\':\'none\';this.innerHTML=this.innerHTML==\''.$this->CI->lang->line('profiler_section_hide').'\'?\''.$this->CI->lang->line('profiler_section_show').'\':\''.$this->CI->lang->line('profiler_section_hide').'\';">'.$this->CI->lang->line('profiler_section_hide').'</span>)';
 
-			if ($hide_queries != '')
+			if ($hide_queries !== '')
 			{
 				$show_hide_js = '(<span style="cursor: pointer;" onclick="var s=document.getElementById(\'ci_profiler_queries_db_'.$count.'\').style;s.display=s.display==\'none\'?\'\':\'none\';this.innerHTML=this.innerHTML==\''.$this->CI->lang->line('profiler_section_show').'\'?\''.$this->CI->lang->line('profiler_section_hide').'\':\''.$this->CI->lang->line('profiler_section_show').'\';">'.$this->CI->lang->line('profiler_section_show').'</span>)';
 			}
 
-			$output .= '<fieldset style="border:1px solid #0000FF;padding:6px 10px 10px 10px;margin:20px 0 20px 0;background-color:#eee">'
-				. "\n"
-				. '<legend style="color:#0000FF;">&nbsp;&nbsp;'.$this->CI->lang->line('profiler_database').':&nbsp; '.$db->database.'&nbsp;&nbsp;&nbsp;'.$this->CI->lang->line('profiler_queries').': '.count($db->queries).'&nbsp;&nbsp;'.$show_hide_js.'</legend>'
-				. "\n\n\n<table style='width:100%;{$hide_queries}' id='ci_profiler_queries_db_{$count}'>\n";
+			$output .= '<fieldset style="border:1px solid #0000FF;padding:6px 10px 10px 10px;margin:20px 0 20px 0;background-color:#eee;">'
+				."\n"
+				.'<legend style="color:#0000FF;">&nbsp;&nbsp;'.$this->CI->lang->line('profiler_database')
+				.':&nbsp; '.$db->database.'&nbsp;&nbsp;&nbsp;'.$this->CI->lang->line('profiler_queries')
+				.': '.count($db->queries).'&nbsp;&nbsp;'.$show_hide_js."</legend>\n\n\n"
+				.'<table style="width:100%;'.$hide_queries.'" id="ci_profiler_queries_db_'.$count."\">\n";
 
 			if (count($db->queries) === 0)
 			{
-				$output .= "<tr><td style='width:100%;color:#0000FF;font-weight:normal;background-color:#eee;padding:5px;'>".$this->CI->lang->line('profiler_no_queries')."</td></tr>\n";
+				$output .= '<tr><td style="width:100%;color:#0000FF;font-weight:normal;background-color:#eee;padding:5px;">'
+						.$this->CI->lang->line('profiler_no_queries')."</td></tr>\n";
 			}
 			else
 			{
 				foreach ($db->queries as $key => $val)
 				{
 					$time = number_format($db->query_times[$key], 4);
-
 					$val = highlight_code($val, ENT_QUOTES);
 
 					foreach ($highlight as $bold)
@@ -227,18 +248,18 @@
 						$val = str_replace($bold, '<strong>'.$bold.'</strong>', $val);
 					}
 
-					$output .= "<tr><td style='padding:5px; vertical-align: top;width:1%;color:#900;font-weight:normal;background-color:#ddd;'>".$time."&nbsp;&nbsp;</td><td style='padding:5px; color:#000;font-weight:normal;background-color:#ddd;'>".$val."</td></tr>\n";
+					$output .= '<tr><td style="padding:5px;vertical-align:top;width:1%;color:#900;font-weight:normal;background-color:#ddd;">'
+							.$time.'&nbsp;&nbsp;</td><td style="padding:5px;color:#000;font-weight:normal;background-color:#ddd;">'
+							.$val."</td></tr>\n";
 				}
 			}
 
 			$output .= "</table>\n</fieldset>";
-
 		}
 
 		return $output;
 	}
 
-
 	// --------------------------------------------------------------------
 
 	/**
@@ -248,19 +269,18 @@
 	 */
 	protected function _compile_get()
 	{
-		$output  = "\n\n"
-			. '<fieldset id="ci_profiler_get" style="border:1px solid #cd6e00;padding:6px 10px 10px 10px;margin:20px 0 20px 0;background-color:#eee">'
-			. "\n"
-			. '<legend style="color:#cd6e00;">&nbsp;&nbsp;'.$this->CI->lang->line('profiler_get_data').'&nbsp;&nbsp;</legend>'
-			. "\n";
+		$output = "\n\n"
+			.'<fieldset id="ci_profiler_get" style="border:1px solid #cd6e00;padding:6px 10px 10px 10px;margin:20px 0 20px 0;background-color:#eee;">'
+			."\n"
+			.'<legend style="color:#cd6e00;">&nbsp;&nbsp;'.$this->CI->lang->line('profiler_get_data')."&nbsp;&nbsp;</legend>\n";
 
 		if (count($_GET) === 0)
 		{
-			$output .= "<div style='color:#cd6e00;font-weight:normal;padding:4px 0 4px 0'>".$this->CI->lang->line('profiler_no_get')."</div>";
+			$output .= '<div style="color:#cd6e00;font-weight:normal;padding:4px 0 4px 0;">'.$this->CI->lang->line('profiler_no_get').'</div>';
 		}
 		else
 		{
-			$output .= "\n\n<table style='width:100%; border:none'>\n";
+			$output .= "\n\n<table style=\"width:100%;border:none;\">\n";
 
 			foreach ($_GET as $key => $val)
 			{
@@ -269,9 +289,10 @@
 					$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;'>"
-					. (is_array($val) ? "<pre>" . htmlspecialchars(stripslashes(print_r($val, true))) . "</pre>" : htmlspecialchars(stripslashes($val)))
-					. "</td></tr>\n";
+				$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;">'
+					.((is_array($val) OR is_object($val)) ? '<pre>'.htmlspecialchars(stripslashes(print_r($val, TRUE))).'</pre>' : htmlspecialchars(stripslashes($val)))
+					."</td></tr>\n";
 			}
 
 			$output .= "</table>\n";
@@ -290,18 +311,17 @@
 	protected function _compile_post()
 	{
 		$output = "\n\n"
-			. '<fieldset id="ci_profiler_post" style="border:1px solid #009900;padding:6px 10px 10px 10px;margin:20px 0 20px 0;background-color:#eee">'
-			. "\n"
-			. '<legend style="color:#009900;">&nbsp;&nbsp;'.$this->CI->lang->line('profiler_post_data').'&nbsp;&nbsp;</legend>'
-			. "\n";
+			.'<fieldset id="ci_profiler_post" style="border:1px solid #009900;padding:6px 10px 10px 10px;margin:20px 0 20px 0;background-color:#eee;">'
+			."\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)
 		{
-			$output .= "<div style='color:#009900;font-weight:normal;padding:4px 0 4px 0'>".$this->CI->lang->line('profiler_no_post')."</div>";
+			$output .= '<div style="color:#009900;font-weight:normal;padding:4px 0 4px 0;">'.$this->CI->lang->line('profiler_no_post').'</div>';
 		}
 		else
 		{
-			$output .= "\n\n<table style='width:100%'>\n";
+			$output .= "\n\n<table style=\"width:100%;\">\n";
 
 			foreach ($_POST as $key => $val)
 			{
@@ -310,15 +330,18 @@
 					$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;'>";
-				if (is_array($val))
+				$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;">';
+
+				if (is_array($val) OR is_object($val))
 				{
-					$output .= "<pre>" . htmlspecialchars(stripslashes(print_r($val, TRUE))) . "</pre>";
+					$output .= '<pre>'.htmlspecialchars(stripslashes(print_r($val, TRUE))).'</pre>';
 				}
 				else
 				{
 					$output .= htmlspecialchars(stripslashes($val));
 				}
+
 				$output .= "</td></tr>\n";
 			}
 
@@ -338,12 +361,12 @@
 	protected function _compile_uri_string()
 	{
 		return "\n\n"
-			. '<fieldset id="ci_profiler_uri_string" style="border:1px solid #000;padding:6px 10px 10px 10px;margin:20px 0 20px 0;background-color:#eee">'
-			. "\n"
-			. '<legend style="color:#000;">&nbsp;&nbsp;'.$this->CI->lang->line('profiler_uri_string').'&nbsp;&nbsp;</legend>'
-			. "\n<div style='color:#000;font-weight:normal;padding:4px 0 4px 0'>"
-			. ($this->CI->uri->uri_string == '' ? $this->CI->lang->line('profiler_no_uri') : $this->CI->uri->uri_string)
-			. '</div></fieldset>';
+			.'<fieldset id="ci_profiler_uri_string" style="border:1px solid #000;padding:6px 10px 10px 10px;margin:20px 0 20px 0;background-color:#eee;">'
+			."\n"
+			.'<legend style="color:#000;">&nbsp;&nbsp;'.$this->CI->lang->line('profiler_uri_string')."&nbsp;&nbsp;</legend>\n"
+			.'<div style="color:#000;font-weight:normal;padding:4px 0 4px 0;">'
+			.($this->CI->uri->uri_string === '' ? $this->CI->lang->line('profiler_no_uri') : $this->CI->uri->uri_string)
+			.'</div></fieldset>';
 	}
 
 	// --------------------------------------------------------------------
@@ -356,11 +379,11 @@
 	protected function _compile_controller_info()
 	{
 		return "\n\n"
-			. '<fieldset id="ci_profiler_controller_info" style="border:1px solid #995300;padding:6px 10px 10px 10px;margin:20px 0 20px 0;background-color:#eee">'
-			. "\n"
-			. '<legend style="color:#995300;">&nbsp;&nbsp;'.$this->CI->lang->line('profiler_controller_info').'&nbsp;&nbsp;</legend>'
-			. "\n<div style='color:#995300;font-weight:normal;padding:4px 0 4px 0'>".$this->CI->router->fetch_class().'/'.$this->CI->router->fetch_method()
-			. '</div></fieldset>';
+			.'<fieldset id="ci_profiler_controller_info" style="border:1px solid #995300;padding:6px 10px 10px 10px;margin:20px 0 20px 0;background-color:#eee;">'
+			."\n"
+			.'<legend style="color:#995300;">&nbsp;&nbsp;'.$this->CI->lang->line('profiler_controller_info')."&nbsp;&nbsp;</legend>\n"
+			.'<div style="color:#995300;font-weight:normal;padding:4px 0 4px 0;">'.$this->CI->router->fetch_class().'/'.$this->CI->router->fetch_method()
+			.'</div></fieldset>';
 	}
 
 	// --------------------------------------------------------------------
@@ -375,12 +398,12 @@
 	protected function _compile_memory_usage()
 	{
 		return "\n\n"
-			. '<fieldset id="ci_profiler_memory_usage" style="border:1px solid #5a0099;padding:6px 10px 10px 10px;margin:20px 0 20px 0;background-color:#eee">'
-			. "\n"
-			. '<legend style="color:#5a0099;">&nbsp;&nbsp;'.$this->CI->lang->line('profiler_memory_usage').'&nbsp;&nbsp;</legend>'
-			. "\n<div style='color:#5a0099;font-weight:normal;padding:4px 0 4px 0'>"
-			. ((function_exists('memory_get_usage') && ($usage = memory_get_usage()) != '') ? number_format($usage).' bytes' : $this->CI->lang->line('profiler_no_memory'))
-			. '</div></fieldset>';
+			.'<fieldset id="ci_profiler_memory_usage" style="border:1px solid #5a0099;padding:6px 10px 10px 10px;margin:20px 0 20px 0;background-color:#eee;">'
+			."\n"
+			.'<legend style="color:#5a0099;">&nbsp;&nbsp;'.$this->CI->lang->line('profiler_memory_usage')."&nbsp;&nbsp;</legend>\n"
+			.'<div style="color:#5a0099;font-weight:normal;padding:4px 0 4px 0;">'
+			.(($usage = memory_get_usage()) != '' ? number_format($usage).' bytes' : $this->CI->lang->line('profiler_no_memory'))
+			.'</div></fieldset>';
 	}
 
 	// --------------------------------------------------------------------
@@ -395,15 +418,17 @@
 	protected function _compile_http_headers()
 	{
 		$output = "\n\n"
-			. '<fieldset id="ci_profiler_http_headers" style="border:1px solid #000;padding:6px 10px 10px 10px;margin:20px 0 20px 0;background-color:#eee">'
-			. "\n"
-			. '<legend style="color:#000;">&nbsp;&nbsp;'.$this->CI->lang->line('profiler_headers').'&nbsp;&nbsp;(<span style="cursor: pointer;" onclick="var s=document.getElementById(\'ci_profiler_httpheaders_table\').style;s.display=s.display==\'none\'?\'\':\'none\';this.innerHTML=this.innerHTML==\''.$this->CI->lang->line('profiler_section_show').'\'?\''.$this->CI->lang->line('profiler_section_hide').'\':\''.$this->CI->lang->line('profiler_section_show').'\';">'.$this->CI->lang->line('profiler_section_show').'</span>)</legend>'
-			. "\n\n\n<table style='width:100%;display:none' id='ci_profiler_httpheaders_table'>\n";
+			.'<fieldset id="ci_profiler_http_headers" style="border:1px solid #000;padding:6px 10px 10px 10px;margin:20px 0 20px 0;background-color:#eee;">'
+			."\n"
+			.'<legend style="color:#000;">&nbsp;&nbsp;'.$this->CI->lang->line('profiler_headers')
+			.'&nbsp;&nbsp;(<span style="cursor: pointer;" onclick="var s=document.getElementById(\'ci_profiler_httpheaders_table\').style;s.display=s.display==\'none\'?\'\':\'none\';this.innerHTML=this.innerHTML==\''.$this->CI->lang->line('profiler_section_show').'\'?\''.$this->CI->lang->line('profiler_section_hide').'\':\''.$this->CI->lang->line('profiler_section_show').'\';">'.$this->CI->lang->line('profiler_section_show')."</span>)</legend>\n\n\n"
+			.'<table style="width:100%;display:none;" id="ci_profiler_httpheaders_table">'."\n";
 
 		foreach (array('HTTP_ACCEPT', 'HTTP_USER_AGENT', 'HTTP_CONNECTION', 'SERVER_PORT', 'SERVER_NAME', 'REMOTE_ADDR', 'SERVER_SOFTWARE', 'HTTP_ACCEPT_LANGUAGE', 'SCRIPT_NAME', 'REQUEST_METHOD',' HTTP_HOST', 'REMOTE_HOST', 'CONTENT_TYPE', 'SERVER_PROTOCOL', 'QUERY_STRING', 'HTTP_ACCEPT_ENCODING', 'HTTP_X_FORWARDED_FOR') as $header)
 		{
-			$val = (isset($_SERVER[$header])) ? $_SERVER[$header] : '';
-			$output .= "<tr><td style='vertical-align: top;width:50%;padding:5px;color:#900;background-color:#ddd;'>".$header."&nbsp;&nbsp;</td><td style='width:50%;padding:5px;color:#000;background-color:#ddd;'>".$val."</td></tr>\n";
+			$val = isset($_SERVER[$header]) ? $_SERVER[$header] : '';
+			$output .= '<tr><td style="vertical-align:top;width:50%;padding:5px;color:#900;background-color:#ddd;">'
+				.$header.'&nbsp;&nbsp;</td><td style="width:50%;padding:5px;color:#000;background-color:#ddd;">'.$val."</td></tr>\n";
 		}
 
 		return $output."</table>\n</fieldset>";
@@ -421,19 +446,20 @@
 	protected function _compile_config()
 	{
 		$output = "\n\n"
-			. '<fieldset id="ci_profiler_config" style="border:1px solid #000;padding:6px 10px 10px 10px;margin:20px 0 20px 0;background-color:#eee">'
-			. "\n"
-			. '<legend style="color:#000;">&nbsp;&nbsp;'.$this->CI->lang->line('profiler_config').'&nbsp;&nbsp;(<span style="cursor: pointer;" onclick="var s=document.getElementById(\'ci_profiler_config_table\').style;s.display=s.display==\'none\'?\'\':\'none\';this.innerHTML=this.innerHTML==\''.$this->CI->lang->line('profiler_section_show').'\'?\''.$this->CI->lang->line('profiler_section_hide').'\':\''.$this->CI->lang->line('profiler_section_show').'\';">'.$this->CI->lang->line('profiler_section_show').'</span>)</legend>'
-			. "\n\n\n<table style='width:100%; display:none' id='ci_profiler_config_table'>\n";
+			.'<fieldset id="ci_profiler_config" style="border:1px solid #000;padding:6px 10px 10px 10px;margin:20px 0 20px 0;background-color:#eee;">'
+			."\n"
+			.'<legend style="color:#000;">&nbsp;&nbsp;'.$this->CI->lang->line('profiler_config').'&nbsp;&nbsp;(<span style="cursor: pointer;" onclick="var s=document.getElementById(\'ci_profiler_config_table\').style;s.display=s.display==\'none\'?\'\':\'none\';this.innerHTML=this.innerHTML==\''.$this->CI->lang->line('profiler_section_show').'\'?\''.$this->CI->lang->line('profiler_section_hide').'\':\''.$this->CI->lang->line('profiler_section_show').'\';">'.$this->CI->lang->line('profiler_section_show')."</span>)</legend>\n\n\n"
+			.'<table style="width:100%;display:none;" id="ci_profiler_config_table">'."\n";
 
-		foreach ($this->CI->config->config as $config=>$val)
+		foreach ($this->CI->config->config as $config => $val)
 		{
-			if (is_array($val))
+			if (is_array($val) OR is_object($val))
 			{
 				$val = print_r($val, TRUE);
 			}
 
-			$output .= "<tr><td style='padding:5px; vertical-align: top;color:#900;background-color:#ddd;'>".$config."&nbsp;&nbsp;</td><td style='padding:5px; color:#000;background-color:#ddd;'>".htmlspecialchars($val)."</td></tr>\n";
+			$output .= '<tr><td style="padding:5px;vertical-align:top;color:#900;background-color:#ddd;">'
+				.$config.'&nbsp;&nbsp;</td><td style="padding:5px;color:#000;background-color:#ddd;">'.htmlspecialchars($val)."</td></tr>\n";
 		}
 
 		return $output."</table>\n</fieldset>";
@@ -453,18 +479,19 @@
 			return;
 		}
 
-		$output = '<fieldset id="ci_profiler_csession" style="border:1px solid #000;padding:6px 10px 10px 10px;margin:20px 0 20px 0;background-color:#eee">'
-			. '<legend style="color:#000;">&nbsp;&nbsp;'.$this->CI->lang->line('profiler_session_data').'&nbsp;&nbsp;(<span style="cursor: pointer;" onclick="var s=document.getElementById(\'ci_profiler_session_data\').style;s.display=s.display==\'none\'?\'\':\'none\';this.innerHTML=this.innerHTML==\''.$this->CI->lang->line('profiler_section_show').'\'?\''.$this->CI->lang->line('profiler_section_hide').'\':\''.$this->CI->lang->line('profiler_section_show').'\';">'.$this->CI->lang->line('profiler_section_show').'</span>)</legend>'
-			. "<table style='width:100%;display:none' id='ci_profiler_session_data'>";
+		$output = '<fieldset id="ci_profiler_csession" style="border:1px solid #000;padding:6px 10px 10px 10px;margin:20px 0 20px 0;background-color:#eee;">'
+			.'<legend style="color:#000;">&nbsp;&nbsp;'.$this->CI->lang->line('profiler_session_data').'&nbsp;&nbsp;(<span style="cursor: pointer;" onclick="var s=document.getElementById(\'ci_profiler_session_data\').style;s.display=s.display==\'none\'?\'\':\'none\';this.innerHTML=this.innerHTML==\''.$this->CI->lang->line('profiler_section_show').'\'?\''.$this->CI->lang->line('profiler_section_hide').'\':\''.$this->CI->lang->line('profiler_section_show').'\';">'.$this->CI->lang->line('profiler_section_show').'</span>)</legend>'
+			.'<table style="width:100%;display:none;" id="ci_profiler_session_data">';
 
 		foreach ($this->CI->session->all_userdata() as $key => $val)
 		{
-			if (is_array($val) || is_object($val))
+			if (is_array($val) OR is_object($val))
 			{
 				$val = print_r($val, TRUE);
 			}
 
-			$output .= "<tr><td style='padding:5px; vertical-align: top;color:#900;background-color:#ddd;'>".$key."&nbsp;&nbsp;</td><td style='padding:5px; color:#000;background-color:#ddd;'>".htmlspecialchars($val)."</td></tr>\n";
+			$output .= '<tr><td style="padding:5px;vertical-align:top;color:#900;background-color:#ddd;">'
+				.$key.'&nbsp;&nbsp;</td><td style="padding:5px;color:#000;background-color:#ddd;">'.htmlspecialchars($val)."</td></tr>\n";
 		}
 
 		return $output."</table>\n</fieldset>";
@@ -479,14 +506,14 @@
 	 */
 	public function run()
 	{
-		$output = "<div id='codeigniter_profiler' style='clear:both;background-color:#fff;padding:10px;'>";
+		$output = '<div id="codeigniter_profiler" style="clear:both;background-color:#fff;padding:10px;">';
 		$fields_displayed = 0;
 
 		foreach ($this->_available_sections as $section)
 		{
 			if ($this->_compile_{$section} !== FALSE)
 			{
-				$func = "_compile_{$section}";
+				$func = '_compile_'.$section;
 				$output .= $this->{$func}();
 				$fields_displayed++;
 			}
@@ -494,14 +521,14 @@
 
 		if ($fields_displayed === 0)
 		{
-			$output .= '<p style="border:1px solid #5a0099;padding:10px;margin:20px 0;background-color:#eee">'.$this->CI->lang->line('profiler_no_profiles').'</p>';
+			$output .= '<p style="border:1px solid #5a0099;padding:10px;margin:20px 0;background-color:#eee;">'
+				.$this->CI->lang->line('profiler_no_profiles').'</p>';
 		}
 
 		return $output.'</div>';
 	}
+
 }
 
-// END CI_Profiler class
-
 /* End of file Profiler.php */
-/* Location: ./system/libraries/Profiler.php */
+/* Location: ./system/libraries/Profiler.php */
\ No newline at end of file
diff --git a/system/libraries/Session.php b/system/libraries/Session.php
index 66b39a6..7beedd9 100644
--- a/system/libraries/Session.php
+++ b/system/libraries/Session.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -36,25 +36,151 @@
  */
 class CI_Session {
 
+	/**
+	 * Whether to encrypt the session cookie
+	 *
+	 * @var bool
+	 */
 	public $sess_encrypt_cookie		= FALSE;
+
+	/**
+	 * Whether to use to the database for session storage
+	 *
+	 * @var bool
+	 */
 	public $sess_use_database		= FALSE;
+
+	/**
+	 * Name of the database table in which to store sessions
+	 *
+	 * @var string
+	 */
 	public $sess_table_name			= '';
+
+	/**
+	 * Length of time (in seconds) for sessions to expire
+	 *
+	 * @var int
+	 */
 	public $sess_expiration			= 7200;
+
+	/**
+	 * Whether to kill session on close of browser window
+	 *
+	 * @var bool
+	 */
 	public $sess_expire_on_close		= FALSE;
+
+	/**
+	 * Whether to match session on ip address
+	 *
+	 * @var bool
+	 */
 	public $sess_match_ip			= FALSE;
+
+	/**
+	 * Whether to match session on user-agent
+	 *
+	 * @var bool
+	 */
 	public $sess_match_useragent		= TRUE;
+
+	/**
+	 * Name of session cookie
+	 *
+	 * @var string
+	 */
 	public $sess_cookie_name		= 'ci_session';
+
+	/**
+	 * Session cookie prefix
+	 *
+	 * @var string
+	 */
 	public $cookie_prefix			= '';
+
+	/**
+	 * Session cookie path
+	 *
+	 * @var string
+	 */
 	public $cookie_path			= '';
+
+	/**
+	 * Session cookie domain
+	 *
+	 * @var string
+	 */
 	public $cookie_domain			= '';
+
+	/**
+	 * Whether to set the cookie only on HTTPS connections
+	 *
+	 * @var bool
+	 */
 	public $cookie_secure			= FALSE;
+
+	/**
+	 * Whether cookie should be allowed only to be sent by the server
+	 *
+	 * @var bool
+	 */
+	public $cookie_httponly 		= FALSE;
+
+	/**
+	 * Interval at which to update session
+	 *
+	 * @var int
+	 */
 	public $sess_time_to_update		= 300;
+
+	/**
+	 * Key with which to encrypt the session cookie
+	 *
+	 * @var string
+	 */
 	public $encryption_key			= '';
+
+	/**
+	 * String to indicate flash data cookies
+	 *
+	 * @var string
+	 */
 	public $flashdata_key			= 'flash';
+
+	/**
+	 * Function to use to get the current time
+	 *
+	 * @var string
+	 */
 	public $time_reference			= 'time';
+
+	/**
+	 * Probablity level of garbage collection of old sessions
+	 *
+	 * @var int
+	 */
 	public $gc_probability			= 5;
+
+	/**
+	 * Session data
+	 *
+	 * @var array
+	 */
 	public $userdata			= array();
+
+	/**
+	 * Reference to CodeIgniter instance
+	 *
+	 * @var object
+	 */
 	public $CI;
+
+	/**
+	 * Current time
+	 *
+	 * @var int
+	 */
 	public $now;
 
 	/**
@@ -62,6 +188,9 @@
 	 *
 	 * The constructor runs the session routines automatically
 	 * whenever the class is instantiated.
+	 *
+	 * @param	array
+	 * @return	void
 	 */
 	public function __construct($params = array())
 	{
@@ -72,12 +201,12 @@
 
 		// Set all the session preferences, which can either be set
 		// manually via the $params array above or via the config file
-		foreach (array('sess_encrypt_cookie', 'sess_use_database', 'sess_table_name', 'sess_expiration', 'sess_expire_on_close', 'sess_match_ip', 'sess_match_useragent', 'sess_cookie_name', 'cookie_path', 'cookie_domain', 'cookie_secure', 'sess_time_to_update', 'time_reference', 'cookie_prefix', 'encryption_key') as $key)
+		foreach (array('sess_encrypt_cookie', 'sess_use_database', 'sess_table_name', 'sess_expiration', 'sess_expire_on_close', 'sess_match_ip', 'sess_match_useragent', 'sess_cookie_name', 'cookie_path', 'cookie_domain', 'cookie_secure', 'cookie_httponly', 'sess_time_to_update', 'time_reference', 'cookie_prefix', 'encryption_key') as $key)
 		{
 			$this->$key = (isset($params[$key])) ? $params[$key] : $this->CI->config->item($key);
 		}
 
-		if ($this->encryption_key == '')
+		if ($this->encryption_key === '')
 		{
 			show_error('In order to use the Session class you are required to set an encryption key in your config file.');
 		}
@@ -86,13 +215,13 @@
 		$this->CI->load->helper('string');
 
 		// Do we need encryption? If so, load the encryption class
-		if ($this->sess_encrypt_cookie == TRUE)
+		if ($this->sess_encrypt_cookie === TRUE)
 		{
 			$this->CI->load->library('encrypt');
 		}
 
 		// Are we using a database? If so, load it
-		if ($this->sess_use_database === TRUE && $this->sess_table_name != '')
+		if ($this->sess_use_database === TRUE && $this->sess_table_name !== '')
 		{
 			$this->CI->load->database();
 		}
@@ -103,7 +232,7 @@
 
 		// Set the session length. If the session expiration is
 		// set to zero we'll set the expiration two years from now.
-		if ($this->sess_expiration == 0)
+		if ($this->sess_expiration === 0)
 		{
 			$this->sess_expiration = (60*60*24*365*2);
 		}
@@ -147,14 +276,14 @@
 		$session = $this->CI->input->cookie($this->sess_cookie_name);
 
 		// No cookie?  Goodbye cruel world!...
-		if ($session === FALSE)
+		if ($session === NULL)
 		{
 			log_message('debug', 'A session cookie was not found.');
 			return FALSE;
 		}
 
 		// Decrypt the cookie data
-		if ($this->sess_encrypt_cookie == TRUE)
+		if ($this->sess_encrypt_cookie === TRUE)
 		{
 			$session = $this->CI->encrypt->decode($session);
 		}
@@ -191,14 +320,14 @@
 		}
 
 		// Does the IP match?
-		if ($this->sess_match_ip == TRUE && $session['ip_address'] !== $this->CI->input->ip_address())
+		if ($this->sess_match_ip === TRUE && $session['ip_address'] !== $this->CI->input->ip_address())
 		{
 			$this->sess_destroy();
 			return FALSE;
 		}
 
 		// Does the User Agent Match?
-		if ($this->sess_match_useragent == TRUE && trim($session['user_agent']) !== trim(substr($this->CI->input->user_agent(), 0, 120)))
+		if ($this->sess_match_useragent === TRUE && trim($session['user_agent']) !== trim(substr($this->CI->input->user_agent(), 0, 120)))
 		{
 			$this->sess_destroy();
 			return FALSE;
@@ -209,17 +338,17 @@
 		{
 			$this->CI->db->where('session_id', $session['session_id']);
 
-			if ($this->sess_match_ip == TRUE)
+			if ($this->sess_match_ip === TRUE)
 			{
 				$this->CI->db->where('ip_address', $session['ip_address']);
 			}
 
-			if ($this->sess_match_useragent == TRUE)
+			if ($this->sess_match_useragent === TRUE)
 			{
 				$this->CI->db->where('user_agent', $session['user_agent']);
 			}
 
-			$query = $this->CI->db->get($this->sess_table_name);
+			$query = $this->CI->db->limit(1)->get($this->sess_table_name);
 
 			// No result? Kill it!
 			if ($query->num_rows() === 0)
@@ -230,7 +359,7 @@
 
 			// Is there custom data?  If so, add it to the main session array
 			$row = $query->row();
-			if (isset($row->user_data) && $row->user_data != '')
+			if ( ! empty($row->user_data))
 			{
 				$custom_data = $this->_unserialize($row->user_data);
 
@@ -442,6 +571,9 @@
 				$this->cookie_domain,
 				0
 			);
+
+		// Kill session data
+		$this->userdata = array();
 	}
 
 	// --------------------------------------------------------------------
@@ -454,7 +586,7 @@
 	 */
 	public function userdata($item)
 	{
-		return ( ! isset($this->userdata[$item])) ? FALSE : $this->userdata[$item];
+		return isset($this->userdata[$item]) ? $this->userdata[$item] : NULL;
 	}
 
 	// --------------------------------------------------------------------
@@ -469,6 +601,29 @@
 		return $this->userdata;
 	}
 
+	// --------------------------------------------------------------------------
+
+	/**
+	 * Fetch all flashdata
+	 *
+	 * @return	array
+	 */
+	public function all_flashdata()
+	{
+		$out = array();
+
+		// loop through all userdata
+		foreach ($this->all_userdata() as $key => $val)
+		{
+			// if it contains flashdata, add it
+			if (strpos($key, 'flash:old:') !== FALSE)
+			{
+				$out[$key] = $val;
+			}
+		}
+		return $out;
+	}
+
 	// --------------------------------------------------------------------
 
 	/**
@@ -501,6 +656,7 @@
 	/**
 	 * Delete a session variable from the "userdata" array
 	 *
+	 * @param	array
 	 * @return	void
 	 */
 	public function unset_userdata($newdata = array())
@@ -559,7 +715,7 @@
 	{
 		// 'old' flashdata gets removed. Here we mark all
 		// flashdata as 'new' to preserve it from _flashdata_sweep()
-		// Note the function will return FALSE if the $key
+		// Note the function will return NULL if the $key
 		// provided cannot be found
 		$value = $this->userdata($this->flashdata_key.':old:'.$key);
 
@@ -640,6 +796,7 @@
 	/**
 	 * Write the session cookie
 	 *
+	 * @param	mixed
 	 * @return	void
 	 */
 	protected function _set_cookie($cookie_data = NULL)
@@ -652,7 +809,7 @@
 		// Serialize the userdata for the cookie
 		$cookie_data = $this->_serialize($cookie_data);
 
-		if ($this->sess_encrypt_cookie == TRUE)
+		if ($this->sess_encrypt_cookie === TRUE)
 		{
 			$cookie_data = $this->CI->encrypt->encode($cookie_data);
 		}
@@ -666,13 +823,14 @@
 
 		// Set the cookie
 		setcookie(
-				$this->sess_cookie_name,
-				$cookie_data,
-				$expire,
-				$this->cookie_path,
-				$this->cookie_domain,
-				$this->cookie_secure
-			);
+			$this->sess_cookie_name,
+			$cookie_data,
+			$expire,
+			$this->cookie_path,
+			$this->cookie_domain,
+			$this->cookie_secure,
+			$this->cookie_httponly
+		);
 	}
 
 	// --------------------------------------------------------------------
@@ -729,7 +887,7 @@
 	 */
 	protected function _unserialize($data)
 	{
-		$data = @unserialize(strip_slashes($data));
+		$data = @unserialize(strip_slashes(trim($data)));
 
 		if (is_array($data))
 		{
@@ -737,9 +895,11 @@
 			return $data;
 		}
 
-		return (is_string($data)) ? str_replace('{{slash}}', '\\', $data) : $data;
+		return is_string($data) ? str_replace('{{slash}}', '\\', $data) : $data;
 	}
 
+	// --------------------------------------------------------------------
+
 	/**
 	 * Unescape slashes
 	 *
@@ -769,7 +929,7 @@
 	 */
 	protected function _sess_gc()
 	{
-		if ($this->sess_use_database != TRUE)
+		if ($this->sess_use_database !== TRUE)
 		{
 			return;
 		}
@@ -779,7 +939,7 @@
 		{
 			$expire = $this->now - $this->sess_expiration;
 
-			$this->CI->db->where("last_activity < {$expire}");
+			$this->CI->db->where('last_activity < '.$expire);
 			$this->CI->db->delete($this->sess_table_name);
 
 			log_message('debug', 'Session garbage collection performed.');
@@ -789,4 +949,4 @@
 }
 
 /* End of file Session.php */
-/* Location: ./system/libraries/Session.php */
+/* Location: ./system/libraries/Session.php */
\ No newline at end of file
diff --git a/system/libraries/Table.php b/system/libraries/Table.php
index fb154e5..0f8404d 100644
--- a/system/libraries/Table.php
+++ b/system/libraries/Table.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * HTML Table Generating Class
  *
@@ -40,18 +38,77 @@
  */
 class CI_Table {
 
-	public $rows			= array();
-	public $heading			= array();
-	public $auto_heading		= TRUE;
-	public $caption			= NULL;
-	public $template		= NULL;
-	public $newline			= "\n";
-	public $empty_cells		= '';
-	public $function		= FALSE;
+	/**
+	 * Data for table rows
+	 *
+	 * @var array
+	 */
+	public $rows		= array();
 
-	public function __construct()
+	/**
+	 * Data for table heading
+	 *
+	 * @var array
+	 */
+	public $heading		= array();
+
+	/**
+	 * Whether or not to automatically create the table header
+	 *
+	 * @var bool
+	 */
+	public $auto_heading	= TRUE;
+
+	/**
+	 * Table caption
+	 *
+	 * @var string
+	 */
+	public $caption		= NULL;
+
+	/**
+	 * Table layout template
+	 *
+	 * @var array
+	 */
+	public $template	= NULL;
+
+	/**
+	 * Newline setting
+	 *
+	 * @var string
+	 */
+	public $newline		= "\n";
+
+	/**
+	 * Contents of empty cells
+	 *
+	 * @var string
+	 */
+	public $empty_cells	= '';
+
+	/**
+	 * Callback for custom table layout
+	 *
+	 * @var function
+	 */
+	public $function	= FALSE;
+
+	/**
+	 * Set the template from the table config file if it exists
+	 *
+	 * @param	array	$config	(default: array())
+	 * @return	void
+	 */
+	public function __construct($config = array())
 	{
-		log_message('debug', "Table Class Initialized");
+		// initialize config
+		foreach ($config as $key => $val)
+		{
+			$this->template[$key] = $val;
+		}
+
+		log_message('debug', 'Table Class Initialized');
 	}
 
 	// --------------------------------------------------------------------
@@ -60,7 +117,7 @@
 	 * Set the template
 	 *
 	 * @param	array
-	 * @return	void
+	 * @return	bool
 	 */
 	public function set_template($template)
 	{
@@ -70,6 +127,7 @@
 		}
 
 		$this->template = $template;
+		return TRUE;
 	}
 
 	// --------------------------------------------------------------------
@@ -82,7 +140,7 @@
 	 * @param	mixed
 	 * @return	void
 	 */
-	public function set_heading()
+	public function set_heading($args = array())
 	{
 		$args = func_get_args();
 		$this->heading = $this->_prep_args($args);
@@ -91,9 +149,9 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 * Set columns.  Takes a one-dimensional array as input and creates
+	 * Set columns. Takes a one-dimensional array as input and creates
 	 * a multi-dimensional array with a depth equal to the number of
-	 * columns.  This allows a single array with many elements to  be
+	 * columns. This allows a single array with many elements to be
 	 * displayed in a table that has a fixed column count.
 	 *
 	 * @param	array
@@ -102,7 +160,7 @@
 	 */
 	public function make_columns($array = array(), $col_limit = 0)
 	{
-		if ( ! is_array($array) OR count($array) === 0)
+		if ( ! is_array($array) OR count($array) === 0 OR ! is_int($col_limit))
 		{
 			return FALSE;
 		}
@@ -111,7 +169,7 @@
 		// will want headings from a one-dimensional array
 		$this->auto_heading = FALSE;
 
-		if ($col_limit == 0)
+		if ($col_limit === 0)
 		{
 			return $array;
 		}
@@ -161,7 +219,7 @@
 	 * @param	mixed
 	 * @return	void
 	 */
-	public function add_row()
+	public function add_row($args = array())
 	{
 		$args = func_get_args();
 		$this->rows[] = $this->_prep_args($args);
@@ -174,29 +232,22 @@
 	 *
 	 * Ensures a standard associative array format for all cell data
 	 *
-	 * @param	type
-	 * @return	type
+	 * @param	array
+	 * @return	array
 	 */
 	protected function _prep_args($args)
 	{
 		// If there is no $args[0], skip this and treat as an associative array
 		// This can happen if there is only a single key, for example this is passed to table->generate
 		// array(array('foo'=>'bar'))
-		if (isset($args[0]) AND (count($args) === 1 && is_array($args[0])))
+		if (isset($args[0]) && count($args) === 1 && is_array($args[0]))
 		{
 			// args sent as indexed array
 			if ( ! isset($args[0]['data']))
 			{
 				foreach ($args[0] as $key => $val)
 				{
-					if (is_array($val) && isset($val['data']))
-					{
-						$args[$key] = $val;
-					}
-					else
-					{
-						$args[$key] = array('data' => $val);
-					}
+					$args[$key] = (is_array($val) && isset($val['data'])) ? $val : array('data' => $val);
 				}
 			}
 		}
@@ -247,13 +298,13 @@
 			}
 			elseif (is_array($table_data))
 			{
-				$set_heading = (count($this->heading) === 0 AND $this->auto_heading == FALSE) ? FALSE : TRUE;
+				$set_heading = (count($this->heading) !== 0 OR $this->auto_heading !== FALSE);
 				$this->_set_from_array($table_data, $set_heading);
 			}
 		}
 
-		// Is there anything to display?  No?  Smite them!
-		if (count($this->heading) === 0 AND count($this->rows) === 0)
+		// Is there anything to display? No? Smite them!
+		if (count($this->heading) === 0 && count($this->rows) === 0)
 		{
 			return 'Undefined table data';
 		}
@@ -285,9 +336,9 @@
 
 				foreach ($heading as $key => $val)
 				{
-					if ($key != 'data')
+					if ($key !== 'data')
 					{
-						$temp = str_replace('<th', "<th $key='$val'", $temp);
+						$temp = str_replace('<th', '<th '.$key.'="'.$val.'"', $temp);
 					}
 				}
 
@@ -311,7 +362,7 @@
 				}
 
 				// We use modulus to alternate the row colors
-				$name = (fmod($i++, 2)) ? '' : 'alt_';
+				$name = fmod($i++, 2) ? '' : 'alt_';
 
 				$out .= $this->template['row_'.$name.'start'].$this->newline;
 
@@ -323,27 +374,24 @@
 					{
 						if ($key !== 'data')
 						{
-							$temp = str_replace('<td', "<td $key='$val'", $temp);
+							$temp = str_replace('<td', '<td '.$key.'="'.$val.'"', $temp);
 						}
 					}
 
 					$cell = isset($cell['data']) ? $cell['data'] : '';
 					$out .= $temp;
 
-					if ($cell === "" OR $cell === NULL)
+					if ($cell === '' OR $cell === NULL)
 					{
 						$out .= $this->empty_cells;
 					}
+					elseif ($function !== FALSE && is_callable($function))
+					{
+						$out .= call_user_func($function, $cell);
+					}
 					else
 					{
-						if ($function !== FALSE && is_callable($function))
-						{
-							$out .= call_user_func($function, $cell);
-						}
-						else
-						{
-							$out .= $cell;
-						}
+						$out .= $cell;
 					}
 
 					$out .= $this->template['cell_'.$name.'end'];
@@ -372,9 +420,9 @@
 	 */
 	public function clear()
 	{
-		$this->rows				= array();
-		$this->heading			= array();
-		$this->auto_heading		= TRUE;
+		$this->rows		= array();
+		$this->heading		= array();
+		$this->auto_heading	= TRUE;
 	}
 
 	// --------------------------------------------------------------------
@@ -389,22 +437,21 @@
 	{
 		if ( ! is_object($query))
 		{
-			return FALSE;
+			return;
 		}
 
 		// First generate the headings from the table column names
 		if (count($this->heading) === 0)
 		{
-			if ( ! method_exists($query, 'list_fields'))
+			if ( ! is_callable(array($query, 'list_fields')))
 			{
-				return FALSE;
+				return;
 			}
 
 			$this->heading = $this->_prep_args($query->list_fields());
 		}
 
 		// Next blast through the result array and build out the rows
-
 		if ($query->num_rows() > 0)
 		{
 			foreach ($query->result_array() as $row)
@@ -420,6 +467,7 @@
 	 * Set table data from an array
 	 *
 	 * @param	array
+	 * @param	bool
 	 * @return	void
 	 */
 	protected function _set_from_array($data, $set_heading = TRUE)
@@ -433,7 +481,7 @@
 		foreach ($data as $row)
 		{
 			// If a heading hasn't already been set we'll use the first row of the array as the heading
-			if ($i++ === 0 AND count($data) > 1 AND count($this->heading) === 0 AND $set_heading == TRUE)
+			if ($i++ === 0 && count($data) > 1 && count($this->heading) === 0 && $set_heading === TRUE)
 			{
 				$this->heading = $this->_prep_args($row);
 			}
@@ -453,7 +501,7 @@
 	 */
 	protected function _compile_template()
 	{
-		if ($this->template == NULL)
+		if ($this->template === NULL)
 		{
 			$this->template = $this->_default_template();
 			return;
@@ -478,36 +526,35 @@
 	 */
 	protected function _default_template()
 	{
-		return  array (
-						'table_open'			=> '<table border="0" cellpadding="4" cellspacing="0">',
+		return  array(
+				'table_open'		=> '<table border="0" cellpadding="4" cellspacing="0">',
 
-						'thead_open'			=> '<thead>',
-						'thead_close'			=> '</thead>',
+				'thead_open'		=> '<thead>',
+				'thead_close'		=> '</thead>',
 
-						'heading_row_start'		=> '<tr>',
-						'heading_row_end'		=> '</tr>',
-						'heading_cell_start'	=> '<th>',
-						'heading_cell_end'		=> '</th>',
+				'heading_row_start'	=> '<tr>',
+				'heading_row_end'	=> '</tr>',
+				'heading_cell_start'	=> '<th>',
+				'heading_cell_end'	=> '</th>',
 
-						'tbody_open'			=> '<tbody>',
-						'tbody_close'			=> '</tbody>',
+				'tbody_open'		=> '<tbody>',
+				'tbody_close'		=> '</tbody>',
 
-						'row_start'				=> '<tr>',
-						'row_end'				=> '</tr>',
-						'cell_start'			=> '<td>',
-						'cell_end'				=> '</td>',
+				'row_start'		=> '<tr>',
+				'row_end'		=> '</tr>',
+				'cell_start'		=> '<td>',
+				'cell_end'		=> '</td>',
 
-						'row_alt_start'		=> '<tr>',
-						'row_alt_end'			=> '</tr>',
-						'cell_alt_start'		=> '<td>',
-						'cell_alt_end'			=> '</td>',
+				'row_alt_start'		=> '<tr>',
+				'row_alt_end'		=> '</tr>',
+				'cell_alt_start'	=> '<td>',
+				'cell_alt_end'		=> '</td>',
 
-						'table_close'			=> '</table>'
-					);
+				'table_close'		=> '</table>'
+			);
 	}
 
-
 }
 
 /* End of file Table.php */
-/* Location: ./system/libraries/Table.php */
+/* Location: ./system/libraries/Table.php */
\ No newline at end of file
diff --git a/system/libraries/Trackback.php b/system/libraries/Trackback.php
index 79a0091..9a680dc 100644
--- a/system/libraries/Trackback.php
+++ b/system/libraries/Trackback.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * Trackback Class
  *
@@ -49,7 +47,7 @@
 
 	public function __construct()
 	{
-		log_message('debug', "Trackback Class Initialized");
+		log_message('debug', 'Trackback Class Initialized');
 	}
 
 	// --------------------------------------------------------------------
@@ -90,16 +88,17 @@
 			}
 
 			// Convert High ASCII Characters
-			if ($this->convert_ascii == TRUE && in_array($item, array('excerpt', 'title', 'blog_name')))
+			if ($this->convert_ascii === TRUE && in_array($item, array('excerpt', 'title', 'blog_name')))
 			{
 				$$item = $this->convert_ascii($$item);
 			}
 		}
 
 		// Build the Trackback data string
-		$charset = ( ! isset($tb_data['charset'])) ? $this->charset : $tb_data['charset'];
+		$charset = isset($tb_data['charset']) ? $tb_data['charset'] : $this->charset;
 
-		$data = "url=".rawurlencode($url)."&title=".rawurlencode($title)."&blog_name=".rawurlencode($blog_name)."&excerpt=".rawurlencode($excerpt)."&charset=".rawurlencode($charset);
+		$data = 'url='.rawurlencode($url).'&title='.rawurlencode($title).'&blog_name='.rawurlencode($blog_name)
+			.'&excerpt='.rawurlencode($excerpt).'&charset='.rawurlencode($charset);
 
 		// Send Trackback(s)
 		$return = TRUE;
@@ -107,7 +106,7 @@
 		{
 			foreach ($ping_url as $url)
 			{
-				if ($this->process($url, $data) == FALSE)
+				if ($this->process($url, $data) === FALSE)
 				{
 					$return = FALSE;
 				}
@@ -133,22 +132,22 @@
 	{
 		foreach (array('url', 'title', 'blog_name', 'excerpt') as $val)
 		{
-			if ( ! isset($_POST[$val]) OR $_POST[$val] == '')
+			if (empty($_POST[$val]))
 			{
 				$this->set_error('The following required POST variable is missing: '.$val);
 				return FALSE;
 			}
 
-			$this->data['charset'] = ( ! isset($_POST['charset'])) ? 'auto' : strtoupper(trim($_POST['charset']));
+			$this->data['charset'] = isset($_POST['charset']) ? strtoupper(trim($_POST['charset'])) : 'auto';
 
-			if ($val != 'url' && function_exists('mb_convert_encoding'))
+			if ($val !== 'url' && MB_ENABLED === TRUE)
 			{
 				$_POST[$val] = mb_convert_encoding($_POST[$val], $this->charset, $this->data['charset']);
 			}
 
-			$_POST[$val] = ($val != 'url') ? $this->convert_xml(strip_tags($_POST[$val])) : strip_tags($_POST[$val]);
+			$_POST[$val] = ($val !== 'url') ? $this->convert_xml(strip_tags($_POST[$val])) : strip_tags($_POST[$val]);
 
-			if ($val == 'excerpt')
+			if ($val === 'excerpt')
 			{
 				$_POST['excerpt'] = $this->limit_characters($_POST['excerpt']);
 			}
@@ -164,7 +163,7 @@
 	/**
 	 * Send Trackback Error Message
 	 *
-	 * Allows custom errors to be set.  By default it
+	 * Allows custom errors to be set. By default it
 	 * sends the "incomplete information" error, as that's
 	 * the most common one.
 	 *
@@ -173,7 +172,7 @@
 	 */
 	public function send_error($message = 'Incomplete Information')
 	{
-		echo "<?xml version=\"1.0\" encoding=\"utf-8\"?".">\n<response>\n<error>1</error>\n<message>".$message."</message>\n</response>";
+		echo '<?xml version="1.0" encoding="utf-8"?'.">\n<response>\n<error>1</error>\n<message>".$message."</message>\n</response>";
 		exit;
 	}
 
@@ -189,7 +188,7 @@
 	 */
 	public function send_success()
 	{
-		echo "<?xml version=\"1.0\" encoding=\"utf-8\"?".">\n<response>\n<error>0</error>\n</response>";
+		echo '<?xml version="1.0" encoding="utf-8"?'.">\n<response>\n<error>0</error>\n</response>";
 		exit;
 	}
 
@@ -203,7 +202,7 @@
 	 */
 	public function data($item)
 	{
-		return ( ! isset($this->data[$item])) ? '' : $this->data[$item];
+		return isset($this->data[$item]) ? $this->data[$item] : '';
 	}
 
 	// --------------------------------------------------------------------
@@ -212,7 +211,7 @@
 	 * Process Trackback
 	 *
 	 * Opens a socket connection and passes the data to
-	 * the server.  Returns TRUE on success, FALSE on failure
+	 * the server. Returns TRUE on success, FALSE on failure
 	 *
 	 * @param	string
 	 * @param	string
@@ -230,37 +229,36 @@
 		}
 
 		// Build the path
-		$ppath = ( ! isset($target['path'])) ? $url : $target['path'];
+		$ppath = isset($target['path']) ? $target['path'] : $url;
 
-		$path = (isset($target['query']) && $target['query'] != "") ? $ppath.'?'.$target['query'] : $ppath;
+		$path = empty($target['query']) ? $ppath : $ppath.'?'.$target['query'];
 
 		// Add the Trackback ID to the data string
 		if ($id = $this->get_id($url))
 		{
-			$data = "tb_id=".$id."&".$data;
+			$data = 'tb_id='.$id.'&'.$data;
 		}
 
 		// Transfer the data
-		fputs ($fp, "POST " . $path . " HTTP/1.0\r\n" );
-		fputs ($fp, "Host: " . $target['host'] . "\r\n" );
-		fputs ($fp, "Content-type: application/x-www-form-urlencoded\r\n" );
-		fputs ($fp, "Content-length: " . strlen($data) . "\r\n" );
-		fputs ($fp, "Connection: close\r\n\r\n" );
-		fputs ($fp, $data);
+		fputs($fp, 'POST '.$path." HTTP/1.0\r\n");
+		fputs($fp, 'Host: '.$target['host']."\r\n");
+		fputs($fp, "Content-type: application/x-www-form-urlencoded\r\n");
+		fputs($fp, 'Content-length: '.strlen($data)."\r\n");
+		fputs($fp, "Connection: close\r\n\r\n");
+		fputs($fp, $data);
 
 		// Was it successful?
-		$this->response = "";
 
+		$this->response = '';
 		while ( ! feof($fp))
 		{
 			$this->response .= fgets($fp, 128);
 		}
 		@fclose($fp);
 
-
 		if (stripos($this->response, '<error>0</error>') === FALSE)
 		{
-			$message = (preg_match('/<message>(.*?)<\/message>/is', $this->response, $match)) ? trim($match[1]) : 'An unknown error was encountered';
+			$message = preg_match('/<message>(.*?)<\/message>/is', $this->response, $match) ? trim($match[1]) : 'An unknown error was encountered';
 			$this->set_error($message);
 			return FALSE;
 		}
@@ -282,11 +280,8 @@
 	 */
 	public function extract_urls($urls)
 	{
-		// Remove the pesky white space and replace with a comma.
-		$urls = preg_replace("/\s*(\S+)\s*/", "\\1,", $urls);
-
-		// If they use commas get rid of the doubles.
-		$urls = str_replace(",,", ",", $urls);
+		// Remove the pesky white space and replace with a comma, then replace doubles.
+		$urls = str_replace(',,', ',', preg_replace('/\s*(\S+)\s*/', '\\1,', $urls));
 
 		// Remove any comma that might be at the end
 		if (substr($urls, -1) === ',')
@@ -294,11 +289,8 @@
 			$urls = substr($urls, 0, -1);
 		}
 
-		// Break into an array via commas
-		$urls = preg_split('/[,]/', $urls);
-
-		// Removes duplicates
-		$urls = array_unique($urls);
+		// Break into an array via commas and remove duplicates
+		$urls = array_unique(preg_split('/[,]/', $urls));
 
 		array_walk($urls, array($this, 'validate_url'));
 
@@ -313,9 +305,9 @@
 	 * Simply adds "http://" if missing
 	 *
 	 * @param	string
-	 * @return	string
+	 * @return	void
 	 */
-	public function validate_url($url)
+	public function validate_url(&$url)
 	{
 		$url = trim($url);
 
@@ -335,7 +327,7 @@
 	 */
 	public function get_id($url)
 	{
-		$tb_id = "";
+		$tb_id = '';
 
 		if (strpos($url, '?') !== FALSE)
 		{
@@ -359,18 +351,11 @@
 
 			if ( ! is_numeric($tb_id))
 			{
-				$tb_id  = $tb_array[count($tb_array)-2];
+				$tb_id = $tb_array[count($tb_array)-2];
 			}
 		}
 
-		if ( ! preg_match ("/^([0-9]+)$/", $tb_id))
-		{
-			return FALSE;
-		}
-		else
-		{
-			return $tb_id;
-		}
+		return preg_match('/^[0-9]+$/', $tb_id) ? $tb_id : FALSE;
 	}
 
 	// --------------------------------------------------------------------
@@ -385,15 +370,13 @@
 	{
 		$temp = '__TEMP_AMPERSANDS__';
 
-		$str = preg_replace(array('/&#(\d+);/', '/&(\w+);/'), "$temp\\1;", $str);
+		$str = preg_replace(array('/&#(\d+);/', '/&(\w+);/'), $temp.'\\1;', $str);
 
-		$str = str_replace(array("&","<",">","\"", "'", "-"),
-							array("&amp;", "&lt;", "&gt;", "&quot;", "&#39;", "&#45;"),
-							$str);
+		$str = str_replace(array('&', '<', '>', '"', "'", '-'),
+					array('&amp;', '&lt;', '&gt;', '&quot;', '&#39;', '&#45;'),
+					$str);
 
-		$str = preg_replace(array("/$temp(\d+);/", "/$temp(\w+);/"), array('&#\\1;', '&\\1;'), $str);
-
-		return $str;
+		return preg_replace(array('/'.$temp.'(\d+);/', '/'.$temp.'(\w+);/'), array('&#\\1;', '&\\1;'), $str);
 	}
 
 	// --------------------------------------------------------------------
@@ -404,7 +387,7 @@
 	 * Limits the string based on the character count. Will preserve complete words.
 	 *
 	 * @param	string
-	 * @param	integer
+	 * @param	int
 	 * @param	string
 	 * @return	string
 	 */
@@ -415,7 +398,7 @@
 			return $str;
 		}
 
-		$str = preg_replace("/\s+/", ' ', str_replace(array("\r\n", "\r", "\n"), ' ', $str));
+		$str = preg_replace('/\s+/', ' ', str_replace(array("\r\n", "\r", "\n"), ' ', $str));
 
 		if (strlen($str) <= $n)
 		{
@@ -469,7 +452,9 @@
 
 				if (count($temp) === $count)
 				{
-					$number = ($count == 3) ? (($temp[0] % 16) * 4096) + (($temp[1] % 64) * 64) + ($temp[2] % 64) : (($temp[0] % 32) * 64) + ($temp[1] % 64);
+					$number = ($count === 3)
+						? (($temp[0] % 16) * 4096) + (($temp[1] % 64) * 64) + ($temp[2] % 64)
+						: (($temp[0] % 32) * 64) + ($temp[1] % 64);
 
 					$out .= '&#'.$number.';';
 					$count = 1;
@@ -506,11 +491,10 @@
 	 */
 	public function display_errors($open = '<p>', $close = '</p>')
 	{
-		return (count($this->error_msg) > 0) ? $open . implode($close . $open, $this->error_msg) . $close : '';
+		return (count($this->error_msg) > 0) ? $open.implode($close.$open, $this->error_msg).$close : '';
 	}
 
 }
-// END Trackback Class
 
 /* End of file Trackback.php */
-/* Location: ./system/libraries/Trackback.php */
+/* Location: ./system/libraries/Trackback.php */
\ No newline at end of file
diff --git a/system/libraries/Typography.php b/system/libraries/Typography.php
index 46c73ef..a50934f 100644
--- a/system/libraries/Typography.php
+++ b/system/libraries/Typography.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -25,35 +25,57 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * Typography Class
  *
- *
- * @access		protected
+ * @package		CodeIgniter
+ * @subpackage	Libraries
  * @category	Helpers
  * @author		EllisLab Dev Team
  * @link		http://codeigniter.com/user_guide/libraries/typography.html
  */
 class CI_Typography {
 
-	// Block level elements that should not be wrapped inside <p> tags
+	/**
+	 * Block level elements that should not be wrapped inside <p> tags
+	 *
+	 * @var string
+	 */
 	public $block_elements = 'address|blockquote|div|dl|fieldset|form|h\d|hr|noscript|object|ol|p|pre|script|table|ul';
 
-	// Elements that should not have <p> and <br /> tags within them.
+	/**
+	 * Elements that should not have <p> and <br /> tags within them.
+	 *
+	 * @var string
+	 */
 	public $skip_elements	= 'p|pre|ol|ul|dl|object|table|h\d';
 
-	// Tags we want the parser to completely ignore when splitting the string.
+	/**
+	 * Tags we want the parser to completely ignore when splitting the string.
+	 *
+	 * @var string
+	 */
 	public $inline_elements = 'a|abbr|acronym|b|bdo|big|br|button|cite|code|del|dfn|em|i|img|ins|input|label|map|kbd|q|samp|select|small|span|strong|sub|sup|textarea|tt|var';
 
-	// array of block level elements that require inner content to be within another block level element
+	/**
+	 * array of block level elements that require inner content to be within another block level element
+	 *
+	 * @var array
+	 */
 	public $inner_block_required = array('blockquote');
 
-	// the last block element parsed
+	/**
+	 * the last block element parsed
+	 *
+	 * @var string
+	 */
 	public $last_block_element = '';
 
-	// whether or not to protect quotes within { curly braces }
+	/**
+	 * whether or not to protect quotes within { curly braces }
+	 *
+	 * @var bool
+	 */
 	public $protect_braced_quotes = FALSE;
 
 	/**
@@ -67,14 +89,13 @@
 	 *	- Converts double dashes into em-dashes.
 	 *  - Converts two spaces into entities
 	 *
-	 * @access	public
 	 * @param	string
 	 * @param	bool	whether to reduce more then two consecutive newlines to two
 	 * @return	string
 	 */
 	public function auto_typography($str, $reduce_linebreaks = FALSE)
 	{
-		if ($str == '')
+		if ($str === '')
 		{
 			return '';
 		}
@@ -94,15 +115,12 @@
 
 		// HTML comment tags don't conform to patterns of normal tags, so pull them out separately, only if needed
 		$html_comments = array();
-		if (strpos($str, '<!--') !== FALSE)
+		if (strpos($str, '<!--') !== FALSE && preg_match_all('#(<!\-\-.*?\-\->)#s', $str, $matches))
 		{
-			if (preg_match_all("#(<!\-\-.*?\-\->)#s", $str, $matches))
+			for ($i = 0, $total = count($matches[0]); $i < $total; $i++)
 			{
-				for ($i = 0, $total = count($matches[0]); $i < $total; $i++)
-				{
-					$html_comments[] = $matches[0][$i];
-					$str = str_replace($matches[0][$i], '{@HC'.$i.'}', $str);
-				}
+				$html_comments[] = $matches[0][$i];
+				$str = str_replace($matches[0][$i], '{@HC'.$i.'}', $str);
 			}
 		}
 
@@ -110,22 +128,22 @@
 		// not contain <pre> tags, and it keeps the PCRE patterns below simpler and faster
 		if (strpos($str, '<pre') !== FALSE)
 		{
-			$str = preg_replace_callback("#<pre.*?>.*?</pre>#si", array($this, '_protect_characters'), $str);
+			$str = preg_replace_callback('#<pre.*?>.*?</pre>#si', array($this, '_protect_characters'), $str);
 		}
 
 		// Convert quotes within tags to temporary markers.
-		$str = preg_replace_callback("#<.+?>#si", array($this, '_protect_characters'), $str);
+		$str = preg_replace_callback('#<.+?>#si', array($this, '_protect_characters'), $str);
 
 		// Do the same with braces if necessary
 		if ($this->protect_braced_quotes === TRUE)
 		{
-			$str = preg_replace_callback("#\{.+?\}#si", array($this, '_protect_characters'), $str);
+			$str = preg_replace_callback('#\{.+?\}#si', array($this, '_protect_characters'), $str);
 		}
 
 		// Convert "ignore" tags to temporary marker.  The parser splits out the string at every tag
 		// it encounters.  Certain inline tags, like image tags, links, span tags, etc. will be
 		// adversely affected if they are split out so we'll convert the opening bracket < temporarily to: {@TAG}
-		$str = preg_replace("#<(/*)(".$this->inline_elements.")([ >])#i", "{@TAG}\\1\\2\\3", $str);
+		$str = preg_replace('#<(/*)('.$this->inline_elements.')([ >])#i', '{@TAG}\\1\\2\\3', $str);
 
 		/* Split the string at every tag. This expression creates an array with this prototype:
 		 *
@@ -148,14 +166,14 @@
 		{
 			// Are we dealing with a tag? If so, we'll skip the processing for this cycle.
 			// Well also set the "process" flag which allows us to skip <pre> tags and a few other things.
-			if (preg_match("#<(/*)(".$this->block_elements.").*?>#", $chunks[$i], $match))
+			if (preg_match('#<(/*)('.$this->block_elements.').*?>#', $chunks[$i], $match))
 			{
-				if (preg_match("#".$this->skip_elements."#", $match[2]))
+				if (preg_match('#'.$this->skip_elements.'#', $match[2]))
 				{
 					$process = ($match[1] === '/');
 				}
 
-				if ($match[1] == '')
+				if ($match[1] === '')
 				{
 					$this->last_block_element = $match[2];
 				}
@@ -180,10 +198,10 @@
 			$str .= $this->_format_newlines($chunks[$i]);
 		}
 
-		// No opening block level tag?  Add it if needed.
-		if ( ! preg_match("/^\s*<(?:".$this->block_elements.")/i", $str))
+		// No opening block level tag? Add it if needed.
+		if ( ! preg_match('/^\s*<(?:'.$this->block_elements.')/i', $str))
 		{
-			$str = preg_replace("/^(.*?)<(".$this->block_elements.")/i", '<p>$1</p><$2', $str);
+			$str = preg_replace('/^(.*?)<('.$this->block_elements.')/i', '<p>$1</p><$2', $str);
 		}
 
 		// Convert quotes, elipsis, em-dashes, non-breaking spaces, and ampersands
@@ -230,7 +248,7 @@
 
 						// Similarly, there might be cases where a closing </block> will follow
 						// a closing </p> tag, so we'll correct it by adding a newline in between
-						"#</p></#"			=> "</p>\n</"
+						'#</p></#'			=> "</p>\n</"
 						);
 
 		// Do we need to reduce empty lines?
@@ -258,7 +276,6 @@
 	 * to curly entities, but it also converts em-dashes,
 	 * double spaces, and ampersands
 	 *
-	 * @access	public
 	 * @param	string
 	 * @return	string
 	 */
@@ -322,13 +339,12 @@
 	 *
 	 * Converts newline characters into either <p> tags or <br />
 	 *
-	 * @access	protected
 	 * @param	string
 	 * @return	string
 	 */
 	protected function _format_newlines($str)
 	{
-		if ($str == '' OR (strpos($str, "\n") === FALSE AND ! in_array($this->last_block_element, $this->inner_block_required)))
+		if ($str === '' OR (strpos($str, "\n") === FALSE && ! in_array($this->last_block_element, $this->inner_block_required)))
 		{
 			return $str;
 		}
@@ -337,10 +353,10 @@
 		$str = str_replace("\n\n", "</p>\n\n<p>", $str);
 
 		// Convert single spaces to <br /> tags
-		$str = preg_replace("/([^\n])(\n)([^\n])/", "\\1<br />\\2\\3", $str);
+		$str = preg_replace("/([^\n])(\n)([^\n])/", '\\1<br />\\2\\3', $str);
 
 		// Wrap the whole enchilada in enclosing paragraphs
-		if ($str != "\n")
+		if ($str !== "\n")
 		{
 			// We trim off the right-side new line so that the closing </p> tag
 			// will be positioned immediately following the string, matching
@@ -350,9 +366,7 @@
 
 		// Remove empty paragraphs if they are on the first line, as this
 		// is a potential unintended consequence of the previous code
-		$str = preg_replace("/<p><\/p>(.*)/", "\\1", $str, 1);
-
-		return $str;
+		return preg_replace('/<p><\/p>(.*)/', '\\1', $str, 1);
 	}
 
 	// ------------------------------------------------------------------------
@@ -365,7 +379,6 @@
 	 * and we don't want double dashes converted to emdash entities, so they are marked with {@DD}
 	 * likewise double spaces are converted to {@NBS} to prevent entity conversion
 	 *
-	 * @access	protected
 	 * @param	array
 	 * @return	string
 	 */
@@ -379,7 +392,6 @@
 	/**
 	 * Convert newlines to HTML line breaks except within PRE tags
 	 *
-	 * @access	public
 	 * @param	string
 	 * @return	string
 	 */
@@ -399,7 +411,6 @@
 	}
 
 }
-// END Typography Class
 
 /* End of file Typography.php */
-/* Location: ./system/libraries/Typography.php */
+/* Location: ./system/libraries/Typography.php */
\ No newline at end of file
diff --git a/system/libraries/Unit_test.php b/system/libraries/Unit_test.php
index 38d767c..70ad8dc 100644
--- a/system/libraries/Unit_test.php
+++ b/system/libraries/Unit_test.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * Unit Testing Class
  *
@@ -60,7 +58,7 @@
 							'notes'
 						);
 
-		log_message('debug', "Unit Testing Class Initialized");
+		log_message('debug', 'Unit Testing Class Initialized');
 	}
 
 	// --------------------------------------------------------------------
@@ -75,7 +73,7 @@
 	 */
 	public function set_test_items($items = array())
 	{
-		if ( ! empty($items) AND is_array($items))
+		if ( ! empty($items) && is_array($items))
 		{
 			$this->_test_items_visible = $items;
 		}
@@ -95,20 +93,20 @@
 	 */
 	public function run($test, $expected = TRUE, $test_name = 'undefined', $notes = '')
 	{
-		if ($this->active == FALSE)
+		if ($this->active === FALSE)
 		{
 			return FALSE;
 		}
 
 		if (in_array($expected, array('is_object', 'is_string', 'is_bool', 'is_true', 'is_false', 'is_int', 'is_numeric', 'is_float', 'is_double', 'is_array', 'is_null'), TRUE))
 		{
-			$expected = str_replace('is_float', 'is_double', $expected);
-			$result = ($expected($test)) ? TRUE : FALSE;
+			$expected = str_replace('is_double', 'is_float', $expected);
+			$result = $expected($test);
 			$extype = str_replace(array('true', 'false'), 'bool', str_replace('is_', '', $expected));
 		}
 		else
 		{
-			$result = ($this->strict == TRUE) ? ($test === $expected) : ($test == $expected);
+			$result = ($this->strict === TRUE) ? ($test === $expected) : ($test === $expected);
 			$extype = gettype($expected);
 		}
 
@@ -126,7 +124,7 @@
 
 		$this->results[] = $report;
 
-		return($this->report($this->result($report)));
+		return $this->report($this->result($report));
 	}
 
 	// --------------------------------------------------------------------
@@ -157,13 +155,13 @@
 
 			foreach ($res as $key => $val)
 			{
-				if ($key == $CI->lang->line('ut_result'))
+				if ($key === $CI->lang->line('ut_result'))
 				{
-					if ($val == $CI->lang->line('ut_passed'))
+					if ($val === $CI->lang->line('ut_passed'))
 					{
 						$val = '<span style="color: #0C0;">'.$val.'</span>';
 					}
-					elseif ($val == $CI->lang->line('ut_failed'))
+					elseif ($val === $CI->lang->line('ut_failed'))
 					{
 						$val = '<span style="color: #C00;">'.$val.'</span>';
 					}
@@ -186,7 +184,7 @@
 	 * Causes the evaluation to use === rather than ==
 	 *
 	 * @param	bool
-	 * @return	null
+	 * @return	void
 	 */
 	public function use_strict($state = TRUE)
 	{
@@ -201,7 +199,7 @@
 	 * Enables/disables unit testing
 	 *
 	 * @param	bool
-	 * @return	null
+	 * @return	void
 	 */
 	public function active($state = TRUE)
 	{
@@ -291,15 +289,11 @@
 	 */
 	protected function _backtrace()
 	{
-		if (function_exists('debug_backtrace'))
-		{
-			$back = debug_backtrace();
-			return array(
-					'file' => (isset($back[1]['file']) ? $back[1]['file'] : ''),
-					'line' => (isset($back[1]['line']) ? $back[1]['line'] : '')
-				);
-		}
-		return array('file' => 'Unknown', 'line' => 'Unknown');
+		$back = debug_backtrace();
+		return array(
+				'file' => (isset($back[1]['file']) ? $back[1]['file'] : ''),
+				'line' => (isset($back[1]['line']) ? $back[1]['line'] : '')
+			);
 	}
 
 	// --------------------------------------------------------------------
@@ -311,10 +305,10 @@
 	 */
 	protected function _default_template()
 	{
-		$this->_template = "\n".'<table style="width:100%; font-size:small; margin:10px 0; border-collapse:collapse; border:1px solid #CCC;">{rows}'."\n".'</table>';
+		$this->_template = "\n".'<table style="width:100%; font-size:small; margin:10px 0; border-collapse:collapse; border:1px solid #CCC;">{rows}'."\n</table>";
 
 		$this->_template_rows = "\n\t<tr>\n\t\t".'<th style="text-align: left; border-bottom:1px solid #CCC;">{item}</th>'
-					. "\n\t\t".'<td style="border-bottom:1px solid #CCC;">{result}</td>'."\n\t</tr>";
+					."\n\t\t".'<td style="border-bottom:1px solid #CCC;">{result}</td>'."\n\t</tr>";
 	}
 
 	// --------------------------------------------------------------------
@@ -333,7 +327,7 @@
 			return;
 		}
 
-		if (is_null($this->_template) OR ! preg_match("/\{rows\}(.*?)\{\/rows\}/si", $this->_template, $match))
+		if (is_null($this->_template) OR ! preg_match('/\{rows\}(.*?)\{\/rows\}/si', $this->_template, $match))
 		{
 			$this->_default_template();
 			return;
@@ -344,7 +338,6 @@
 	}
 
 }
-// END Unit_test Class
 
 /**
  * Helper functions to test boolean true/false
@@ -353,13 +346,12 @@
  */
 function is_true($test)
 {
-	return (is_bool($test) AND $test === TRUE) ? TRUE : FALSE;
+	return ($test === TRUE);
 }
 function is_false($test)
 {
-	return (is_bool($test) AND $test === FALSE) ? TRUE : FALSE;
+	return ($test === FALSE);
 }
 
-
 /* 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 0c63886..c96daaf 100644
--- a/system/libraries/Upload.php
+++ b/system/libraries/Upload.php
@@ -1,8 +1,8 @@
-<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * File Uploading Class
  *
@@ -38,39 +36,40 @@
  */
 class CI_Upload {
 
-	public $max_size				= 0;
-	public $max_width				= 0;
-	public $max_height				= 0;
-	public $max_filename			= 0;
+	public $max_size		= 0;
+	public $max_width		= 0;
+	public $max_height		= 0;
+	public $max_filename		= 0;
 	public $max_filename_increment 	= 100;
-	public $allowed_types			= "";
-	public $file_temp				= "";
-	public $file_name				= "";
-	public $orig_name				= "";
-	public $file_type				= "";
-	public $file_size				= "";
-	public $file_ext				= "";
-	public $upload_path				= "";
-	public $overwrite				= FALSE;
-	public $encrypt_name			= FALSE;
-	public $is_image				= FALSE;
-	public $image_width				= '';
-	public $image_height			= '';
-	public $image_type				= '';
-	public $image_size_str			= '';
-	public $error_msg				= array();
-	public $mimes					= array();
-	public $remove_spaces			= TRUE;
-	public $xss_clean				= FALSE;
-	public $temp_prefix				= "temp_file_";
-	public $client_name				= '';
+	public $allowed_types		= '';
+	public $file_temp		= '';
+	public $file_name		= '';
+	public $orig_name		= '';
+	public $file_type		= '';
+	public $file_size		= '';
+	public $file_ext		= '';
+	public $upload_path		= '';
+	public $overwrite		= FALSE;
+	public $encrypt_name		= FALSE;
+	public $is_image		= FALSE;
+	public $image_width		= '';
+	public $image_height		= '';
+	public $image_type		= '';
+	public $image_size_str		= '';
+	public $error_msg		= array();
+	public $mimes			= array();
+	public $remove_spaces		= TRUE;
+	public $xss_clean		= FALSE;
+	public $temp_prefix		= 'temp_file_';
+	public $client_name		= '';
 
 	protected $_file_name_override	= '';
 
 	/**
 	 * Constructor
 	 *
-	 * @access	public
+	 * @param	array
+	 * @return	void
 	 */
 	public function __construct($props = array())
 	{
@@ -79,7 +78,9 @@
 			$this->initialize($props);
 		}
 
-		log_message('debug', "Upload Class Initialized");
+		$this->mimes =& get_mimes();
+
+		log_message('debug', 'Upload Class Initialized');
 	}
 
 	// --------------------------------------------------------------------
@@ -93,33 +94,32 @@
 	public function initialize($config = array())
 	{
 		$defaults = array(
-							'max_size'					=> 0,
-							'max_width'					=> 0,
-							'max_height'				=> 0,
-							'max_filename'				=> 0,
-							'max_filename_increment'	=> 100,
-							'allowed_types'				=> "",
-							'file_temp'					=> "",
-							'file_name'					=> "",
-							'orig_name'					=> "",
-							'file_type'					=> "",
-							'file_size'					=> "",
-							'file_ext'					=> "",
-							'upload_path'				=> "",
-							'overwrite'					=> FALSE,
-							'encrypt_name'				=> FALSE,
-							'is_image'					=> FALSE,
-							'image_width'				=> '',
-							'image_height'				=> '',
-							'image_type'				=> '',
-							'image_size_str'			=> '',
-							'error_msg'					=> array(),
-							'mimes'						=> array(),
-							'remove_spaces'				=> TRUE,
-							'xss_clean'					=> FALSE,
-							'temp_prefix'				=> "temp_file_",
-							'client_name'				=> ''
-						);
+					'max_size'			=> 0,
+					'max_width'			=> 0,
+					'max_height'			=> 0,
+					'max_filename'			=> 0,
+					'max_filename_increment'	=> 100,
+					'allowed_types'			=> '',
+					'file_temp'			=> '',
+					'file_name'			=> '',
+					'orig_name'			=> '',
+					'file_type'			=> '',
+					'file_size'			=> '',
+					'file_ext'			=> '',
+					'upload_path'			=> '',
+					'overwrite'			=> FALSE,
+					'encrypt_name'			=> FALSE,
+					'is_image'			=> FALSE,
+					'image_width'			=> '',
+					'image_height'			=> '',
+					'image_type'			=> '',
+					'image_size_str'		=> '',
+					'error_msg'			=> array(),
+					'remove_spaces'			=> TRUE,
+					'xss_clean'			=> FALSE,
+					'temp_prefix'			=> 'temp_file_',
+					'client_name'			=> ''
+				);
 
 
 		foreach ($defaults as $key => $val)
@@ -156,8 +156,7 @@
 	 */
 	public function do_upload($field = 'userfile')
 	{
-
-	// Is $_FILES[$field] set? If not, no reason to continue.
+		// Is $_FILES[$field] set? If not, no reason to continue.
 		if ( ! isset($_FILES[$field]))
 		{
 			$this->set_error('upload_no_file_selected');
@@ -176,7 +175,7 @@
 		{
 			$error = ( ! isset($_FILES[$field]['error'])) ? 4 : $_FILES[$field]['error'];
 
-			switch($error)
+			switch ($error)
 			{
 				case 1:	// UPLOAD_ERR_INI_SIZE
 					$this->set_error('upload_file_exceeds_limit');
@@ -199,19 +198,19 @@
 				case 8: // UPLOAD_ERR_EXTENSION
 					$this->set_error('upload_stopped_by_extension');
 					break;
-				default :   $this->set_error('upload_no_file_selected');
+				default:
+					$this->set_error('upload_no_file_selected');
 					break;
 			}
 
 			return FALSE;
 		}
 
-
 		// Set the uploaded data as class variables
 		$this->file_temp = $_FILES[$field]['tmp_name'];
 		$this->file_size = $_FILES[$field]['size'];
 		$this->_file_mime_type($_FILES[$field]);
-		$this->file_type = preg_replace("/^(.+?);.*$/", "\\1", $this->file_type);
+		$this->file_type = preg_replace('/^(.+?);.*$/', '\\1', $this->file_type);
 		$this->file_type = strtolower(trim(stripslashes($this->file_type), '"'));
 		$this->file_name = $this->_prep_filename($_FILES[$field]['name']);
 		$this->file_ext	 = $this->get_extension($this->file_name);
@@ -225,7 +224,7 @@
 		}
 
 		// if we're overriding, let's now make sure the new name and type is allowed
-		if ($this->_file_name_override != '')
+		if ($this->_file_name_override !== '')
 		{
 			$this->file_name = $this->_prep_filename($this->_file_name_override);
 
@@ -234,11 +233,10 @@
 			{
 				$this->file_name .= $this->file_ext;
 			}
-
-			// An extension was provided, lets have it!
 			else
 			{
-				$this->file_ext	 = $this->get_extension($this->_file_name_override);
+				// An extension was provided, lets have it!
+				$this->file_ext	= $this->get_extension($this->_file_name_override);
 			}
 
 			if ( ! $this->is_allowed_filetype(TRUE))
@@ -279,9 +277,9 @@
 		}
 
 		// Remove white spaces in the name
-		if ($this->remove_spaces == TRUE)
+		if ($this->remove_spaces === TRUE)
 		{
-			$this->file_name = preg_replace("/\s+/", "_", $this->file_name);
+			$this->file_name = preg_replace('/\s+/', '_', $this->file_name);
 		}
 
 		/*
@@ -292,7 +290,7 @@
 		 */
 		$this->orig_name = $this->file_name;
 
-		if ($this->overwrite == FALSE)
+		if ($this->overwrite === FALSE)
 		{
 			$this->file_name = $this->set_filename($this->upload_path, $this->file_name);
 
@@ -305,23 +303,20 @@
 		/*
 		 * Run the file through the XSS hacking filter
 		 * This helps prevent malicious code from being
-		 * embedded within a file.  Scripts can easily
+		 * embedded within a file. Scripts can easily
 		 * be disguised as images or other file types.
 		 */
-		if ($this->xss_clean)
+		if ($this->xss_clean && $this->do_xss_clean() === FALSE)
 		{
-			if ($this->do_xss_clean() === FALSE)
-			{
-				$this->set_error('upload_unable_to_write_file');
-				return FALSE;
-			}
+			$this->set_error('upload_unable_to_write_file');
+			return FALSE;
 		}
 
 		/*
 		 * Move the file to the final destination
 		 * To deal with different server configurations
-		 * we'll attempt to use copy() first.  If that fails
-		 * we'll use move_uploaded_file().  One of the two should
+		 * we'll attempt to use copy() first. If that fails
+		 * we'll use move_uploaded_file(). One of the two should
 		 * reliably work in most environments
 		 */
 		if ( ! @copy($this->file_temp, $this->upload_path.$this->file_name))
@@ -336,7 +331,7 @@
 		/*
 		 * Set the finalized image dimensions
 		 * This sets the image width/height (assuming the
-		 * file was an image).  We use this information
+		 * file was an image). We use this information
 		 * in the "data" function.
 		 */
 		$this->set_image_properties($this->upload_path.$this->file_name);
@@ -352,26 +347,34 @@
 	 * Returns an associative array containing all of the information
 	 * related to the upload, allowing the developer easy access in one array.
 	 *
-	 * @return	array
+	 * @param	string
+	 * @return	mixed
 	 */
-	public function data()
+	public function data($index = NULL)
 	{
-		return array (
-						'file_name'			=> $this->file_name,
-						'file_type'			=> $this->file_type,
-						'file_path'			=> $this->upload_path,
-						'full_path'			=> $this->upload_path.$this->file_name,
-						'raw_name'			=> str_replace($this->file_ext, '', $this->file_name),
-						'orig_name'			=> $this->orig_name,
-						'client_name'		=> $this->client_name,
-						'file_ext'			=> $this->file_ext,
-						'file_size'			=> $this->file_size,
-						'is_image'			=> $this->is_image(),
-						'image_width'		=> $this->image_width,
-						'image_height'		=> $this->image_height,
-						'image_type'		=> $this->image_type,
-						'image_size_str'	=> $this->image_size_str,
-					);
+		$data = array(
+				'file_name'		=> $this->file_name,
+				'file_type'		=> $this->file_type,
+				'file_path'		=> $this->upload_path,
+				'full_path'		=> $this->upload_path.$this->file_name,
+				'raw_name'		=> str_replace($this->file_ext, '', $this->file_name),
+				'orig_name'		=> $this->orig_name,
+				'client_name'		=> $this->client_name,
+				'file_ext'		=> $this->file_ext,
+				'file_size'		=> $this->file_size,
+				'is_image'		=> $this->is_image(),
+				'image_width'		=> $this->image_width,
+				'image_height'		=> $this->image_height,
+				'image_type'		=> $this->image_type,
+				'image_size_str'	=> $this->image_size_str,
+			);
+
+		if ( ! empty($index))
+		{
+			return isset($data[$index]) ? $data[$index] : NULL;
+		}
+
+		return $data;
 	}
 
 	// --------------------------------------------------------------------
@@ -403,7 +406,7 @@
 	 */
 	public function set_filename($path, $filename)
 	{
-		if ($this->encrypt_name == TRUE)
+		if ($this->encrypt_name === TRUE)
 		{
 			mt_srand();
 			$filename = md5(uniqid(mt_rand())).$this->file_ext;
@@ -426,7 +429,7 @@
 			}
 		}
 
-		if ($new_filename == '')
+		if ($new_filename === '')
 		{
 			$this->set_error('upload_bad_filename');
 			return FALSE;
@@ -442,12 +445,12 @@
 	/**
 	 * Set Maximum File Size
 	 *
-	 * @param	integer
+	 * @param	int
 	 * @return	void
 	 */
 	public function set_max_filesize($n)
 	{
-		$this->max_size = ((int) $n < 0) ? 0: (int) $n;
+		$this->max_size = ((int) $n < 0) ? 0 : (int) $n;
 	}
 
 	// --------------------------------------------------------------------
@@ -455,12 +458,12 @@
 	/**
 	 * Set Maximum File Name Length
 	 *
-	 * @param	integer
+	 * @param	int
 	 * @return	void
 	 */
 	public function set_max_filename($n)
 	{
-		$this->max_filename = ((int) $n < 0) ? 0: (int) $n;
+		$this->max_filename = ((int) $n < 0) ? 0 : (int) $n;
 	}
 
 	// --------------------------------------------------------------------
@@ -468,12 +471,12 @@
 	/**
 	 * Set Maximum Image Width
 	 *
-	 * @param	integer
+	 * @param	int
 	 * @return	void
 	 */
 	public function set_max_width($n)
 	{
-		$this->max_width = ((int) $n < 0) ? 0: (int) $n;
+		$this->max_width = ((int) $n < 0) ? 0 : (int) $n;
 	}
 
 	// --------------------------------------------------------------------
@@ -481,12 +484,12 @@
 	/**
 	 * Set Maximum Image Height
 	 *
-	 * @param	integer
+	 * @param	int
 	 * @return	void
 	 */
 	public function set_max_height($n)
 	{
-		$this->max_height = ((int) $n < 0) ? 0: (int) $n;
+		$this->max_height = ((int) $n < 0) ? 0 : (int) $n;
 	}
 
 	// --------------------------------------------------------------------
@@ -499,7 +502,7 @@
 	 */
 	public function set_allowed_types($types)
 	{
-		if ( ! is_array($types) && $types == '*')
+		if ( ! is_array($types) && $types === '*')
 		{
 			$this->allowed_types = '*';
 			return;
@@ -530,10 +533,10 @@
 			{
 				$types = array(1 => 'gif', 2 => 'jpeg', 3 => 'png');
 
-				$this->image_width		= $D['0'];
-				$this->image_height		= $D['1'];
-				$this->image_type		= ( ! isset($types[$D['2']])) ? 'unknown' : $types[$D['2']];
-				$this->image_size_str	= $D['3'];  // string containing height and width
+				$this->image_width	= $D[0];
+				$this->image_height	= $D[1];
+				$this->image_type	= isset($types[$D[2]]) ? $types[$D[2]] : 'unknown';
+				$this->image_size_str	= $D[3]; // string containing height and width
 			}
 		}
 	}
@@ -551,7 +554,7 @@
 	 */
 	public function set_xss_clean($flag = FALSE)
 	{
-		$this->xss_clean = ($flag == TRUE) ? TRUE : FALSE;
+		$this->xss_clean = ($flag === TRUE);
 	}
 
 	// --------------------------------------------------------------------
@@ -573,19 +576,14 @@
 		{
 			$this->file_type = 'image/png';
 		}
-
-		if (in_array($this->file_type, $jpeg_mimes))
+		elseif (in_array($this->file_type, $jpeg_mimes))
 		{
 			$this->file_type = 'image/jpeg';
 		}
 
-		$img_mimes = array(
-							'image/gif',
-							'image/jpeg',
-							'image/png',
-						);
+		$img_mimes = array('image/gif',	'image/jpeg', 'image/png');
 
-		return (in_array($this->file_type, $img_mimes, TRUE)) ? TRUE : FALSE;
+		return in_array($this->file_type, $img_mimes, TRUE);
 	}
 
 	// --------------------------------------------------------------------
@@ -593,16 +591,17 @@
 	/**
 	 * Verify that the filetype is allowed
 	 *
+	 * @param	bool
 	 * @return	bool
 	 */
 	public function is_allowed_filetype($ignore_mime = FALSE)
 	{
-		if ($this->allowed_types == '*')
+		if ($this->allowed_types === '*')
 		{
 			return TRUE;
 		}
 
-		if (count($this->allowed_types) == 0 OR ! is_array($this->allowed_types))
+		if ( ! is_array($this->allowed_types) OR count($this->allowed_types) === 0)
 		{
 			$this->set_error('upload_no_file_types');
 			return FALSE;
@@ -618,12 +617,9 @@
 		// Images get some additional checks
 		$image_types = array('gif', 'jpg', 'jpeg', 'png', 'jpe');
 
-		if (in_array($ext, $image_types))
+		if (in_array($ext, $image_types) && @getimagesize($this->file_temp) === FALSE)
 		{
-			if (getimagesize($this->file_temp) === FALSE)
-			{
-				return FALSE;
-			}
+			return FALSE;
 		}
 
 		if ($ignore_mime === TRUE)
@@ -633,16 +629,13 @@
 
 		$mime = $this->mimes_types($ext);
 
-		if (is_array($mime))
+		if (is_array($mime) && in_array($this->file_type, $mime, TRUE))
 		{
-			if (in_array($this->file_type, $mime, TRUE))
-			{
-				return TRUE;
-			}
+			return TRUE;
 		}
-		elseif ($mime == $this->file_type)
+		elseif ($mime === $this->file_type)
 		{
-				return TRUE;
+			return TRUE;
 		}
 
 		return FALSE;
@@ -657,14 +650,7 @@
 	 */
 	public function is_allowed_filesize()
 	{
-		if ($this->max_size != 0  AND  $this->file_size > $this->max_size)
-		{
-			return FALSE;
-		}
-		else
-		{
-			return TRUE;
-		}
+		return ($this->max_size === 0 OR $this->max_size > $this->file_size);
 	}
 
 	// --------------------------------------------------------------------
@@ -685,17 +671,15 @@
 		{
 			$D = @getimagesize($this->file_temp);
 
-			if ($this->max_width > 0 AND $D['0'] > $this->max_width)
+			if ($this->max_width > 0 && $D[0] > $this->max_width)
 			{
 				return FALSE;
 			}
 
-			if ($this->max_height > 0 AND $D['1'] > $this->max_height)
+			if ($this->max_height > 0 && $D[1] > $this->max_height)
 			{
 				return FALSE;
 			}
-
-			return TRUE;
 		}
 
 		return TRUE;
@@ -708,20 +692,19 @@
 	 *
 	 * Verifies that it is a valid upload path with proper permissions.
 	 *
-	 *
 	 * @return	bool
 	 */
 	public function validate_upload_path()
 	{
-		if ($this->upload_path == '')
+		if ($this->upload_path === '')
 		{
 			$this->set_error('upload_no_filepath');
 			return FALSE;
 		}
 
-		if (function_exists('realpath') AND @realpath($this->upload_path) !== FALSE)
+		if (@realpath($this->upload_path) !== FALSE)
 		{
-			$this->upload_path = str_replace("\\", "/", realpath($this->upload_path));
+			$this->upload_path = str_replace('\\', '/', realpath($this->upload_path));
 		}
 
 		if ( ! @is_dir($this->upload_path))
@@ -736,7 +719,7 @@
 			return FALSE;
 		}
 
-		$this->upload_path = preg_replace("/(.+?)\/*$/", "\\1/",  $this->upload_path);
+		$this->upload_path = preg_replace('/(.+?)\/*$/', '\\1/',  $this->upload_path);
 		return TRUE;
 	}
 
@@ -751,7 +734,7 @@
 	public function get_extension($filename)
 	{
 		$x = explode('.', $filename);
-		return '.'.end($x);
+		return (count($x) !== 1) ? '.'.end($x) : '';
 	}
 
 	// --------------------------------------------------------------------
@@ -765,37 +748,33 @@
 	public function clean_file_name($filename)
 	{
 		$bad = array(
-						"<!--",
-						"-->",
-						"'",
-						"<",
-						">",
-						'"',
-						'&',
-						'$',
-						'=',
-						';',
-						'?',
-						'/',
-						"%20",
-						"%22",
-						"%3c",		// <
-						"%253c",	// <
-						"%3e",		// >
-						"%0e",		// >
-						"%28",		// (
-						"%29",		// )
-						"%2528",	// (
-						"%26",		// &
-						"%24",		// $
-						"%3f",		// ?
-						"%3b",		// ;
-						"%3d"		// =
-					);
+				'<!--', '-->',
+				"'", '"',
+				'<', '>',
+				'&', '$',
+				'=',
+				';',
+				'?',
+				'/',
+				'!',
+				'#',
+				'%20',
+				'%22',
+				'%3c',		// <
+				'%253c',	// <
+				'%3e',		// >
+				'%0e',		// >
+				'%28',		// (
+				'%29',		// )
+				'%2528',	// (
+				'%26',		// &
+				'%24',		// $
+				'%3f',		// ?
+				'%3b',		// ;
+				'%3d'		// =
+			);
 
-		$filename = str_replace($bad, '', $filename);
-
-		return stripslashes($filename);
+		return stripslashes(str_replace($bad, '', $filename));
 	}
 
 	// --------------------------------------------------------------------
@@ -844,23 +823,23 @@
 			return FALSE;
 		}
 
-		if (function_exists('memory_get_usage') && memory_get_usage() && ini_get('memory_limit') != '')
+		if (memory_get_usage() && ($memory_limit = ini_get('memory_limit')))
 		{
-			$current = ini_get('memory_limit') * 1024 * 1024;
+			$memory_limit *= 1024 * 1024;
 
 			// There was a bug/behavioural change in PHP 5.2, where numbers over one million get output
-			// into scientific notation.  number_format() ensures this number is an integer
+			// into scientific notation. number_format() ensures this number is an integer
 			// http://bugs.php.net/bug.php?id=43053
 
-			$new_memory = number_format(ceil(filesize($file) + $current), 0, '.', '');
+			$memory_limit = number_format(ceil(filesize($file) + $memory_limit), 0, '.', '');
 
-			ini_set('memory_limit', $new_memory); // When an integer is used, the value is measured in bytes. - PHP.net
+			ini_set('memory_limit', $memory_limit); // When an integer is used, the value is measured in bytes. - PHP.net
 		}
 
 		// If the file being uploaded is an image, then we should have no problem with XSS attacks (in theory), but
 		// IE can be fooled into mime-type detecting a malformed image as an html file, thus executing an XSS attack on anyone
-		// using IE who looks at the image.  It does this by inspecting the first 255 bytes of an image.  To get around this
-		// CI will itself look at the first 255 bytes of an image to determine its relative safety.  This can save a lot of
+		// using IE who looks at the image. It does this by inspecting the first 255 bytes of an image. To get around this
+		// CI will itself look at the first 255 bytes of an image to determine its relative safety. This can save a lot of
 		// processor power and time if it is actually a clean image, as it will be in nearly all instances _except_ an
 		// attempted XSS attack.
 
@@ -878,10 +857,8 @@
 			// <a, <body, <head, <html, <img, <plaintext, <pre, <script, <table, <title
 			// title is basically just in SVG, but we filter it anyhow
 
-			if ( ! preg_match('/<(a|body|head|html|img|plaintext|pre|script|table|title)[\s>]/i', $opening_bytes))
-			{
-				return TRUE; // its an image, no "triggers" detected in the first 256 bytes, we're good
-			}
+			// if its an image or no "triggers" detected in the first 256 bytes - we're good
+			return ! preg_match('/<(a|body|head|html|img|plaintext|pre|script|table|title)[\s>]/i', $opening_bytes);
 		}
 
 		if (($data = @file_get_contents($file)) === FALSE)
@@ -910,14 +887,14 @@
 		{
 			foreach ($msg as $val)
 			{
-				$msg = ($CI->lang->line($val) == FALSE) ? $val : $CI->lang->line($val);
+				$msg = ($CI->lang->line($val) === FALSE) ? $val : $CI->lang->line($val);
 				$this->error_msg[] = $msg;
 				log_message('error', $msg);
 			}
 		}
 		else
 		{
-			$msg = ($CI->lang->line($msg) == FALSE) ? $msg : $CI->lang->line($msg);
+			$msg = ($CI->lang->line($msg) === FALSE) ? $msg : $CI->lang->line($msg);
 			$this->error_msg[] = $msg;
 			log_message('error', $msg);
 		}
@@ -934,7 +911,7 @@
 	 */
 	public function display_errors($open = '<p>', $close = '</p>')
 	{
-		return (count($this->error_msg) > 0) ? $open . implode($close . $open, $this->error_msg) . $close : '';
+		return (count($this->error_msg) > 0) ? $open.implode($close.$open, $this->error_msg).$close : '';
 	}
 
 	// --------------------------------------------------------------------
@@ -942,7 +919,7 @@
 	/**
 	 * List of Mime Types
 	 *
-	 * This is a list of mime types.  We use it to validate
+	 * This is a list of mime types. We use it to validate
 	 * the "allowed types" set by the developer
 	 *
 	 * @param	string
@@ -950,28 +927,7 @@
 	 */
 	public function mimes_types($mime)
 	{
-		global $mimes;
-
-		if (count($this->mimes) == 0)
-		{
-			if (defined('ENVIRONMENT') AND is_file(APPPATH.'config/'.ENVIRONMENT.'/mimes.php'))
-			{
-				include(APPPATH.'config/'.ENVIRONMENT.'/mimes.php');
-			}
-			elseif (is_file(APPPATH.'config/mimes.php'))
-			{
-				include(APPPATH.'config//mimes.php');
-			}
-			else
-			{
-				return FALSE;
-			}
-
-			$this->mimes = $mimes;
-			unset($mimes);
-		}
-
-		return ( ! isset($this->mimes[$mime])) ? FALSE : $this->mimes[$mime];
+		return isset($this->mimes[$mime]) ? $this->mimes[$mime] : FALSE;
 	}
 
 	// --------------------------------------------------------------------
@@ -987,7 +943,7 @@
 	 */
 	protected function _prep_filename($filename)
 	{
-		if (strpos($filename, '.') === FALSE OR $this->allowed_types == '*')
+		if (strpos($filename, '.') === FALSE OR $this->allowed_types === '*')
 		{
 			return $filename;
 		}
@@ -1008,9 +964,7 @@
 			}
 		}
 
-		$filename .= '.'.$ext;
-
-		return $filename;
+		return $filename.'.'.$ext;
 	}
 
 	// --------------------------------------------------------------------
@@ -1026,47 +980,104 @@
 	 */
 	protected function _file_mime_type($file)
 	{
-		// Use if the Fileinfo extension, if available (only versions above 5.3 support the FILEINFO_MIME_TYPE flag)
-		if ( (float) substr(phpversion(), 0, 3) >= 5.3 && function_exists('finfo_file'))
+		// We'll need this to validate the MIME info string (e.g. text/plain; charset=us-ascii)
+		$regexp = '/^([a-z\-]+\/[a-z0-9\-\.\+]+)(;\s.+)?$/';
+
+		/* Fileinfo extension - most reliable method
+		 *
+		 * Unfortunately, prior to PHP 5.3 - it's only available as a PECL extension and the
+		 * more convenient FILEINFO_MIME_TYPE flag doesn't exist.
+		 */
+		if (function_exists('finfo_file'))
 		{
-			$finfo = new finfo(FILEINFO_MIME_TYPE);
-			if ($finfo !== FALSE) // This is possible, if there is no magic MIME database file found on the system
+			$finfo = finfo_open(FILEINFO_MIME);
+			if (is_resource($finfo)) // It is possible that a FALSE value is returned, if there is no magic MIME database file found on the system
 			{
-				$file_type = $finfo->file($file['tmp_name']);
+				$mime = @finfo_file($finfo, $file['tmp_name']);
+				finfo_close($finfo);
 
 				/* According to the comments section of the PHP manual page,
 				 * it is possible that this function returns an empty string
 				 * for some files (e.g. if they don't exist in the magic MIME database)
 				 */
-				if (strlen($file_type) > 1)
+				if (is_string($mime) && preg_match($regexp, $mime, $matches))
 				{
-					$this->file_type = $file_type;
+					$this->file_type = $matches[1];
 					return;
 				}
 			}
 		}
 
-		// Fall back to the deprecated mime_content_type(), if available
+		/* This is an ugly hack, but UNIX-type systems provide a "native" way to detect the file type,
+		 * which is still more secure than depending on the value of $_FILES[$field]['type'], and as it
+		 * was reported in issue #750 (https://github.com/EllisLab/CodeIgniter/issues/750) - it's better
+		 * than mime_content_type() as well, hence the attempts to try calling the command line with
+		 * three different functions.
+		 *
+		 * Notes:
+		 *	- the DIRECTORY_SEPARATOR comparison ensures that we're not on a Windows system
+		 *	- many system admins would disable the exec(), shell_exec(), popen() and similar functions
+		 *	  due to security concerns, hence the function_exists() checks
+		 */
+		if (DIRECTORY_SEPARATOR !== '\\')
+		{
+			$cmd = 'file --brief --mime '.escapeshellarg($file['tmp_name']).' 2>&1';
+
+			if (function_exists('exec'))
+			{
+				/* This might look confusing, as $mime is being populated with all of the output when set in the second parameter.
+				 * However, we only neeed the last line, which is the actual return value of exec(), and as such - it overwrites
+				 * anything that could already be set for $mime previously. This effectively makes the second parameter a dummy
+				 * value, which is only put to allow us to get the return status code.
+				 */
+				$mime = @exec($cmd, $mime, $return_status);
+				if ($return_status === 0 && is_string($mime) && preg_match($regexp, $mime, $matches))
+				{
+					$this->file_type = $matches[1];
+					return;
+				}
+			}
+
+			if ( (bool) @ini_get('safe_mode') === FALSE && function_exists('shell_exec'))
+			{
+				$mime = @shell_exec($cmd);
+				if (strlen($mime) > 0)
+				{
+					$mime = explode("\n", trim($mime));
+					if (preg_match($regexp, $mime[(count($mime) - 1)], $matches))
+					{
+						$this->file_type = $matches[1];
+						return;
+					}
+				}
+			}
+
+			if (function_exists('popen'))
+			{
+				$proc = @popen($cmd, 'r');
+				if (is_resource($proc))
+				{
+					$mime = @fread($proc, 512);
+					@pclose($proc);
+					if ($mime !== FALSE)
+					{
+						$mime = explode("\n", trim($mime));
+						if (preg_match($regexp, $mime[(count($mime) - 1)], $matches))
+						{
+							$this->file_type = $matches[1];
+							return;
+						}
+					}
+				}
+			}
+		}
+
+		// Fall back to the deprecated mime_content_type(), if available (still better than $_FILES[$field]['type'])
 		if (function_exists('mime_content_type'))
 		{
 			$this->file_type = @mime_content_type($file['tmp_name']);
-			return;
-		}
-
-		/* This is an ugly hack, but UNIX-type systems provide a native way to detect the file type,
-		 * which is still more secure than depending on the value of $_FILES[$field]['type'].
-		 *
-		 * Notes:
-		 *	- a 'W' in the substr() expression bellow, would mean that we're using Windows
-		 *	- many system admins would disable the exec() function due to security concerns, hence the function_exists() check
-		 */
-		if (DIRECTORY_SEPARATOR !== '\\' && function_exists('exec'))
-		{
-			$output = array();
-			@exec('file --brief --mime-type ' . escapeshellarg($file['tmp_path']), $output, $return_code);
-			if ($return_code === 0 && strlen($output[0]) > 0) // A return status code != 0 would mean failed execution
+			if (strlen($this->file_type) > 0) // It's possible that mime_content_type() returns FALSE or an empty string
 			{
-				$this->file_type = rtrim($output[0]);
 				return;
 			}
 		}
@@ -1074,10 +1085,7 @@
 		$this->file_type = $file['type'];
 	}
 
-	// --------------------------------------------------------------------
-
 }
-// END Upload Class
 
 /* End of file Upload.php */
-/* Location: ./system/libraries/Upload.php */
+/* Location: ./system/libraries/Upload.php */
\ No newline at end of file
diff --git a/system/libraries/User_agent.php b/system/libraries/User_agent.php
index cd644c0..ff596f0 100644
--- a/system/libraries/User_agent.php
+++ b/system/libraries/User_agent.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * User Agent Class
  *
@@ -40,25 +38,110 @@
  */
 class CI_User_agent {
 
-	public $agent		= NULL;
+	/**
+	 * Current user-agent
+	 *
+	 * @var string
+	 */
+	public $agent = NULL;
 
-	public $is_browser	= FALSE;
-	public $is_robot	= FALSE;
-	public $is_mobile	= FALSE;
+	/**
+	 * Flag for if the user-agent belongs to a browser
+	 *
+	 * @var bool
+	 */
+	public $is_browser = FALSE;
 
-	public $languages	= array();
-	public $charsets	= array();
+	/**
+	 * Flag for if the user-agent is a robot
+	 *
+	 * @var bool
+	 */
+	public $is_robot = FALSE;
 
-	public $platforms	= array();
-	public $browsers	= array();
-	public $mobiles		= array();
-	public $robots		= array();
+	/**
+	 * Flag for if the user-agent is a mobile browser
+	 *
+	 * @var bool
+	 */
+	public $is_mobile = FALSE;
 
-	public $platform	= '';
-	public $browser		= '';
-	public $version		= '';
-	public $mobile		= '';
-	public $robot		= '';
+	/**
+	 * Languages accepted by the current user agent
+	 *
+	 * @var array
+	 */
+	public $languages = array();
+
+	/**
+	 * Character sets accepted by the current user agent
+	 *
+	 * @var array
+	 */
+	public $charsets = array();
+
+	/**
+	 * List of platforms to compare against current user agent
+	 *
+	 * @var array
+	 */
+	public $platforms = array();
+
+	/**
+	 * List of browsers to compare against current user agent
+	 *
+	 * @var array
+	 */
+	public $browsers = array();
+
+	/**
+	 * List of mobile browsers to compare against current user agent
+	 *
+	 * @var array
+	 */
+	public $mobiles = array();
+
+	/**
+	 * List of robots to compare against current user agent
+	 *
+	 * @var array
+	 */
+	public $robots = array();
+
+	/**
+	 * Current user-agent platform
+	 *
+	 * @var string
+	 */
+	public $platform = '';
+
+	/**
+	 * Current user-agent browser
+	 *
+	 * @var string
+	 */
+	public $browser = '';
+
+	/**
+	 * Current user-agent version
+	 *
+	 * @var string
+	 */
+	public $version = '';
+
+	/**
+	 * Current user-agent mobile name
+	 *
+	 * @var string
+	 */
+	public $mobile = '';
+
+	/**
+	 * Current user-agent robot name
+	 *
+	 * @var string
+	 */
+	public $robot = '';
 
 	/**
 	 * Constructor
@@ -74,15 +157,12 @@
 			$this->agent = trim($_SERVER['HTTP_USER_AGENT']);
 		}
 
-		if ( ! is_null($this->agent))
+		if ( ! is_null($this->agent) && $this->_load_agent_file())
 		{
-			if ($this->_load_agent_file())
-			{
-				$this->_compile_data();
-			}
+			$this->_compile_data();
 		}
 
-		log_message('debug', "User Agent Class Initialized");
+		log_message('debug', 'User Agent Class Initialized');
 	}
 
 	// --------------------------------------------------------------------
@@ -94,7 +174,7 @@
 	 */
 	protected function _load_agent_file()
 	{
-		if (defined('ENVIRONMENT') AND is_file(APPPATH.'config/'.ENVIRONMENT.'/user_agents.php'))
+		if (defined('ENVIRONMENT') && is_file(APPPATH.'config/'.ENVIRONMENT.'/user_agents.php'))
 		{
 			include(APPPATH.'config/'.ENVIRONMENT.'/user_agents.php');
 		}
@@ -165,22 +245,24 @@
 	/**
 	 * Set the Platform
 	 *
-	 * @return	mixed
+	 * @return	bool
 	 */
 	protected function _set_platform()
 	{
-		if (is_array($this->platforms) AND count($this->platforms) > 0)
+		if (is_array($this->platforms) && count($this->platforms) > 0)
 		{
 			foreach ($this->platforms as $key => $val)
 			{
-				if (preg_match("|".preg_quote($key)."|i", $this->agent))
+				if (preg_match('|'.preg_quote($key).'|i', $this->agent))
 				{
 					$this->platform = $val;
 					return TRUE;
 				}
 			}
 		}
+
 		$this->platform = 'Unknown Platform';
+		return FALSE;
 	}
 
 	// --------------------------------------------------------------------
@@ -192,11 +274,11 @@
 	 */
 	protected function _set_browser()
 	{
-		if (is_array($this->browsers) AND count($this->browsers) > 0)
+		if (is_array($this->browsers) && count($this->browsers) > 0)
 		{
 			foreach ($this->browsers as $key => $val)
 			{
-				if (preg_match("|".preg_quote($key).".*?([0-9\.]+)|i", $this->agent, $match))
+				if (preg_match('|'.preg_quote($key).'.*?([0-9\.]+)|i', $this->agent, $match))
 				{
 					$this->is_browser = TRUE;
 					$this->version = $match[1];
@@ -206,6 +288,7 @@
 				}
 			}
 		}
+
 		return FALSE;
 	}
 
@@ -218,11 +301,11 @@
 	 */
 	protected function _set_robot()
 	{
-		if (is_array($this->robots) AND count($this->robots) > 0)
+		if (is_array($this->robots) && count($this->robots) > 0)
 		{
 			foreach ($this->robots as $key => $val)
 			{
-				if (preg_match("|".preg_quote($key)."|i", $this->agent))
+				if (preg_match('|'.preg_quote($key).'|i', $this->agent))
 				{
 					$this->is_robot = TRUE;
 					$this->robot = $val;
@@ -230,6 +313,7 @@
 				}
 			}
 		}
+
 		return FALSE;
 	}
 
@@ -242,11 +326,11 @@
 	 */
 	protected function _set_mobile()
 	{
-		if (is_array($this->mobiles) AND count($this->mobiles) > 0)
+		if (is_array($this->mobiles) && count($this->mobiles) > 0)
 		{
 			foreach ($this->mobiles as $key => $val)
 			{
-				if (FALSE !== (strpos(strtolower($this->agent), $key)))
+				if (FALSE !== (stripos($this->agent, $key)))
 				{
 					$this->is_mobile = TRUE;
 					$this->mobile = $val;
@@ -254,6 +338,7 @@
 				}
 			}
 		}
+
 		return FALSE;
 	}
 
@@ -266,7 +351,7 @@
 	 */
 	protected function _set_languages()
 	{
-		if ((count($this->languages) === 0) AND isset($_SERVER['HTTP_ACCEPT_LANGUAGE']) AND $_SERVER['HTTP_ACCEPT_LANGUAGE'] != '')
+		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']))));
 		}
@@ -286,7 +371,7 @@
 	 */
 	protected function _set_charsets()
 	{
-		if ((count($this->charsets) === 0) AND isset($_SERVER['HTTP_ACCEPT_CHARSET']) AND $_SERVER['HTTP_ACCEPT_CHARSET'] != '')
+		if ((count($this->charsets) === 0) && ! empty($_SERVER['HTTP_ACCEPT_CHARSET']))
 		{
 			$this->charsets = explode(',', preg_replace('/(;q=.+)/i', '', strtolower(trim($_SERVER['HTTP_ACCEPT_CHARSET']))));
 		}
@@ -302,6 +387,7 @@
 	/**
 	 * Is Browser
 	 *
+	 * @param	string	$key
 	 * @return	bool
 	 */
 	public function is_browser($key = NULL)
@@ -318,7 +404,7 @@
 		}
 
 		// Check for a specific browser
-		return array_key_exists($key, $this->browsers) AND $this->browser === $this->browsers[$key];
+		return (isset($this->browsers[$key]) && $this->browser === $this->browsers[$key]);
 	}
 
 	// --------------------------------------------------------------------
@@ -326,6 +412,7 @@
 	/**
 	 * Is Robot
 	 *
+	 * @param	string	$key
 	 * @return	bool
 	 */
 	public function is_robot($key = NULL)
@@ -342,7 +429,7 @@
 		}
 
 		// Check for a specific robot
-		return array_key_exists($key, $this->robots) AND $this->robot === $this->robots[$key];
+		return (isset($this->robots[$key]) && $this->robot === $this->robots[$key]);
 	}
 
 	// --------------------------------------------------------------------
@@ -350,6 +437,7 @@
 	/**
 	 * Is Mobile
 	 *
+	 * @param	string	$key
 	 * @return	bool
 	 */
 	public function is_mobile($key = NULL)
@@ -366,7 +454,7 @@
 		}
 
 		// Check for a specific robot
-		return array_key_exists($key, $this->mobiles) AND $this->mobile === $this->mobiles[$key];
+		return (isset($this->mobiles[$key]) && $this->mobile === $this->mobiles[$key]);
 	}
 
 	// --------------------------------------------------------------------
@@ -378,7 +466,7 @@
 	 */
 	public function is_referral()
 	{
-		return ( ! isset($_SERVER['HTTP_REFERER']) OR $_SERVER['HTTP_REFERER'] == '') ? FALSE : TRUE;
+		return ! empty($_SERVER['HTTP_REFERER']);
 	}
 
 	// --------------------------------------------------------------------
@@ -461,7 +549,7 @@
 	 */
 	public function referrer()
 	{
-		return ( ! isset($_SERVER['HTTP_REFERER']) OR $_SERVER['HTTP_REFERER'] == '') ? '' : trim($_SERVER['HTTP_REFERER']);
+		return empty($_SERVER['HTTP_REFERER']) ? '' : trim($_SERVER['HTTP_REFERER']);
 	}
 
 	// --------------------------------------------------------------------
@@ -503,11 +591,12 @@
 	/**
 	 * Test for a particular language
 	 *
+	 * @param	string	$lang
 	 * @return	bool
 	 */
 	public function accept_lang($lang = 'en')
 	{
-		return (in_array(strtolower($lang), $this->languages(), TRUE));
+		return in_array(strtolower($lang), $this->languages(), TRUE);
 	}
 
 	// --------------------------------------------------------------------
@@ -515,14 +604,15 @@
 	/**
 	 * Test for a particular character set
 	 *
+	 * @param	string	$charset
 	 * @return	bool
 	 */
 	public function accept_charset($charset = 'utf-8')
 	{
-		return (in_array(strtolower($charset), $this->charsets(), TRUE));
+		return in_array(strtolower($charset), $this->charsets(), TRUE);
 	}
 
 }
 
 /* End of file User_agent.php */
-/* Location: ./system/libraries/User_agent.php */
+/* Location: ./system/libraries/User_agent.php */
\ No newline at end of file
diff --git a/system/libraries/Xmlrpc.php b/system/libraries/Xmlrpc.php
index 730a0fc..6f35423 100644
--- a/system/libraries/Xmlrpc.php
+++ b/system/libraries/Xmlrpc.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -25,14 +25,6 @@
  * @filesource
  */
 
-if ( ! function_exists('xml_parser_create'))
-{
-	show_error('Your PHP installation does not support XML');
-}
-
-
-// ------------------------------------------------------------------------
-
 /**
  * XML-RPC request handler class
  *
@@ -42,6 +34,14 @@
  * @author		EllisLab Dev Team
  * @link		http://codeigniter.com/user_guide/libraries/xmlrpc.html
  */
+
+if ( ! function_exists('xml_parser_create'))
+{
+	show_error('Your PHP installation does not support XML');
+}
+
+// ------------------------------------------------------------------------
+
 class CI_Xmlrpc {
 
 	public $debug		= FALSE;	// Debugging on or off
@@ -77,13 +77,17 @@
 
 	public $xss_clean		= TRUE;
 
-	//-------------------------------------
-	//  VALUES THAT MULTIPLE CLASSES NEED
-	//-------------------------------------
 
+	/**
+	 * Constructor
+	 *
+	 * Initializes property default values
+	 *
+	 * @param	array
+	 * @return	void
+	 */
 	public function __construct($config = array())
 	{
-		$this->xmlrpcName	= $this->xmlrpcName;
 		$this->xmlrpc_backslash = chr(92).chr(92);
 
 		// Types for info sent back and forth
@@ -100,24 +104,24 @@
 			);
 
 		// Array of Valid Parents for Various XML-RPC elements
-		$this->valid_parents = array('BOOLEAN'			=> array('VALUE'),
-						'I4'				=> array('VALUE'),
-						'INT'				=> array('VALUE'),
-						'STRING'			=> array('VALUE'),
-						'DOUBLE'			=> array('VALUE'),
-						'DATETIME.ISO8601'	=> array('VALUE'),
-						'BASE64'			=> array('VALUE'),
-						'ARRAY'			=> array('VALUE'),
-						'STRUCT'			=> array('VALUE'),
-						'PARAM'			=> array('PARAMS'),
-						'METHODNAME'		=> array('METHODCALL'),
-						'PARAMS'			=> array('METHODCALL', 'METHODRESPONSE'),
-						'MEMBER'			=> array('STRUCT'),
-						'NAME'				=> array('MEMBER'),
-						'DATA'				=> array('ARRAY'),
-						'FAULT'			=> array('METHODRESPONSE'),
-						'VALUE'			=> array('MEMBER', 'DATA', 'PARAM', 'FAULT')
-					 );
+		$this->valid_parents = array('BOOLEAN' => array('VALUE'),
+			'I4'				=> array('VALUE'),
+			'INT'				=> array('VALUE'),
+			'STRING'			=> array('VALUE'),
+			'DOUBLE'			=> array('VALUE'),
+			'DATETIME.ISO8601'	=> array('VALUE'),
+			'BASE64'			=> array('VALUE'),
+			'ARRAY'			=> array('VALUE'),
+			'STRUCT'			=> array('VALUE'),
+			'PARAM'			=> array('PARAMS'),
+			'METHODNAME'		=> array('METHODCALL'),
+			'PARAMS'			=> array('METHODCALL', 'METHODRESPONSE'),
+			'MEMBER'			=> array('STRUCT'),
+			'NAME'				=> array('MEMBER'),
+			'DATA'				=> array('ARRAY'),
+			'FAULT'			=> array('METHODRESPONSE'),
+			'VALUE'			=> array('MEMBER', 'DATA', 'PARAM', 'FAULT')
+		 );
 
 
 		// XML-RPC Responses
@@ -136,14 +140,17 @@
 
 		$this->initialize($config);
 
-		log_message('debug', "XML-RPC Class Initialized");
+		log_message('debug', 'XML-RPC Class Initialized');
 	}
 
+	// --------------------------------------------------------------------
 
-	//-------------------------------------
-	//  Initialize Prefs
-	//-------------------------------------
-
+	/**
+	 * Initialize
+	 *
+	 * @param	array
+	 * @return	void
+	 */
 	public function initialize($config = array())
 	{
 		if (count($config) > 0)
@@ -157,36 +164,43 @@
 			}
 		}
 	}
-	// END
 
-	//-------------------------------------
-	//  Take URL and parse it
-	//-------------------------------------
+	// --------------------------------------------------------------------
 
-	public function server($url, $port=80)
+	/**
+	 * Parse server URL
+	 *
+	 * @param	string	url
+	 * @param	int	port
+	 * @return	void
+	 */
+	public function server($url, $port = 80)
 	{
 		if (strpos($url, 'http') !== 0)
 		{
-			$url = "http://".$url;
+			$url = 'http://'.$url;
 		}
 
 		$parts = parse_url($url);
 
-		$path = ( ! isset($parts['path'])) ? '/' : $parts['path'];
+		$path = isset($parts['path']) ? $parts['path'] : '/';
 
-		if (isset($parts['query']) && $parts['query'] != '')
+		if ( ! empty($parts['query']))
 		{
 			$path .= '?'.$parts['query'];
 		}
 
 		$this->client = new XML_RPC_Client($path, $parts['host'], $port);
 	}
-	// END
 
-	//-------------------------------------
-	//  Set Timeout
-	//-------------------------------------
+	// --------------------------------------------------------------------
 
+	/**
+	 * Set Timeout
+	 *
+	 * @param	int	seconds
+	 * @return	void
+	 */
 	public function timeout($seconds = 5)
 	{
 		if ( ! is_null($this->client) && is_int($seconds))
@@ -194,27 +208,34 @@
 			$this->client->timeout = $seconds;
 		}
 	}
-	// END
 
-	//-------------------------------------
-	//  Set Methods
-	//-------------------------------------
+	// --------------------------------------------------------------------
 
+	/**
+	 * Set Methods
+	 *
+	 * @param	string	method name
+	 * @return	void
+	 */
 	public function method($function)
 	{
 		$this->method = $function;
 	}
-	// END
 
-	//-------------------------------------
-	//  Take Array of Data and Create Objects
-	//-------------------------------------
+	// --------------------------------------------------------------------
 
+	/**
+	 * Take Array of Data and Create Objects
+	 *
+	 * @param	array
+	 * @return	void
+	 */
 	public function request($incoming)
 	{
 		if ( ! is_array($incoming))
 		{
 			// Send Error
+			return;
 		}
 
 		$this->data = array();
@@ -224,33 +245,39 @@
 			$this->data[$key] = $this->values_parsing($value);
 		}
 	}
-	// END
 
+	// --------------------------------------------------------------------
 
-	//-------------------------------------
-	//  Set Debug
-	//-------------------------------------
-
+	/**
+	 * Set Debug
+	 *
+	 * @param	bool
+	 * @return	void
+	 */
 	public function set_debug($flag = TRUE)
 	{
-		$this->debug = ($flag == TRUE);
+		$this->debug = ($flag === TRUE);
 	}
 
-	//-------------------------------------
-	//  Values Parsing
-	//-------------------------------------
+	// --------------------------------------------------------------------
 
-	public function values_parsing($value, $return = FALSE)
+	/**
+	 * Values Parsing
+	 *
+	 * @param	mixed
+	 * @return	object
+	 */
+	public function values_parsing($value)
 	{
 		if (is_array($value) && array_key_exists(0, $value))
 		{
-			if ( ! isset($value[1]) OR ( ! isset($this->xmlrpcTypes[$value[1]])))
+			if ( ! isset($value[1], $this->xmlrpcTypes[$value[1]]))
 			{
 				$temp = new XML_RPC_Values($value[0], (is_array($value[0]) ? 'array' : 'string'));
 			}
 			else
 			{
-				if (is_array($value[0]) && ($value[1] == 'struct' OR $value[1] == 'array'))
+				if (is_array($value[0]) && ($value[1] === 'struct' OR $value[1] === 'array'))
 				{
 					while (list($k) = each($value[0]))
 					{
@@ -268,16 +295,17 @@
 
 		return $temp;
 	}
-	// END
 
+	// --------------------------------------------------------------------
 
-	//-------------------------------------
-	//  Sends XML-RPC Request
-	//-------------------------------------
-
+	/**
+	 * Sends XML-RPC Request
+	 *
+	 * @return	bool
+	 */
 	public function send_request()
 	{
-		$this->message = new XML_RPC_Message($this->method,$this->data);
+		$this->message = new XML_RPC_Message($this->method, $this->data);
 		$this->message->debug = $this->debug;
 
 		if ( ! $this->result = $this->client->send($this->message) OR ! is_object($this->result->val))
@@ -289,55 +317,62 @@
 		$this->response = $this->result->decode();
 		return TRUE;
 	}
-	// END
 
-	//-------------------------------------
-	//  Returns Error
-	//-------------------------------------
+	// --------------------------------------------------------------------
 
+	/**
+	 * Returns Error
+	 *
+	 * @return	string
+	 */
 	public function display_error()
 	{
 		return $this->error;
 	}
-	// END
 
-	//-------------------------------------
-	//  Returns Remote Server Response
-	//-------------------------------------
+	// --------------------------------------------------------------------
 
+	/**
+	 * Returns Remote Server Response
+	 *
+	 * @return	string
+	 */
 	public function display_response()
 	{
 		return $this->response;
 	}
-	// END
 
-	//-------------------------------------
-	//  Sends an Error Message for Server Request
-	//-------------------------------------
+	// --------------------------------------------------------------------
 
+	/**
+	 * Sends an Error Message for Server Request
+	 *
+	 * @param	int
+	 * @param	string
+	 * @return	object
+	 */
 	public function send_error_message($number, $message)
 	{
 		return new XML_RPC_Response(0, $number, $message);
 	}
-	// END
 
+	// --------------------------------------------------------------------
 
-	//-------------------------------------
-	//  Send Response for Server Request
-	//-------------------------------------
-
+	/**
+	 * Send Response for Server Request
+	 *
+	 * @param	array
+	 * @return	object
+	 */
 	public function send_response($response)
 	{
 		// $response should be array of values, which will be parsed
 		// based on their data and type into a valid group of XML-RPC values
 		return new XML_RPC_Response($this->values_parsing($response));
 	}
-	// END
 
 } // END XML_RPC Class
 
-
-
 /**
  * XML-RPC Client class
  *
@@ -355,7 +390,15 @@
 	public $timeout		= 5;
 	public $no_multicall	= FALSE;
 
-	public function __construct($path, $server, $port=80)
+	/**
+	 * Constructor
+	 *
+	 * @param	string
+	 * @param	object
+	 * @param	int
+	 * @return	void
+	 */
+	public function __construct($path, $server, $port = 80)
 	{
 		parent::__construct();
 
@@ -364,27 +407,41 @@
 		$this->path = $path;
 	}
 
+	// --------------------------------------------------------------------
+
+	/**
+	 * Send message
+	 *
+	 * @param	mixed
+	 * @return	object
+	 */
 	public function send($msg)
 	{
 		if (is_array($msg))
 		{
 			// Multi-call disabled
-			$r = new XML_RPC_Response(0, $this->xmlrpcerr['multicall_recursion'],$this->xmlrpcstr['multicall_recursion']);
-			return $r;
+			return new XML_RPC_Response(0, $this->xmlrpcerr['multicall_recursion'], $this->xmlrpcstr['multicall_recursion']);
 		}
 
 		return $this->sendPayload($msg);
 	}
 
+	// --------------------------------------------------------------------
+
+	/**
+	 * Send payload
+	 *
+	 * @param	object
+	 * @return	object
+	 */
 	public function sendPayload($msg)
 	{
-		$fp = @fsockopen($this->server, $this->port,$this->errno, $this->errstr, $this->timeout);
+		$fp = @fsockopen($this->server, $this->port,$this->errno, $this->errstring, $this->timeout);
 
 		if ( ! is_resource($fp))
 		{
 			error_log($this->xmlrpcstr['http_error']);
-			$r = new XML_RPC_Response(0, $this->xmlrpcerr['http_error'],$this->xmlrpcstr['http_error']);
-			return $r;
+			return new XML_RPC_Response(0, $this->xmlrpcerr['http_error'], $this->xmlrpcstr['http_error']);
 		}
 
 		if (empty($msg->payload))
@@ -394,27 +451,25 @@
 		}
 
 		$r = "\r\n";
-		$op = "POST {$this->path} HTTP/1.0$r"
-			. "Host: {$this->server}$r"
-			. "Content-Type: text/xml$r"
-			. "User-Agent: {$this->xmlrpcName}$r"
-			. "Content-Length: ".strlen($msg->payload)."$r$r"
-			. $msg->payload;
+		$op = 'POST '.$this->path.' HTTP/1.0'.$r
+			.'Host: '.$this->server.$r
+			.'Content-Type: text/xml'.$r
+			.'User-Agent: '.$this->xmlrpcName.$r
+			.'Content-Length: '.strlen($msg->payload).$r.$r
+			.$msg->payload;
 
-
-		if ( ! fputs($fp, $op, strlen($op)))
+		if ( ! fwrite($fp, $op, strlen($op)))
 		{
 			error_log($this->xmlrpcstr['http_error']);
-			$r = new XML_RPC_Response(0, $this->xmlrpcerr['http_error'], $this->xmlrpcstr['http_error']);
-			return $r;
+			return new XML_RPC_Response(0, $this->xmlrpcerr['http_error'], $this->xmlrpcstr['http_error']);
 		}
+
 		$resp = $msg->parseResponse($fp);
 		fclose($fp);
 		return $resp;
 	}
 
-}
-// end class XML_RPC_Client
+} // END XML_RPC_Client Class
 
 /**
  * XML-RPC Response class
@@ -425,31 +480,34 @@
  */
 class XML_RPC_Response
 {
-	public $val = 0;
-	public $errno = 0;
-	public $errstr = '';
-	public $headers = array();
-	public $xss_clean = TRUE;
+	public $val		= 0;
+	public $errno		= 0;
+	public $errstr		= '';
+	public $headers		= array();
+	public $xss_clean	= TRUE;
 
+	/**
+	 * Constructor
+	 *
+	 * @param	mixed
+	 * @param	int
+	 * @param	string
+	 * @return	void
+	 */
 	public function __construct($val, $code = 0, $fstr = '')
 	{
-		if ($code != 0)
+		if ($code !== 0)
 		{
 			// error
 			$this->errno = $code;
-			if ( ! is_php('5.4'))
-			{
-				$this->errstr = htmlspecialchars($fstr, ENT_NOQUOTES, 'UTF-8');
-			}
-			else
-			{
-				$this->errstr = htmlspecialchars($fstr, ENT_XML1 | ENT_NOQUOTES, 'UTF-8');
-			}
+			$this->errstr = htmlspecialchars($fstr,
+							(is_php('5.4') ? ENT_XML1 | ENT_NOQUOTES : ENT_NOQUOTES),
+							'UTF-8');
 		}
-		else if ( ! is_object($val))
+		elseif ( ! is_object($val))
 		{
 			// programmer error, not an object
-			error_log("Invalid type '" . gettype($val) . "' (value: $val) passed to XML_RPC_Response.  Defaulting to empty value.");
+			error_log("Invalid type '".gettype($val)."' (value: ".$val.') passed to XML_RPC_Response. Defaulting to empty value.');
 			$this->val = new XML_RPC_Values();
 		}
 		else
@@ -458,43 +516,79 @@
 		}
 	}
 
+	// --------------------------------------------------------------------
+
+	/**
+	 * Fault code
+	 *
+	 * @return	int
+	 */
 	public function faultCode()
 	{
 		return $this->errno;
 	}
 
+	// --------------------------------------------------------------------
+
+	/**
+	 * Fault string
+	 *
+	 * @return	string
+	 */
 	public function faultString()
 	{
 		return $this->errstr;
 	}
 
+	// --------------------------------------------------------------------
+
+	/**
+	 * Value
+	 *
+	 * @return	mixed
+	 */
 	public function value()
 	{
 		return $this->val;
 	}
 
+	// --------------------------------------------------------------------
+
+	/**
+	 * Prepare response
+	 *
+	 * @return	string	xml
+	 */
 	public function prepare_response()
 	{
 		return "<methodResponse>\n"
-			. ($this->errno
-			? '<fault>
+			.($this->errno
+				? '<fault>
 	<value>
 		<struct>
 			<member>
 				<name>faultCode</name>
-				<value><int>' . $this->errno . '</int></value>
+				<value><int>'.$this->errno.'</int></value>
 			</member>
 			<member>
 				<name>faultString</name>
-				<value><string>' . $this->errstr . '</string></value>
+				<value><string>'.$this->errstr.'</string></value>
 			</member>
 		</struct>
 	</value>
 </fault>'
-			: "<params>\n<param>\n".$this->val->serialize_class()."</param>\n</params>")
-			. "\n</methodResponse>";
+				: "<params>\n<param>\n".$this->val->serialize_class()."</param>\n</params>")
+			."\n</methodResponse>";
 	}
 
+	// --------------------------------------------------------------------
+
+	/**
+	 * Decode
+	 *
+	 * @param	mixed
+	 * @return	array
+	 */
 	public function decode($array = FALSE)
 	{
 		$CI =& get_instance();
@@ -513,40 +607,40 @@
 				}
 			}
 
-			$result = $array;
+			return $array;
+		}
+
+		$result = $this->xmlrpc_decoder($this->val);
+
+		if (is_array($result))
+		{
+			$result = $this->decode($result);
 		}
 		else
 		{
-			$result = $this->xmlrpc_decoder($this->val);
-
-			if (is_array($result))
-			{
-				$result = $this->decode($result);
-			}
-			else
-			{
-				$result = ($this->xss_clean) ? $CI->security->xss_clean($result) : $result;
-			}
+			$result = ($this->xss_clean) ? $CI->security->xss_clean($result) : $result;
 		}
 
 		return $result;
 	}
 
+	// --------------------------------------------------------------------
 
-
-	//-------------------------------------
-	//  XML-RPC Object to PHP Types
-	//-------------------------------------
-
+	/**
+	 * XML-RPC Object to PHP Types
+	 *
+	 * @param	object
+	 * @return	array
+	 */
 	public function xmlrpc_decoder($xmlrpc_val)
 	{
 		$kind = $xmlrpc_val->kindOf();
 
-		if ($kind == 'scalar')
+		if ($kind === 'scalar')
 		{
 			return $xmlrpc_val->scalarval();
 		}
-		elseif ($kind == 'array')
+		elseif ($kind === 'array')
 		{
 			reset($xmlrpc_val->me);
 			$b = current($xmlrpc_val->me);
@@ -558,7 +652,7 @@
 			}
 			return $arr;
 		}
-		elseif ($kind == 'struct')
+		elseif ($kind === 'struct')
 		{
 			reset($xmlrpc_val->me['struct']);
 			$arr = array();
@@ -571,25 +665,28 @@
 		}
 	}
 
+	// --------------------------------------------------------------------
 
-	//-------------------------------------
-	//  ISO-8601 time to server or UTC time
-	//-------------------------------------
-
-	public function iso8601_decode($time, $utc = 0)
+	/**
+	 * ISO-8601 time to server or UTC time
+	 *
+	 * @param	string
+	 * @param	bool
+	 * @return	int	unix timestamp
+	 */
+	public function iso8601_decode($time, $utc = FALSE)
 	{
-		// return a timet in the localtime, or UTC
+		// return a time in the localtime, or UTC
 		$t = 0;
 		if (preg_match('/([0-9]{4})([0-9]{2})([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})/', $time, $regs))
 		{
-			$fnc = ($utc == 1) ? 'gmmktime' : 'mktime';
+			$fnc = ($utc === TRUE) ? 'gmmktime' : 'mktime';
 			$t = $fnc($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
 		}
 		return $t;
 	}
 
-}
-// End Response Class
+} // END XML_RPC_Response Class
 
 /**
  * XML-RPC Message class
@@ -602,10 +699,17 @@
 {
 	public $payload;
 	public $method_name;
-	public $params			= array();
-	public $xh				= array();
+	public $params		= array();
+	public $xh		= array();
 
-	public function __construct($method, $pars=0)
+	/**
+	 * Constructor
+	 *
+	 * @param	string	method name
+	 * @param	array
+	 * @return	void
+	 */
+	public function __construct($method, $pars = FALSE)
 	{
 		parent::__construct();
 
@@ -620,15 +724,18 @@
 		}
 	}
 
-	//-------------------------------------
-	//  Create Payload to Send
-	//-------------------------------------
+	// --------------------------------------------------------------------
 
+	/**
+	 * Create Payload to Send
+	 *
+	 * @return	void
+	 */
 	public function createPayload()
 	{
-		$this->payload = "<?xml version=\"1.0\"?".">\r\n<methodCall>\r\n"
-				. '<methodName>'.$this->method_name."</methodName>\r\n"
-				. "<params>\r\n";
+		$this->payload = '<?xml version="1.0"?'.">\r\n<methodCall>\r\n"
+				.'<methodName>'.$this->method_name."</methodName>\r\n"
+				."<params>\r\n";
 
 		for ($i = 0, $c = count($this->params); $i < $c; $i++)
 		{
@@ -640,10 +747,14 @@
 		$this->payload .= "</params>\r\n</methodCall>\r\n";
 	}
 
-	//-------------------------------------
-	//  Parse External XML-RPC Server's Response
-	//-------------------------------------
+	// --------------------------------------------------------------------
 
+	/**
+	 * Parse External XML-RPC Server's Response
+	 *
+	 * @param	resource
+	 * @return	object
+	 */
 	public function parseResponse($fp)
 	{
 		$data = '';
@@ -653,36 +764,24 @@
 			$data .= $datum;
 		}
 
-		//-------------------------------------
-		//  DISPLAY HTTP CONTENT for DEBUGGING
-		//-------------------------------------
-
+		// Display HTTP content for debugging
 		if ($this->debug === TRUE)
 		{
 			echo "<pre>---DATA---\n".htmlspecialchars($data)."\n---END DATA---\n\n</pre>";
 		}
 
-		//-------------------------------------
-		//  Check for data
-		//-------------------------------------
-
+		// Check for data
 		if ($data === '')
 		{
 			error_log($this->xmlrpcstr['no_data']);
-			$r = new XML_RPC_Response(0, $this->xmlrpcerr['no_data'], $this->xmlrpcstr['no_data']);
-			return $r;
+			return new XML_RPC_Response(0, $this->xmlrpcerr['no_data'], $this->xmlrpcstr['no_data']);
 		}
 
-
-		//-------------------------------------
-		//  Check for HTTP 200 Response
-		//-------------------------------------
-
+		// Check for HTTP 200 Response
 		if (strncmp($data, 'HTTP', 4) === 0 && ! preg_match('/^HTTP\/[0-9\.]+ 200 /', $data))
 		{
-			$errstr= substr($data, 0, strpos($data, "\n")-1);
-			$r = new XML_RPC_Response(0, $this->xmlrpcerr['http_error'], $this->xmlrpcstr['http_error']. ' (' . $errstr . ')');
-			return $r;
+			$errstr = substr($data, 0, strpos($data, "\n")-1);
+			return new XML_RPC_Response(0, $this->xmlrpcerr['http_error'], $this->xmlrpcstr['http_error'].' ('.$errstr.')');
 		}
 
 		//-------------------------------------
@@ -692,25 +791,21 @@
 		$parser = xml_parser_create($this->xmlrpc_defencoding);
 
 		$this->xh[$parser] = array(
-						'isf' =>	0,
-						'ac' =>		'',
-						'headers' =>	array(),
-						'stack' =>	array(),
-						'valuestack' =>	array(),
-						'isf_reason' =>	0
+						'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);
+		xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, TRUE);
 		xml_set_element_handler($parser, 'open_tag', 'closing_tag');
 		xml_set_character_data_handler($parser, 'character_data');
 		//xml_set_default_handler($parser, 'default_handler');
 
-
-		//-------------------------------------
-		//  GET HEADERS
-		//-------------------------------------
-
+		// Get headers
 		$lines = explode("\r\n", $data);
 		while (($line = array_shift($lines)))
 		{
@@ -722,16 +817,12 @@
 		}
 		$data = implode("\r\n", $lines);
 
-
-		//-------------------------------------
-		//  PARSE XML DATA
-		//-------------------------------------
-
+		// Parse XML data
 		if ( ! xml_parse($parser, $data, count($data)))
 		{
 			$errstr = sprintf('XML error: %s at line %d',
-					xml_error_string(xml_get_error_code($parser)),
-					xml_get_current_line_number($parser));
+						xml_error_string(xml_get_error_code($parser)),
+						xml_get_current_line_number($parser));
 			//error_log($errstr);
 			$r = new XML_RPC_Response(0, $this->xmlrpcerr['invalid_return'], $this->xmlrpcstr['invalid_return']);
 			xml_parser_free($parser);
@@ -739,10 +830,7 @@
 		}
 		xml_parser_free($parser);
 
-		// ---------------------------------------
-		//  Got Ourselves Some Badness, It Seems
-		// ---------------------------------------
-
+		// Got ourselves some badness, it seems
 		if ($this->xh[$parser]['isf'] > 1)
 		{
 			if ($this->debug === TRUE)
@@ -750,29 +838,24 @@
 				echo "---Invalid Return---\n".$this->xh[$parser]['isf_reason']."---Invalid Return---\n\n";
 			}
 
-			$r = new XML_RPC_Response(0, $this->xmlrpcerr['invalid_return'],$this->xmlrpcstr['invalid_return'].' '.$this->xh[$parser]['isf_reason']);
-			return $r;
+			return new XML_RPC_Response(0, $this->xmlrpcerr['invalid_return'], $this->xmlrpcstr['invalid_return'].' '.$this->xh[$parser]['isf_reason']);
 		}
 		elseif ( ! is_object($this->xh[$parser]['value']))
 		{
-			$r = new XML_RPC_Response(0, $this->xmlrpcerr['invalid_return'],$this->xmlrpcstr['invalid_return'].' '.$this->xh[$parser]['isf_reason']);
-			return $r;
+			return new XML_RPC_Response(0, $this->xmlrpcerr['invalid_return'], $this->xmlrpcstr['invalid_return'].' '.$this->xh[$parser]['isf_reason']);
 		}
 
-		//-------------------------------------
-		//  DISPLAY XML CONTENT for DEBUGGING
-		//-------------------------------------
-
+		// Display XML content for debugging
 		if ($this->debug === TRUE)
 		{
-			echo "<pre>";
+			echo '<pre>';
 
 			if (count($this->xh[$parser]['headers'] > 0))
 			{
 				echo "---HEADERS---\n";
 				foreach ($this->xh[$parser]['headers'] as $header)
 				{
-					echo "$header\n";
+					echo $header."\n";
 				}
 				echo "---END HEADERS---\n\n";
 			}
@@ -782,10 +865,7 @@
 			echo "\n---END PARSED---</pre>";
 		}
 
-		//-------------------------------------
-		//  SEND RESPONSE
-		//-------------------------------------
-
+		// Send response
 		$v = $this->xh[$parser]['value'];
 		if ($this->xh[$parser]['isf'])
 		{
@@ -793,7 +873,7 @@
 			$errstr_v = $v->me['struct']['faultString'];
 			$errno = $errno_v->scalarval();
 
-			if ($errno == 0)
+			if ($errno === 0)
 			{
 				// FAULT returned, errno needs to reflect that
 				$errno = -1;
@@ -810,6 +890,8 @@
 		return $r;
 	}
 
+	// --------------------------------------------------------------------
+
 	// ------------------------------------
 	//  Begin Return Message Parsing section
 	// ------------------------------------
@@ -824,63 +906,61 @@
 	//	 stack - array with parent tree of the xml element,
 	//			 used to validate the nesting of elements
 
-	//-------------------------------------
-	//  Start Element Handler
-	//-------------------------------------
+	// --------------------------------------------------------------------
 
-	public function open_tag($the_parser, $name, $attrs)
+	/**
+	 * Start Element Handler
+	 *
+	 * @param	string
+	 * @param	string
+	 * @return	void
+	 */
+	public function open_tag($the_parser, $name)
 	{
 		// If invalid nesting, then return
 		if ($this->xh[$the_parser]['isf'] > 1) return;
 
 		// Evaluate and check for correct nesting of XML elements
-
-		if (count($this->xh[$the_parser]['stack']) == 0)
+		if (count($this->xh[$the_parser]['stack']) === 0)
 		{
-			if ($name != 'METHODRESPONSE' && $name != 'METHODCALL')
+			if ($name !== 'METHODRESPONSE' && $name !== 'METHODCALL')
 			{
 				$this->xh[$the_parser]['isf'] = 2;
 				$this->xh[$the_parser]['isf_reason'] = 'Top level XML-RPC element is missing';
 				return;
 			}
 		}
-		else
+		// not top level element: see if parent is OK
+		elseif ( ! in_array($this->xh[$the_parser]['stack'][0], $this->valid_parents[$name], TRUE))
 		{
-			// not top level element: see if parent is OK
-			if ( ! in_array($this->xh[$the_parser]['stack'][0], $this->valid_parents[$name], TRUE))
-			{
-				$this->xh[$the_parser]['isf'] = 2;
-				$this->xh[$the_parser]['isf_reason'] = "XML-RPC element $name cannot be child of ".$this->xh[$the_parser]['stack'][0];
-				return;
-			}
+			$this->xh[$the_parser]['isf'] = 2;
+			$this->xh[$the_parser]['isf_reason'] = 'XML-RPC element $name cannot be child of '.$this->xh[$the_parser]['stack'][0];
+			return;
 		}
 
-		switch($name)
+		switch ($name)
 		{
 			case 'STRUCT':
 			case 'ARRAY':
 				// Creates array for child elements
-
-				$cur_val = array('value' => array(),
-								 'type'	 => $name);
-
+				$cur_val = array('value' => array(), 'type' => $name);
 				array_unshift($this->xh[$the_parser]['valuestack'], $cur_val);
-			break;
+				break;
 			case 'METHODNAME':
 			case 'NAME':
 				$this->xh[$the_parser]['ac'] = '';
-			break;
+				break;
 			case 'FAULT':
 				$this->xh[$the_parser]['isf'] = 1;
-			break;
+				break;
 			case 'PARAM':
 				$this->xh[$the_parser]['value'] = NULL;
-			break;
+				break;
 			case 'VALUE':
 				$this->xh[$the_parser]['vt'] = 'value';
 				$this->xh[$the_parser]['ac'] = '';
 				$this->xh[$the_parser]['lv'] = 1;
-			break;
+				break;
 			case 'I4':
 			case 'INT':
 			case 'STRING':
@@ -888,70 +968,74 @@
 			case 'DOUBLE':
 			case 'DATETIME.ISO8601':
 			case 'BASE64':
-				if ($this->xh[$the_parser]['vt'] != 'value')
+				if ($this->xh[$the_parser]['vt'] !== 'value')
 				{
 					//two data elements inside a value: an error occurred!
 					$this->xh[$the_parser]['isf'] = 2;
-					$this->xh[$the_parser]['isf_reason'] = "'Twas a $name element following a ".$this->xh[$the_parser]['vt']." element inside a single value";
+					$this->xh[$the_parser]['isf_reason'] = "'Twas a ".$name.' element following a '
+										.$this->xh[$the_parser]['vt'].' element inside a single value';
 					return;
 				}
 
 				$this->xh[$the_parser]['ac'] = '';
-			break;
+				break;
 			case 'MEMBER':
 				// Set name of <member> to nothing to prevent errors later if no <name> is found
 				$this->xh[$the_parser]['valuestack'][0]['name'] = '';
 
 				// Set NULL value to check to see if value passed for this param/member
 				$this->xh[$the_parser]['value'] = NULL;
-			break;
+				break;
 			case 'DATA':
 			case 'METHODCALL':
 			case 'METHODRESPONSE':
 			case 'PARAMS':
 				// valid elements that add little to processing
-			break;
+				break;
 			default:
 				/// An Invalid Element is Found, so we have trouble
 				$this->xh[$the_parser]['isf'] = 2;
-				$this->xh[$the_parser]['isf_reason'] = "Invalid XML-RPC element found: $name";
-			break;
+				$this->xh[$the_parser]['isf_reason'] = 'Invalid XML-RPC element found: '.$name;
+				break;
 		}
 
 		// Add current element name to stack, to allow validation of nesting
 		array_unshift($this->xh[$the_parser]['stack'], $name);
 
-		if ($name != 'VALUE') $this->xh[$the_parser]['lv'] = 0;
+		$name === 'VALUE' OR $this->xh[$the_parser]['lv'] = 0;
 	}
-	// END
 
+	// --------------------------------------------------------------------
 
-	//-------------------------------------
-	//  End Element Handler
-	//-------------------------------------
-
+	/**
+	 * End Element Handler
+	 *
+	 * @param	string
+	 * @param	string
+	 * @return	void
+	 */
 	public function closing_tag($the_parser, $name)
 	{
 		if ($this->xh[$the_parser]['isf'] > 1) return;
 
 		// Remove current element from stack and set variable
 		// NOTE: If the XML validates, then we do not have to worry about
-		// the opening and closing of elements.  Nesting is checked on the opening
+		// the opening and closing of elements. Nesting is checked on the opening
 		// tag so we be safe there as well.
 
 		$curr_elem = array_shift($this->xh[$the_parser]['stack']);
 
-		switch($name)
+		switch ($name)
 		{
 			case 'STRUCT':
 			case 'ARRAY':
 				$cur_val = array_shift($this->xh[$the_parser]['valuestack']);
-				$this->xh[$the_parser]['value'] = ( ! isset($cur_val['values'])) ? array() : $cur_val['values'];
+				$this->xh[$the_parser]['value'] = isset($cur_val['values']) ? $cur_val['values'] : array();
 				$this->xh[$the_parser]['vt']	= strtolower($name);
-			break;
+				break;
 			case 'NAME':
 				$this->xh[$the_parser]['valuestack'][0]['name'] = $this->xh[$the_parser]['ac'];
-			break;
+				break;
 			case 'BOOLEAN':
 			case 'I4':
 			case 'INT':
@@ -961,60 +1045,43 @@
 			case 'BASE64':
 				$this->xh[$the_parser]['vt'] = strtolower($name);
 
-				if ($name == 'STRING')
+				if ($name === 'STRING')
 				{
 					$this->xh[$the_parser]['value'] = $this->xh[$the_parser]['ac'];
 				}
-				elseif ($name=='DATETIME.ISO8601')
+				elseif ($name === 'DATETIME.ISO8601')
 				{
 					$this->xh[$the_parser]['vt']	= $this->xmlrpcDateTime;
 					$this->xh[$the_parser]['value'] = $this->xh[$the_parser]['ac'];
 				}
-				elseif ($name=='BASE64')
+				elseif ($name === 'BASE64')
 				{
 					$this->xh[$the_parser]['value'] = base64_decode($this->xh[$the_parser]['ac']);
 				}
-				elseif ($name=='BOOLEAN')
+				elseif ($name === 'BOOLEAN')
 				{
 					// Translated BOOLEAN values to TRUE AND FALSE
-					if ($this->xh[$the_parser]['ac'] == '1')
-					{
-						$this->xh[$the_parser]['value'] = TRUE;
-					}
-					else
-					{
-						$this->xh[$the_parser]['value'] = FALSE;
-					}
+					$this->xh[$the_parser]['value'] = (bool) $this->xh[$the_parser]['ac'];
 				}
 				elseif ($name=='DOUBLE')
 				{
 					// we have a DOUBLE
 					// we must check that only 0123456789-.<space> are characters here
-					if ( ! preg_match('/^[+-]?[eE0-9\t \.]+$/', $this->xh[$the_parser]['ac']))
-					{
-						$this->xh[$the_parser]['value'] = 'ERROR_NON_NUMERIC_FOUND';
-					}
-					else
-					{
-						$this->xh[$the_parser]['value'] = (double)$this->xh[$the_parser]['ac'];
-					}
+					$this->xh[$the_parser]['value'] = preg_match('/^[+-]?[eE0-9\t \.]+$/', $this->xh[$the_parser]['ac'])
+										? (float) $this->xh[$the_parser]['ac']
+										: 'ERROR_NON_NUMERIC_FOUND';
 				}
 				else
 				{
 					// we have an I4/INT
 					// we must check that only 0123456789-<space> are characters here
-					if ( ! preg_match('/^[+-]?[0-9\t ]+$/', $this->xh[$the_parser]['ac']))
-					{
-						$this->xh[$the_parser]['value'] = 'ERROR_NON_NUMERIC_FOUND';
-					}
-					else
-					{
-						$this->xh[$the_parser]['value'] = (int)$this->xh[$the_parser]['ac'];
-					}
+					$this->xh[$the_parser]['value'] = preg_match('/^[+-]?[0-9\t ]+$/', $this->xh[$the_parser]['ac'])
+										? (int) $this->xh[$the_parser]['ac']
+										: 'ERROR_NON_NUMERIC_FOUND';
 				}
 				$this->xh[$the_parser]['ac'] = '';
 				$this->xh[$the_parser]['lv'] = 3; // indicate we've found a value
-			break;
+				break;
 			case 'VALUE':
 				// This if() detects if no scalar was inside <VALUE></VALUE>
 				if ($this->xh[$the_parser]['vt']=='value')
@@ -1026,7 +1093,7 @@
 				// build the XML-RPC value out of the data received, and substitute it
 				$temp = new XML_RPC_Values($this->xh[$the_parser]['value'], $this->xh[$the_parser]['vt']);
 
-				if (count($this->xh[$the_parser]['valuestack']) && $this->xh[$the_parser]['valuestack'][0]['type'] == 'ARRAY')
+				if (count($this->xh[$the_parser]['valuestack']) && $this->xh[$the_parser]['valuestack'][0]['type'] === 'ARRAY')
 				{
 					// Array
 					$this->xh[$the_parser]['valuestack'][0]['values'][] = $temp;
@@ -1036,57 +1103,62 @@
 					// Struct
 					$this->xh[$the_parser]['value'] = $temp;
 				}
-			break;
+				break;
 			case 'MEMBER':
-				$this->xh[$the_parser]['ac']='';
+				$this->xh[$the_parser]['ac'] = '';
 
 				// If value add to array in the stack for the last element built
 				if ($this->xh[$the_parser]['value'])
 				{
 					$this->xh[$the_parser]['valuestack'][0]['values'][$this->xh[$the_parser]['valuestack'][0]['name']] = $this->xh[$the_parser]['value'];
 				}
-			break;
+				break;
 			case 'DATA':
-				$this->xh[$the_parser]['ac']='';
-			break;
+				$this->xh[$the_parser]['ac'] = '';
+				break;
 			case 'PARAM':
 				if ($this->xh[$the_parser]['value'])
 				{
 					$this->xh[$the_parser]['params'][] = $this->xh[$the_parser]['value'];
 				}
-			break;
+				break;
 			case 'METHODNAME':
 				$this->xh[$the_parser]['method'] = ltrim($this->xh[$the_parser]['ac']);
-			break;
+				break;
 			case 'PARAMS':
 			case 'FAULT':
 			case 'METHODCALL':
 			case 'METHORESPONSE':
 				// We're all good kids with nuthin' to do
-			break;
+				break;
 			default:
-				// End of an Invalid Element.  Taken care of during the opening tag though
-			break;
+				// End of an Invalid Element. Taken care of during the opening tag though
+				break;
 		}
 	}
 
-	//-------------------------------------
-	//  Parses Character Data
-	//-------------------------------------
+	// --------------------------------------------------------------------
 
+	/**
+	 * Parse character data
+	 *
+	 * @param	string
+	 * @param	string
+	 * @return	void
+	 */
 	public function character_data($the_parser, $data)
 	{
 		if ($this->xh[$the_parser]['isf'] > 1) return; // XML Fault found already
 
 		// If a value has not been found
-		if ($this->xh[$the_parser]['lv'] != 3)
+		if ($this->xh[$the_parser]['lv'] !== 3)
 		{
-			if ($this->xh[$the_parser]['lv'] == 1)
+			if ($this->xh[$the_parser]['lv'] === 1)
 			{
 				$this->xh[$the_parser]['lv'] = 2; // Found a value
 			}
 
-			if ( ! @isset($this->xh[$the_parser]['ac']))
+			if ( ! isset($this->xh[$the_parser]['ac']))
 			{
 				$this->xh[$the_parser]['ac'] = '';
 			}
@@ -1095,12 +1167,27 @@
 		}
 	}
 
+	// --------------------------------------------------------------------
 
+	/**
+	 * Add parameter
+	 *
+	 * @param	mixed
+	 * @return	void
+	 */
 	public function addParam($par)
 	{
 		$this->params[] = $par;
 	}
 
+	// --------------------------------------------------------------------
+
+	/**
+	 * Output parameters
+	 *
+	 * @param	array
+	 * @return	array
+	 */
 	public function output_parameters($array = FALSE)
 	{
 		$CI =& get_instance();
@@ -1117,57 +1204,62 @@
 				{
 					// '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] = ($key === 'bits' OR $this->xss_clean === FALSE) ? $array[$key] : $CI->security->xss_clean($array[$key]);
 				}
 			}
 
-			$parameters = $array;
+			return $array;
 		}
-		else
+
+		$parameters = array();
+
+		for ($i = 0, $c = count($this->params); $i < $c; $i++)
 		{
-			$parameters = array();
+			$a_param = $this->decode_message($this->params[$i]);
 
-			for ($i = 0, $c = count($this->params); $i < $c; $i++)
+			if (is_array($a_param))
 			{
-				$a_param = $this->decode_message($this->params[$i]);
-
-				if (is_array($a_param))
-				{
-					$parameters[] = $this->output_parameters($a_param);
-				}
-				else
-				{
-					$parameters[] = ($this->xss_clean) ? $CI->security->xss_clean($a_param) : $a_param;
-				}
+				$parameters[] = $this->output_parameters($a_param);
+			}
+			else
+			{
+				$parameters[] = ($this->xss_clean) ? $CI->security->xss_clean($a_param) : $a_param;
 			}
 		}
 
 		return $parameters;
 	}
 
+	// --------------------------------------------------------------------
 
+	/**
+	 * Decode message
+	 *
+	 * @param	object
+	 * @return	mixed
+	 */
 	public function decode_message($param)
 	{
 		$kind = $param->kindOf();
 
-		if ($kind == 'scalar')
+		if ($kind === 'scalar')
 		{
 			return $param->scalarval();
 		}
-		elseif ($kind == 'array')
+		elseif ($kind === 'array')
 		{
 			reset($param->me);
 			$b = current($param->me);
 			$arr = array();
 
-			for($i = 0, $c = count($b); $i < $c; $i++)
+			for ($i = 0, $c = count($b); $i < $c; $i++)
 			{
 				$arr[] = $this->decode_message($param->me['array'][$i]);
 			}
 
 			return $arr;
 		}
-		elseif ($kind == 'struct')
+		elseif ($kind === 'struct')
 		{
 			reset($param->me['struct']);
 			$arr = array();
@@ -1181,8 +1273,7 @@
 		}
 	}
 
-}
-// End XML_RPC_Messages class
+} // END XML_RPC_Message Class
 
 /**
  * XML-RPC Values class
@@ -1196,51 +1287,67 @@
 	public $me	= array();
 	public $mytype	= 0;
 
+	/**
+	 * Constructor
+	 *
+	 * @param	mixed
+	 * @param	string
+	 * @return	void
+	 */
 	public function __construct($val = -1, $type = '')
 	{
 		parent::__construct();
 
-		if ($val != -1 OR $type != '')
+		if ($val !== -1 OR $type !== '')
 		{
-			$type = $type == '' ? 'string' : $type;
+			$type = $type === '' ? 'string' : $type;
 
-			if ($this->xmlrpcTypes[$type] == 1)
+			if ($this->xmlrpcTypes[$type] === 1)
 			{
 				$this->addScalar($val,$type);
 			}
-			elseif ($this->xmlrpcTypes[$type] == 2)
+			elseif ($this->xmlrpcTypes[$type] === 2)
 			{
 				$this->addArray($val);
 			}
-			elseif ($this->xmlrpcTypes[$type] == 3)
+			elseif ($this->xmlrpcTypes[$type] === 3)
 			{
 				$this->addStruct($val);
 			}
 		}
 	}
 
+	// --------------------------------------------------------------------
+
+	/**
+	 * Add scalar value
+	 *
+	 * @param	scalar
+	 * @param	string
+	 * @return	int
+	 */
 	public function addScalar($val, $type = 'string')
 	{
 		$typeof = $this->xmlrpcTypes[$type];
 
-		if ($this->mytype==1)
+		if ($this->mytype === 1)
 		{
 			echo '<strong>XML_RPC_Values</strong>: scalar can have only one value<br />';
 			return 0;
 		}
 
-		if ($typeof != 1)
+		if ($typeof !== 1)
 		{
 			echo '<strong>XML_RPC_Values</strong>: not a scalar type (${typeof})<br />';
 			return 0;
 		}
 
-		if ($type == $this->xmlrpcBoolean)
+		if ($type === $this->xmlrpcBoolean)
 		{
-			$val = (strcasecmp($val,'true') === 0 OR $val == 1 OR ($val == true && strcasecmp($val, 'false'))) ? 1 : 0;
+			$val = (int) (strcasecmp($val,'true') === 0 OR $val === 1 OR ($val === TRUE && strcasecmp($val, 'false')));
 		}
 
-		if ($this->mytype == 2)
+		if ($this->mytype === 2)
 		{
 			// adding to an array here
 			$ar = $this->me['array'];
@@ -1253,12 +1360,21 @@
 			$this->me[$type] = $val;
 			$this->mytype = $typeof;
 		}
+
 		return 1;
 	}
 
+	// --------------------------------------------------------------------
+
+	/**
+	 * Add array value
+	 *
+	 * @param	array
+	 * @return	int
+	 */
 	public function addArray($vals)
 	{
-		if ($this->mytype != 0)
+		if ($this->mytype !== 0)
 		{
 			echo '<strong>XML_RPC_Values</strong>: already initialized as a [' . $this->kindOf() . ']<br />';
 			return 0;
@@ -1269,9 +1385,17 @@
 		return 1;
 	}
 
+	// --------------------------------------------------------------------
+
+	/**
+	 * Add struct value
+	 *
+	 * @param	object
+	 * @return	int
+	 */
 	public function addStruct($vals)
 	{
-		if ($this->mytype != 0)
+		if ($this->mytype !== 0)
 		{
 			echo '<strong>XML_RPC_Values</strong>: already initialized as a [' . $this->kindOf() . ']<br />';
 			return 0;
@@ -1281,29 +1405,37 @@
 		return 1;
 	}
 
+	// --------------------------------------------------------------------
+
+	/**
+	 * Get value type
+	 *
+	 * @return	string
+	 */
 	public function kindOf()
 	{
-		switch($this->mytype)
+		switch ($this->mytype)
 		{
-			case 3:
-				return 'struct';
-				break;
-			case 2:
-				return 'array';
-				break;
-			case 1:
-				return 'scalar';
-				break;
-			default:
-				return 'undef';
+			case 3: return 'struct';
+			case 2: return 'array';
+			case 1: return 'scalar';
+			default: return 'undef';
 		}
 	}
 
+	// --------------------------------------------------------------------
+
+	/**
+	 * Serialize data
+	 *
+	 * @param	string
+	 * @param	mixed
+	 */
 	public function serializedata($typ, $val)
 	{
 		$rs = '';
 
-		switch($this->xmlrpcTypes[$typ])
+		switch ($this->xmlrpcTypes[$typ])
 		{
 			case 3:
 				// struct
@@ -1314,11 +1446,11 @@
 					$rs .= "<member>\n<name>{$key2}</name>\n".$this->serializeval($val2)."</member>\n";
 				}
 				$rs .= '</struct>';
-			break;
+				break;
 			case 2:
 				// array
 				$rs .= "<array>\n<data>\n";
-				for($i = 0, $c = count($val); $i < $c; $i++)
+				for ($i = 0, $c = count($val); $i < $c; $i++)
 				{
 					$rs .= $this->serializeval($val[$i]);
 				}
@@ -1329,29 +1461,45 @@
 				switch ($typ)
 				{
 					case $this->xmlrpcBase64:
-						$rs .= "<{$typ}>" . base64_encode((string)$val) . "</{$typ}>\n";
-					break;
+						$rs .= '<'.$typ.'>'.base64_encode( (string) $val).'</'.$typ.">\n";
+						break;
 					case $this->xmlrpcBoolean:
-						$rs .= "<{$typ}>" . ((bool)$val ? '1' : '0') . "</{$typ}>\n";
-					break;
+						$rs .= '<'.$typ.'>'.( (bool) $val ? '1' : '0').'</'.$typ.">\n";
+						break;
 					case $this->xmlrpcString:
-						$rs .= "<{$typ}>" . htmlspecialchars((string)$val). "</{$typ}>\n";
-					break;
+						$rs .= '<'.$typ.'>'.htmlspecialchars( (string) $val).'</'.$typ.">\n";
+						break;
 					default:
-						$rs .= "<{$typ}>{$val}</{$typ}>\n";
-					break;
+						$rs .= '<'.$typ.'>'.$val.'</'.$typ.">\n";
+						break;
 				}
 			default:
-			break;
+				break;
 		}
+
 		return $rs;
 	}
 
+	// --------------------------------------------------------------------
+
+	/**
+	 * Serialize class
+	 *
+	 * @return	string
+	 */
 	public function serialize_class()
 	{
 		return $this->serializeval($this);
 	}
 
+	// --------------------------------------------------------------------
+
+	/**
+	 * Serialize value
+	 *
+	 * @param	object
+	 * @return	string
+	 */
 	public function serializeval($o)
 	{
 		$ar = $o->me;
@@ -1361,26 +1509,35 @@
 		return "<value>\n".$this->serializedata($typ, $val)."</value>\n";
 	}
 
+	// --------------------------------------------------------------------
+
+	/**
+	 * Scalar value
+	 *
+	 * @return	mixed
+	 */
 	public function scalarval()
 	{
 		reset($this->me);
 		return current($this->me);
 	}
 
+	// --------------------------------------------------------------------
 
-	//-------------------------------------
-	// Encode time in ISO-8601 form.
-	//-------------------------------------
-
-	// Useful for sending time in XML-RPC
-
-	public function iso8601_encode($time, $utc = 0)
+	/**
+	 * Encode time in ISO-8601 form.
+	 * Useful for sending time in XML-RPC
+	 *
+	 * @param	int	unix timestamp
+	 * @param	bool
+	 * @return	string
+	*/
+	public function iso8601_encode($time, $utc = FALSE)
 	{
 		return ($utc) ? strftime('%Y%m%dT%H:%i:%s', $time) : gmstrftime('%Y%m%dT%H:%i:%s', $time);
 	}
 
-}
-// END XML_RPC_Values Class
+} // END XML_RPC_Values Class
 
 /* End of file Xmlrpc.php */
-/* Location: ./system/libraries/Xmlrpc.php */
+/* Location: ./system/libraries/Xmlrpc.php */
\ No newline at end of file
diff --git a/system/libraries/Xmlrpcs.php b/system/libraries/Xmlrpcs.php
index 355d43f..be930b0 100644
--- a/system/libraries/Xmlrpcs.php
+++ b/system/libraries/Xmlrpcs.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -48,16 +48,41 @@
  */
 class CI_Xmlrpcs extends CI_Xmlrpc
 {
-	public $methods		= array();	//array of methods mapped to function names and signatures
-	public $debug_msg	= '';		// Debug Message
-	public $system_methods	= array();	// XML RPC Server methods
-	public $controller_obj;
-	public $object		= FALSE;
+	/**
+	 * array of methods mapped to function names and signatures
+	 *
+	 * @var array
+	 */
+	public $methods = array();
 
 	/**
-	 * Constructor
+	 * Debug Message
+	 *
+	 * @var string
 	 */
-	public function __construct($config=array())
+	public $debug_msg = '';
+
+	/**
+	 * XML RPC Server methods
+	 *
+	 * @var array
+	 */
+	public $system_methods	= array();
+
+	/**
+	 * Configuration object
+	 *
+	 * @var object
+	 */
+	public $object = FALSE;
+
+	/**
+	 * Initialize XMLRPC class
+	 *
+	 * @param	array	$config
+	 * @return	void
+	 */
+	public function __construct($config = array())
 	{
 		parent::__construct();
 		$this->set_system_methods();
@@ -67,7 +92,7 @@
 			$this->methods = array_merge($this->methods, $config['functions']);
 		}
 
-		log_message('debug', "XML-RPC Server Class Initialized");
+		log_message('debug', 'XML-RPC Server Class Initialized');
 	}
 
 	// --------------------------------------------------------------------
@@ -75,7 +100,6 @@
 	/**
 	 * Initialize Prefs and Serve
 	 *
-	 * @access	public
 	 * @param	mixed
 	 * @return	void
 	 */
@@ -107,7 +131,6 @@
 	/**
 	 * Setting of System Methods
 	 *
-	 * @access	public
 	 * @return	void
 	 */
 	public function set_system_methods()
@@ -137,7 +160,6 @@
 	/**
 	 * Main Server Function
 	 *
-	 * @access	public
 	 * @return	void
 	 */
 	public function serve()
@@ -145,8 +167,8 @@
 		$r = $this->parseRequest();
 		$payload = '<?xml version="1.0" encoding="'.$this->xmlrpc_defencoding.'"?'.'>'."\n".$this->debug_msg.$r->prepare_response();
 
-		header("Content-Type: text/xml");
-		header("Content-Length: ".strlen($payload));
+		header('Content-Type: text/xml');
+		header('Content-Length: '.strlen($payload));
 		exit($payload);
 	}
 
@@ -155,7 +177,6 @@
 	/**
 	 * Add Method to Class
 	 *
-	 * @access	public
 	 * @param	string	method name
 	 * @param	string	function
 	 * @param	string	signature
@@ -176,7 +197,6 @@
 	/**
 	 * Parse Server Request
 	 *
-	 * @access	public
 	 * @param	string	data
 	 * @return	object	xmlrpc response
 	 */
@@ -188,7 +208,7 @@
 		//  Get Data
 		//-------------------------------------
 
-		if ($data == '')
+		if ($data === '')
 		{
 			$data = $HTTP_RAW_POST_DATA;
 		}
@@ -198,7 +218,7 @@
 		//-------------------------------------
 
 		$parser = xml_parser_create($this->xmlrpc_defencoding);
-		$parser_object = new XML_RPC_Message("filler");
+		$parser_object = new XML_RPC_Message('filler');
 
 		$parser_object->xh[$parser] = array(
 							'isf' =>	0,
@@ -215,7 +235,6 @@
 		xml_set_character_data_handler($parser, 'character_data');
 		//xml_set_default_handler($parser, 'default_handler');
 
-
 		//-------------------------------------
 		//  PARSE + PROCESS XML DATA
 		//-------------------------------------
@@ -245,7 +264,7 @@
 			{
 				if ($this->debug === TRUE)
 				{
-					$plist .= "$i - " .  print_r(get_object_vars($parser_object->xh[$parser]['params'][$i]), TRUE). ";\n";
+					$plist .= $i.' - '.print_r(get_object_vars($parser_object->xh[$parser]['params'][$i]), TRUE).";\n";
 				}
 
 				$m->addParam($parser_object->xh[$parser]['params'][$i]);
@@ -276,7 +295,6 @@
 	/**
 	 * Executes the Method
 	 *
-	 * @access	protected
 	 * @param	object
 	 * @return	mixed
 	 */
@@ -287,7 +305,7 @@
 		// Check to see if it is a system call
 		$system_call = (strncmp($methName, 'system', 5) === 0);
 
-		if ($this->xss_clean == FALSE)
+		if ($this->xss_clean === FALSE)
 		{
 			$m->xss_clean = FALSE;
 		}
@@ -305,8 +323,8 @@
 		//  Check for Method (and Object)
 		//-------------------------------------
 
-		$method_parts = explode(".", $this->methods[$methName]['function']);
-		$objectCall = (isset($method_parts[1]) && $method_parts[1] != '');
+		$method_parts = explode('.', $this->methods[$methName]['function']);
+		$objectCall = (isset($method_parts[1]) && $method_parts[1] !== '');
 
 		if ($system_call === TRUE)
 		{
@@ -315,14 +333,11 @@
 				return new XML_RPC_Response(0, $this->xmlrpcerr['unknown_method'], $this->xmlrpcstr['unknown_method']);
 			}
 		}
-		else
+		elseif (($objectCall && ! is_callable(array($method_parts[0], $method_parts[1])))
+			OR ( ! $objectCall && ! is_callable($this->methods[$methName]['function']))
+		)
 		{
-			if (($objectCall AND ! is_callable(array($method_parts[0], $method_parts[1])))
-				OR ( ! $objectCall AND ! is_callable($this->methods[$methName]['function']))
-			)
-			{
-				return new XML_RPC_Response(0, $this->xmlrpcerr['unknown_method'], $this->xmlrpcstr['unknown_method']);
-			}
+			return new XML_RPC_Response(0, $this->xmlrpcerr['unknown_method'], $this->xmlrpcstr['unknown_method']);
 		}
 
 		//-------------------------------------
@@ -341,9 +356,9 @@
 					for ($n = 0, $mc = count($m->params); $n < $mc; $n++)
 					{
 						$p = $m->params[$n];
-						$pt = ($p->kindOf() == 'scalar') ? $p->scalarval() : $p->kindOf();
+						$pt = ($p->kindOf() === 'scalar') ? $p->scalarval() : $p->kindOf();
 
-						if ($pt != $current_sig[$n+1])
+						if ($pt !== $current_sig[$n+1])
 						{
 							$pno = $n+1;
 							$wanted = $current_sig[$n+1];
@@ -351,7 +366,7 @@
 							return new XML_RPC_Response(0,
 								$this->xmlrpcerr['incorrect_params'],
 								$this->xmlrpcstr['incorrect_params'] .
-								": Wanted {$wanted}, got {$pt} at param {$pno})");
+								': Wanted '.$wanted.', got '.$pt.' at param '.$pno.')');
 						}
 					}
 				}
@@ -393,7 +408,6 @@
 	/**
 	 * Server Function:  List Methods
 	 *
-	 * @access	public
 	 * @param	mixed
 	 * @return	object
 	 */
@@ -409,7 +423,7 @@
 
 		foreach ($this->system_methods as $key => $value)
 		{
-			$output[]= new XML_RPC_Values($key, 'string');
+			$output[] = new XML_RPC_Values($key, 'string');
 		}
 
 		$v->addArray($output);
@@ -421,7 +435,6 @@
 	/**
 	 * Server Function:  Return Signature for Method
 	 *
-	 * @access	public
 	 * @param	mixed
 	 * @return	object
 	 */
@@ -447,18 +460,14 @@
 					}
 					$sigs[] = new XML_RPC_Values($cursig, 'array');
 				}
-				$r = new XML_RPC_Response(new XML_RPC_Values($sigs, 'array'));
+
+				return new XML_RPC_Response(new XML_RPC_Values($sigs, 'array'));
 			}
-			else
-			{
-				$r = new XML_RPC_Response(new XML_RPC_Values('undef', 'string'));
-			}
+
+			return new XML_RPC_Response(new XML_RPC_Values('undef', 'string'));
 		}
-		else
-		{
-			$r = new XML_RPC_Response(0,$this->xmlrpcerr['introspect_unknown'], $this->xmlrpcstr['introspect_unknown']);
-		}
-		return $r;
+
+		return new XML_RPC_Response(0,$this->xmlrpcerr['introspect_unknown'], $this->xmlrpcstr['introspect_unknown']);
 	}
 
 	// --------------------------------------------------------------------
@@ -466,7 +475,6 @@
 	/**
 	 * Server Function:  Doc String for Method
 	 *
-	 * @access	public
 	 * @param	mixed
 	 * @return	object
 	 */
@@ -492,7 +500,6 @@
 	/**
 	 * Server Function:  Multi-call
 	 *
-	 * @access	public
 	 * @param	mixed
 	 * @return	object
 	 */
@@ -520,7 +527,7 @@
 
 			$attempt = $this->_execute($m);
 
-			if ($attempt->faultCode() != 0)
+			if ($attempt->faultCode() !== 0)
 			{
 				return $attempt;
 			}
@@ -536,7 +543,6 @@
 	/**
 	 *  Multi-call Function:  Error Handling
 	 *
-	 * @access	public
 	 * @param	mixed
 	 * @return	object
 	 */
@@ -556,13 +562,12 @@
 	/**
 	 *  Multi-call Function:  Processes method
 	 *
-	 * @access	public
 	 * @param	mixed
 	 * @return	object
 	 */
 	public function do_multicall($call)
 	{
-		if ($call->kindOf() != 'struct')
+		if ($call->kindOf() !== 'struct')
 		{
 			return $this->multicall_error('notstruct');
 		}
@@ -572,13 +577,13 @@
 		}
 
 		list($scalar_type,$scalar_value)=each($methName->me);
-		$scalar_type = $scalar_type == $this->xmlrpcI4 ? $this->xmlrpcInt : $scalar_type;
+		$scalar_type = $scalar_type === $this->xmlrpcI4 ? $this->xmlrpcInt : $scalar_type;
 
-		if ($methName->kindOf() != 'scalar' OR $scalar_type != 'string')
+		if ($methName->kindOf() !== 'scalar' OR $scalar_type !== 'string')
 		{
 			return $this->multicall_error('notstring');
 		}
-		elseif ($scalar_value == 'system.multicall')
+		elseif ($scalar_value === 'system.multicall')
 		{
 			return $this->multicall_error('recursion');
 		}
@@ -586,7 +591,7 @@
 		{
 			return $this->multicall_error('noparams');
 		}
-		elseif ($params->kindOf() != 'array')
+		elseif ($params->kindOf() !== 'array')
 		{
 			return $this->multicall_error('notarray');
 		}
@@ -601,7 +606,7 @@
 
 		$result = $this->_execute($msg);
 
-		if ($result->faultCode() != 0)
+		if ($result->faultCode() !== 0)
 		{
 			return $this->multicall_error($result);
 		}
@@ -610,7 +615,6 @@
 	}
 
 }
-// END XML_RPC_Server class
 
 /* End of file Xmlrpcs.php */
-/* Location: ./system/libraries/Xmlrpcs.php */
+/* Location: ./system/libraries/Xmlrpcs.php */
\ No newline at end of file
diff --git a/system/libraries/Zip.php b/system/libraries/Zip.php
index 50e8492..e0dc637 100644
--- a/system/libraries/Zip.php
+++ b/system/libraries/Zip.php
@@ -1,13 +1,13 @@
-<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
- * 
+ *
  * Licensed under the Open Software License version 3.0
- * 
+ *
  * This source file is subject to the Open Software License (OSL 3.0) that is
  * bundled with this package in the files license.txt / license.rst.  It is
  * also available through the world wide web at this URL:
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * Zip Compression Class
  *
@@ -44,21 +42,57 @@
  */
 class CI_Zip  {
 
-	var $zipdata	= '';
-	var $directory	= '';
-	var $entries	= 0;
-	var $file_num	= 0;
-	var $offset		= 0;
-	var $now;
+	/**
+	 * Zip data in string form
+	 *
+	 * @var string
+	 */
+	public $zipdata		= '';
 
 	/**
-	 * Constructor
+	 * Zip data for a directory in string form
+	 *
+	 * @var string
+	 */
+	public $directory	= '';
+
+	/**
+	 * Number of files/folder in zip file
+	 *
+	 * @var int
+	 */
+	public $entries		= 0;
+
+	/**
+	 * Number of files in zip
+	 *
+	 * @var int
+	 */
+	public $file_num	= 0;
+
+	/**
+	 * relative offset of local header
+	 *
+	 * @var int
+	 */
+	public $offset		= 0;
+
+	/**
+	 * Reference to time at init
+	 *
+	 * @var int
+	 */
+	public $now;
+
+	/**
+	 * Initialize zip compression class
+	 *
+	 * @return	void
 	 */
 	public function __construct()
 	{
-		log_message('debug', "Zip Compression Class Initialized");
-
 		$this->now = time();
+		log_message('debug', 'Zip Compression Class Initialized');
 	}
 
 	// --------------------------------------------------------------------
@@ -68,21 +102,19 @@
 	 *
 	 * Lets you add a virtual directory into which you can place files.
 	 *
-	 * @access	public
 	 * @param	mixed	the directory name. Can be string or array
 	 * @return	void
 	 */
-	function add_dir($directory)
+	public function add_dir($directory)
 	{
-		foreach ((array)$directory as $dir)
+		foreach ( (array) $directory as $dir)
 		{
-			if ( ! preg_match("|.+/$|", $dir))
+			if ( ! preg_match('|.+/$|', $dir))
 			{
 				$dir .= '/';
 			}
 
 			$dir_time = $this->_get_mod_time($dir);
-
 			$this->_add_dir($dir, $dir_time['file_mtime'], $dir_time['file_mdate']);
 		}
 	}
@@ -90,22 +122,22 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 *	Get file/directory modification time
+	 * Get file/directory modification time
 	 *
-	 *	If this is a newly created file/dir, we will set the time to 'now'
+	 * If this is a newly created file/dir, we will set the time to 'now'
 	 *
-	 *	@param string	path to file
-	 *	@return array	filemtime/filemdate
+	 * @param	string	path to file
+	 * @return	array	filemtime/filemdate
 	 */
-	function _get_mod_time($dir)
+	protected function _get_mod_time($dir)
 	{
 		// filemtime() may return false, but raises an error for non-existing files
-		$date = (file_exists($dir)) ? filemtime($dir): getdate($this->now);
-		
-		$time['file_mtime'] = ($date['hours'] << 11) + ($date['minutes'] << 5) + $date['seconds'] / 2;
-		$time['file_mdate'] = (($date['year'] - 1980) << 9) + ($date['mon'] << 5) + $date['mday'];
+		$date = file_exists($dir) ? filemtime($dir) : getdate($this->now);
 
-		return $time;
+		return array(
+				'file_mtime' => ($date['hours'] << 11) + ($date['minutes'] << 5) + $date['seconds'] / 2,
+				'file_mdate' => (($date['year'] - 1980) << 9) + ($date['mon'] << 5) + $date['mday']
+			);
 	}
 
 	// --------------------------------------------------------------------
@@ -113,13 +145,14 @@
 	/**
 	 * Add Directory
 	 *
-	 * @access	private
 	 * @param	string	the directory name
+	 * @param	int
+	 * @param	int
 	 * @return	void
 	 */
-	function _add_dir($dir, $file_mtime, $file_mdate)
+	protected function _add_dir($dir, $file_mtime, $file_mdate)
 	{
-		$dir = str_replace("\\", "/", $dir);
+		$dir = str_replace('\\', '/', $dir);
 
 		$this->zipdata .=
 			"\x50\x4b\x03\x04\x0a\x00\x00\x00\x00\x00"
@@ -162,29 +195,26 @@
 	 * Add Data to Zip
 	 *
 	 * Lets you add files to the archive. If the path is included
-	 * in the filename it will be placed within a directory.  Make
+	 * in the filename it will be placed within a directory. Make
 	 * sure you use add_dir() first to create the folder.
 	 *
-	 * @access	public
 	 * @param	mixed
 	 * @param	string
 	 * @return	void
 	 */
-	function add_data($filepath, $data = NULL)
+	public function add_data($filepath, $data = NULL)
 	{
 		if (is_array($filepath))
 		{
 			foreach ($filepath as $path => $data)
 			{
 				$file_data = $this->_get_mod_time($path);
-
 				$this->_add_data($path, $data, $file_data['file_mtime'], $file_data['file_mdate']);
 			}
 		}
 		else
 		{
 			$file_data = $this->_get_mod_time($filepath);
-
 			$this->_add_data($filepath, $data, $file_data['file_mtime'], $file_data['file_mdate']);
 		}
 	}
@@ -194,20 +224,19 @@
 	/**
 	 * Add Data to Zip
 	 *
-	 * @access	private
 	 * @param	string	the file name/path
 	 * @param	string	the data to be encoded
+	 * @param	int
+	 * @param	int
 	 * @return	void
 	 */
-	function _add_data($filepath, $data, $file_mtime, $file_mdate)
+	protected function _add_data($filepath, $data, $file_mtime, $file_mdate)
 	{
-		$filepath = str_replace("\\", "/", $filepath);
+		$filepath = str_replace('\\', '/', $filepath);
 
 		$uncompressed_size = strlen($data);
 		$crc32  = crc32($data);
-
-		$gzdata = gzcompress($data);
-		$gzdata = substr($gzdata, 2, -4);
+		$gzdata = substr(gzcompress($data), 2, -4);
 		$compressed_size = strlen($gzdata);
 
 		$this->zipdata .=
@@ -248,10 +277,11 @@
 	/**
 	 * Read the contents of a file and add it to the zip
 	 *
-	 * @access	public
+	 * @param	string
+	 * @param	bool
 	 * @return	bool
 	 */
-	function read_file($path, $preserve_filepath = FALSE)
+	public function read_file($path, $preserve_filepath = FALSE)
 	{
 		if ( ! file_exists($path))
 		{
@@ -260,16 +290,16 @@
 
 		if (FALSE !== ($data = file_get_contents($path)))
 		{
-			$name = str_replace("\\", "/", $path);
-
+			$name = str_replace('\\', '/', $path);
 			if ($preserve_filepath === FALSE)
 			{
-				$name = preg_replace("|.*/(.+)|", "\\1", $name);
+				$name = preg_replace('|.*/(.+)|', '\\1', $name);
 			}
 
 			$this->add_data($name, $data);
 			return TRUE;
 		}
+
 		return FALSE;
 	}
 
@@ -279,15 +309,17 @@
 	 * Read a directory and add it to the zip.
 	 *
 	 * This function recursively reads a folder and everything it contains (including
-	 * sub-folders) and creates a zip based on it.  Whatever directory structure
+	 * 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.
 	 *
-	 * @access	public
 	 * @param	string	path to source
+	 * @param	bool
+	 * @param	bool
 	 * @return	bool
 	 */
-	function read_dir($path, $preserve_filepath = TRUE, $root_path = NULL)
+	public function read_dir($path, $preserve_filepath = TRUE, $root_path = NULL)
 	{
+		$path = rtrim($path, '/\\').DIRECTORY_SEPARATOR;
 		if ( ! $fp = @opendir($path))
 		{
 			return FALSE;
@@ -296,36 +328,32 @@
 		// Set the original directory root for child dir's to use as relative
 		if ($root_path === NULL)
 		{
-			$root_path = dirname($path).'/';
+			$root_path = dirname($path).DIRECTORY_SEPARATOR;
 		}
 
 		while (FALSE !== ($file = readdir($fp)))
 		{
-			if (substr($file, 0, 1) == '.')
+			if ($file[0] === '.')
 			{
 				continue;
 			}
 
 			if (@is_dir($path.$file))
 			{
-				$this->read_dir($path.$file."/", $preserve_filepath, $root_path);
+				$this->read_dir($path.$file.DIRECTORY_SEPARATOR, $preserve_filepath, $root_path);
 			}
-			else
+			elseif (FALSE !== ($data = file_get_contents($path.$file)))
 			{
-				if (FALSE !== ($data = file_get_contents($path.$file)))
+				$name = str_replace(array('\\', '/'), DIRECTORY_SEPARATOR, $path);
+				if ($preserve_filepath === FALSE)
 				{
-					$name = str_replace("\\", "/", $path);
-
-					if ($preserve_filepath === FALSE)
-					{
-						$name = str_replace($root_path, '', $name);
-					}
-
-					$this->add_data($name.$file, $data);
+					$name = str_replace($root_path, '', $name);
 				}
+				$this->add_data($name.$file, $data);
 			}
 		}
 
+		closedir($fp);
 		return TRUE;
 	}
 
@@ -334,26 +362,23 @@
 	/**
 	 * Get the Zip file
 	 *
-	 * @access	public
-	 * @return	binary string
+	 * @return	string	(binary encoded)
 	 */
-	function get_zip()
+	public function get_zip()
 	{
 		// Is there any data to return?
-		if ($this->entries == 0)
+		if ($this->entries === 0)
 		{
 			return FALSE;
 		}
 
-		$zip_data = $this->zipdata;
-		$zip_data .= $this->directory."\x50\x4b\x05\x06\x00\x00\x00\x00";
-		$zip_data .= pack('v', $this->entries); // total # of entries "on this disk"
-		$zip_data .= pack('v', $this->entries); // total # of entries overall
-		$zip_data .= pack('V', strlen($this->directory)); // size of central dir
-		$zip_data .= pack('V', strlen($this->zipdata)); // offset to start of central dir
-		$zip_data .= "\x00\x00"; // .zip file comment length
-
-		return $zip_data;
+		return $this->zipdata
+			.$this->directory."\x50\x4b\x05\x06\x00\x00\x00\x00"
+			.pack('v', $this->entries) // total # of entries "on this disk"
+			.pack('v', $this->entries) // total # of entries overall
+			.pack('V', strlen($this->directory)) // size of central dir
+			.pack('V', strlen($this->zipdata)) // offset to start of central dir
+			."\x00\x00"; // .zip file comment length
 	}
 
 	// --------------------------------------------------------------------
@@ -363,11 +388,10 @@
 	 *
 	 * Lets you write a file
 	 *
-	 * @access	public
 	 * @param	string	the file name
 	 * @return	bool
 	 */
-	function archive($filepath)
+	public function archive($filepath)
 	{
 		if ( ! ($fp = @fopen($filepath, FOPEN_WRITE_CREATE_DESTRUCTIVE)))
 		{
@@ -387,23 +411,19 @@
 	/**
 	 * Download
 	 *
-	 * @access	public
 	 * @param	string	the file name
-	 * @param	string	the data to be encoded
-	 * @return	bool
+	 * @return	void
 	 */
-	function download($filename = 'backup.zip')
+	public function download($filename = 'backup.zip')
 	{
-		if ( ! preg_match("|.+?\.zip$|", $filename))
+		if ( ! preg_match('|.+?\.zip$|', $filename))
 		{
 			$filename .= '.zip';
 		}
 
 		$CI =& get_instance();
 		$CI->load->helper('download');
-
 		$get_zip = $this->get_zip();
-
 		$zip_content =& $get_zip;
 
 		force_download($filename, $zip_content);
@@ -414,19 +434,19 @@
 	/**
 	 * Initialize Data
 	 *
-	 * Lets you clear current zip data.  Useful if you need to create
+	 * Lets you clear current zip data. Useful if you need to create
 	 * multiple zips with different data.
 	 *
-	 * @access	public
-	 * @return	void
+	 * @return	object
 	 */
-	function clear_data()
+	public function clear_data()
 	{
 		$this->zipdata		= '';
 		$this->directory	= '';
 		$this->entries		= 0;
 		$this->file_num		= 0;
 		$this->offset		= 0;
+		return $this;
 	}
 
 }
diff --git a/system/libraries/javascript/Jquery.php b/system/libraries/javascript/Jquery.php
index 03574c6..44c16b5 100644
--- a/system/libraries/javascript/Jquery.php
+++ b/system/libraries/javascript/Jquery.php
@@ -2,7 +2,7 @@
 /**
  * CodeIgniter
  *
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
  *
  * NOTICE OF LICENSE
  *
@@ -25,8 +25,6 @@
  * @filesource
  */
 
-// ------------------------------------------------------------------------
-
 /**
  * Jquery Class
  *
@@ -57,7 +55,7 @@
 			$this->script();
 		}
 
-		log_message('debug', "Jquery Class Initialized");
+		log_message('debug', 'Jquery Class Initialized');
 	}
 
 	// --------------------------------------------------------------------
@@ -115,7 +113,7 @@
 
 		if ($ret_false)
 		{
-			$js[] = "return false;";
+			$js[] = 'return false;';
 		}
 
 		return $this->_add_event($element, $js, 'click');
@@ -183,7 +181,7 @@
 	 */
 	protected function _hover($element = 'this', $over, $out)
 	{
-		$event = "\n\t$(" . $this->_prep_element($element) . ").hover(\n\t\tfunction()\n\t\t{\n\t\t\t{$over}\n\t\t}, \n\t\tfunction()\n\t\t{\n\t\t\t{$out}\n\t\t});\n";
+		$event = "\n\t$(".$this->_prep_element($element).").hover(\n\t\tfunction()\n\t\t{\n\t\t\t{$over}\n\t\t}, \n\t\tfunction()\n\t\t{\n\t\t\t{$out}\n\t\t});\n";
 
 		$this->jquery_code_for_compile[] = $event;
 
@@ -322,7 +320,7 @@
 
 		foreach ($array_js as $js)
 		{
-			$this->jquery_code_for_compile[] = "\t$js\n";
+			$this->jquery_code_for_compile[] = "\t".$js."\n";
 		}
 	}
 
@@ -389,7 +387,7 @@
 	protected function _addClass($element = 'this', $class='')
 	{
 		$element = $this->_prep_element($element);
-		return "$({$element}).addClass(\"$class\");";
+		return '$('.$element.').addClass("'.$class.'");';
 	}
 
 	// --------------------------------------------------------------------
@@ -411,24 +409,24 @@
 
 		$animations = "\t\t\t";
 
-		foreach ($params as $param=>$value)
+		foreach ($params as $param => $value)
 		{
-			$animations .= $param.': \''.$value.'\', ';
+			$animations .= $param.": '".$value."', ";
 		}
 
 		$animations = substr($animations, 0, -2); // remove the last ", "
 
-		if ($speed != '')
+		if ($speed !== '')
 		{
 			$speed = ', '.$speed;
 		}
 
-		if ($extra != '')
+		if ($extra !== '')
 		{
 			$extra = ', '.$extra;
 		}
 
-		return "$({$element}).animate({\n$animations\n\t\t}".$speed.$extra.");";
+		return "$({$element}).animate({\n$animations\n\t\t}".$speed.$extra.');';
 	}
 
 	// --------------------------------------------------------------------
@@ -448,7 +446,7 @@
 		$element = $this->_prep_element($element);
 		$speed = $this->_validate_speed($speed);
 
-		if ($callback != '')
+		if ($callback !== '')
 		{
 			$callback = ", function(){\n{$callback}\n}";
 		}
@@ -473,12 +471,12 @@
 		$element = $this->_prep_element($element);
 		$speed = $this->_validate_speed($speed);
 
-		if ($callback != '')
+		if ($callback !== '')
 		{
 			$callback = ", function(){\n{$callback}\n}";
 		}
 
-		return "$({$element}).fadeOut({$speed}{$callback});";
+		return '$('.$element.').fadeOut('.$speed.$callback.');';
 	}
 
 	// --------------------------------------------------------------------
@@ -498,7 +496,7 @@
 		$element = $this->_prep_element($element);
 		$speed = $this->_validate_speed($speed);
 
-		if ($callback != '')
+		if ($callback !== '')
 		{
 			$callback = ", function(){\n{$callback}\n}";
 		}
@@ -519,7 +517,7 @@
 	protected function _removeClass($element = 'this', $class='')
 	{
 		$element = $this->_prep_element($element);
-		return "$({$element}).removeClass(\"$class\");";
+		return '$('.$element.').removeClass("'.$class.'");';
 	}
 
 	// --------------------------------------------------------------------
@@ -539,12 +537,12 @@
 		$element = $this->_prep_element($element);
 		$speed = $this->_validate_speed($speed);
 
-		if ($callback != '')
+		if ($callback !== '')
 		{
 			$callback = ", function(){\n{$callback}\n}";
 		}
 
-		return "$({$element}).slideUp({$speed}{$callback});";
+		return '$('.$element.').slideUp('.$speed.$callback.');';
 	}
 
 	// --------------------------------------------------------------------
@@ -564,12 +562,12 @@
 		$element = $this->_prep_element($element);
 		$speed = $this->_validate_speed($speed);
 
-		if ($callback != '')
+		if ($callback !== '')
 		{
 			$callback = ", function(){\n{$callback}\n}";
 		}
 
-		return "$({$element}).slideDown({$speed}{$callback});";
+		return '$('.$element.').slideDown('.$speed.$callback.');';
 	}
 
 	// --------------------------------------------------------------------
@@ -589,12 +587,12 @@
 		$element = $this->_prep_element($element);
 		$speed = $this->_validate_speed($speed);
 
-		if ($callback != '')
+		if ($callback !== '')
 		{
 			$callback = ", function(){\n{$callback}\n}";
 		}
 
-		return "$({$element}).slideToggle({$speed}{$callback});";
+		return '$('.$element.').slideToggle('.$speed.$callback.');';
 	}
 
 	// --------------------------------------------------------------------
@@ -610,7 +608,7 @@
 	protected function _toggle($element = 'this')
 	{
 		$element = $this->_prep_element($element);
-		return "$({$element}).toggle();";
+		return '$('.$element.').toggle();';
 	}
 
 	// --------------------------------------------------------------------
@@ -626,7 +624,7 @@
 	protected function _toggleClass($element = 'this', $class='')
 	{
 		$element = $this->_prep_element($element);
-		return "$({$element}).toggleClass(\"$class\");";
+		return '$('.$element.').toggleClass("'.$class.'");';
 	}
 
 	// --------------------------------------------------------------------
@@ -646,12 +644,12 @@
 		$element = $this->_prep_element($element);
 		$speed = $this->_validate_speed($speed);
 
-		if ($callback != '')
+		if ($callback !== '')
 		{
 			$callback = ", function(){\n{$callback}\n}";
 		}
 
-		return "$({$element}).show({$speed}{$callback});";
+		return '$('.$element.').show('.$speed.$callback.');';
 	}
 
 	// --------------------------------------------------------------------
@@ -674,24 +672,24 @@
 		$controller = (strpos('://', $controller) === FALSE) ? $controller : $this->CI->config->site_url($controller);
 
 		// ajaxStart and ajaxStop are better choices here... but this is a stop gap
-		if ($this->CI->config->item('javascript_ajax_img') == '')
+		if ($this->CI->config->item('javascript_ajax_img') === '')
 		{
-			$loading_notifier = "Loading...";
+			$loading_notifier = 'Loading...';
 		}
 		else
 		{
-			$loading_notifier = '<img src=\''.$this->CI->config->slash_item('base_url').$this->CI->config->item('javascript_ajax_img').'\' alt=\'Loading\' />';
+			$loading_notifier = '<img src="'.$this->CI->config->slash_item('base_url').$this->CI->config->item('javascript_ajax_img').'" alt="Loading" />';
 		}
 
-		$updater = "$($container).empty();\n" // anything that was in... get it out
-			. "\t\t$($container).prepend(\"$loading_notifier\");\n"; // to replace with an image
+		$updater = '$('.$container.").empty();\n" // anything that was in... get it out
+			."\t\t$(".$container.').prepend("'.$loading_notifier."\");\n"; // to replace with an image
 
 		$request_options = '';
-		if ($options != '')
+		if ($options !== '')
 		{
 			$request_options .= ', {'
-					. (is_array($options) ? "'".implode("', '", $options)."'" : "'".str_replace(":", "':'", $options)."'")
-					. '}';
+					.(is_array($options) ? "'".implode("', '", $options)."'" : "'".str_replace(':', "':'", $options)."'")
+					.'}';
 		}
 
 		return $updater."\t\t$($container).load('$controller'$request_options);";
@@ -711,12 +709,12 @@
 	 */
 	protected function _zebraTables($class = '', $odd = 'odd', $hover = '')
 	{
-		$class = ($class != '') ? '.'.$class : '';
+		$class = ($class !== '') ? '.'.$class : '';
 		$zebra  = "\t\$(\"table{$class} tbody tr:nth-child(even)\").addClass(\"{$odd}\");";
 
 		$this->jquery_code_for_compile[] = $zebra;
 
-		if ($hover != '')
+		if ($hover !== '')
 		{
 			$hover = $this->hover("table{$class} tbody tr", "$(this).addClass('hover');", "$(this).removeClass('hover');");
 		}
@@ -741,12 +739,12 @@
 		// may want to make this configurable down the road
 		$corner_location = '/plugins/jquery.corner.js';
 
-		if ($corner_style != '')
+		if ($corner_style !== '')
 		{
 			$corner_style = '"'.$corner_style.'"';
 		}
 
-		return "$(" . $this->_prep_element($element) . ").corner(".$corner_style.");";
+		return '$('.$this->_prep_element($element).').corner('.$corner_style.');';
 	}
 
 	// --------------------------------------------------------------------
@@ -821,16 +819,16 @@
 			$sort_options = array();
 			foreach ($options as $k=>$v)
 			{
-				$sort_options[] = "\n\t\t".$k.': '.$v."";
+				$sort_options[] = "\n\t\t".$k.': '.$v;
 			}
-			$sort_options = implode(",", $sort_options);
+			$sort_options = implode(',', $sort_options);
 		}
 		else
 		{
 			$sort_options = '';
 		}
 
-		return "$(" . $this->_prep_element($element) . ").sortable({".$sort_options."\n\t});";
+		return '$('.$this->_prep_element($element).').sortable({'.$sort_options."\n\t});";
 	}
 
 	// --------------------------------------------------------------------
@@ -844,7 +842,7 @@
 	 */
 	public function tablesorter($table = '', $options = '')
 	{
-		$this->jquery_code_for_compile[] = "\t$(" . $this->_prep_element($table) . ").tablesorter($options);\n";
+		$this->jquery_code_for_compile[] = "\t$(".$this->_prep_element($table).').tablesorter('.$options.");\n";
 	}
 
 	// --------------------------------------------------------------------
@@ -869,7 +867,7 @@
 
 		}
 
-		$event = "\n\t$(" . $this->_prep_element($element) . ").{$event}(function(){\n\t\t{$js}\n\t});\n";
+		$event = "\n\t$(".$this->_prep_element($element).').'.$event."(function(){\n\t\t{$js}\n\t});\n";
 		$this->jquery_code_for_compile[] = $event;
 		return $event;
 	}
@@ -898,8 +896,8 @@
 
 		// Inline references
 		$script = '$(document).ready(function() {'."\n"
-			. implode('', $this->jquery_code_for_compile)
-			. '});';
+			.implode('', $this->jquery_code_for_compile)
+			.'});';
 
 		$output = ($script_tags === FALSE) ? $script : $this->inline($script);
 
@@ -974,7 +972,7 @@
 	 */
 	protected function _prep_element($element)
 	{
-		if ($element != 'this')
+		if ($element !== 'this')
 		{
 			$element = '"'.$element.'"';
 		}
@@ -998,7 +996,7 @@
 		{
 			return '"'.$speed.'"';
 		}
-		elseif (preg_match("/[^0-9]/", $speed))
+		elseif (preg_match('/[^0-9]/', $speed))
 		{
 			return '';
 		}
@@ -1009,4 +1007,4 @@
 }
 
 /* End of file Jquery.php */
-/* Location: ./system/libraries/Jquery.php */
+/* Location: ./system/libraries/Jquery.php */
\ No newline at end of file
diff --git a/tests/Bootstrap.php b/tests/Bootstrap.php
new file mode 100644
index 0000000..5216038
--- /dev/null
+++ b/tests/Bootstrap.php
@@ -0,0 +1,38 @@
+<?php
+
+// Errors on full!
+ini_set('display_errors', 1);
+error_reporting(E_ALL | E_STRICT);
+
+$dir = realpath(dirname(__FILE__));
+
+// Path constants
+defined('PROJECT_BASE') OR define('PROJECT_BASE', realpath($dir.'/../').'/');
+defined('BASEPATH') OR define('BASEPATH', PROJECT_BASE.'system/');
+defined('APPPATH') OR define('APPPATH', PROJECT_BASE.'application/');
+defined('VIEWPATH') OR define('VIEWPATH', PROJECT_BASE.'');
+
+// Get vfsStream either via PEAR or composer
+foreach (explode(PATH_SEPARATOR, get_include_path()) as $path)
+{
+	if (file_exists($path.DIRECTORY_SEPARATOR.'vfsStream/vfsStream.php'))
+	{
+		require_once 'vfsStream/vfsStream.php';
+		break;
+	}
+}
+
+if ( ! class_exists('vfsStream') && file_exists(PROJECT_BASE.'vendor/autoload.php'))
+{
+	include_once PROJECT_BASE.'vendor/autoload.php';
+	class_alias('org\bovigo\vfs\vfsStream', 'vfsStream');
+	class_alias('org\bovigo\vfs\vfsStreamDirectory', 'vfsStreamDirectory');
+	class_alias('org\bovigo\vfs\vfsStreamWrapper', 'vfsStreamWrapper');
+}
+
+// Prep our test environment
+include_once $dir.'/mocks/core/common.php';
+include_once $dir.'/mocks/autoloader.php';
+spl_autoload_register('autoload');
+
+unset($dir);
\ No newline at end of file
diff --git a/tests/README.md b/tests/README.md
new file mode 100644
index 0000000..d600951
--- /dev/null
+++ b/tests/README.md
@@ -0,0 +1,158 @@
+# CodeIgniter Unit Tests #
+
+Status : [![Build Status](https://secure.travis-ci.org/EllisLab/CodeIgniter.png?branch=develop)](http://travis-ci.org/EllisLab/CodeIgniter)
+
+### Introduction:
+
+This is the preliminary CodeIgniter testing documentation. It
+will cover both internal as well as external APIs and the reasoning
+behind their implemenation, where appropriate. As with all CodeIgniter
+documentation, this file should maintain a mostly human readable
+format to facilitate clean api design. [see http://arrenbrecht.ch/testing/]
+
+*First public draft: everything is subject to change*
+
+### Requirements
+
+PHP Unit >= 3.5.6
+
+	pear channel-discover pear.phpunit.de
+	pear install phpunit/PHPUnit
+
+vfsStream
+
+	pear channel-discover pear.bovigo.org
+	pear install bovigo/vfsStream-beta
+
+#### Installation of PEAR and PHPUnit on Ubuntu
+
+  Installation on Ubuntu requires a few steps. Depending on your setup you may
+  need to use 'sudo' to install these. Mileage may vary but these steps are a
+  good start.
+
+	# Install the PEAR package
+	sudo apt-get install php-pear
+
+	# Add a few sources to PEAR
+	pear channel-discover pear.phpunit.de
+	pear channel-discover pear.symfony-project.com
+	pear channel-discover components.ez.no
+	pear channel-discover pear.bovigo.org
+
+	# Finally install PHPUnit and vfsStream (including dependencies)
+	pear install --alldeps phpunit/PHPUnit
+	pear install --alldeps bovigo/vfsStream-beta
+
+	# Finally, run 'phpunit' from within the ./tests directory
+	# and you should be on your way!
+
+## Test Suites:
+
+CodeIgniter bootstraps a request very directly, with very flat class
+hierarchy. As a result, there is no main CodeIgniter class until the
+controller is instantiated.
+
+This has forced the core classes to be relatively decoupled, which is
+a good thing. However, it makes that portion of code relatively hard
+to test.
+
+Right now that means we'll probably have two core test suites, along
+with a base for application and package tests. That gives us:
+
+1. Bootstrap Test	- test common.php and sanity check codeigniter.php [in planning]
+2. System Test		- test core components in relative isolation [in development]
+3. Application Test	- bootstrapping for application/tests [not started]
+4. Package Test		- bootstrapping for <package>/tests [not started]
+
+### CI_TestCase Documentation
+
+Test cases should extend CI_TestCase. This internally extends
+PHPUnit\_Framework\_TestCase, so you have access to all of your
+usual PHPUnit methods.
+
+We need to provide a simple way to modify the globals and the
+common function output. We also need to be able to mock up
+the super object as we please.
+
+Current API is *not stable*. Names and implementations will change.
+
+    $this->ci_set_config($key, $val)
+
+Set the global config variables. If key is an array, it will
+replace the entire config array. They are _not_ merged.
+
+    $this->ci_instance($obj)
+
+Set the object to use as the "super object", in a lot
+of cases this will be a simple stdClass with the attributes
+you need it to have. If no parameter, will return the instance.
+
+	$this->ci_instance_var($name, $val)
+
+Add an attribute to the super object. This is useful if you
+set up a simple instance in setUp and then need to add different
+class mockups to your super object.
+
+	$this->ci_core_class($name)
+
+Get the _class name_ of a core class, so that you can instantiate
+it. The variable is returned by reference and is tied to the correct
+$GLOBALS key. For example:
+    
+	$cfg =& $this->ci_core_class('cfg'); // returns 'CI_Config'
+    $cfg = new $cfg; // instantiates config and overwrites the CFG global
+
+	$this->ci_set_core_class($name, $obj)
+	
+An alternative way to set one of the core globals.
+
+	$this->ci_get_config()  __internal__
+	
+Returns the global config array. Internal as you shouldn't need to
+call this (you're setting it, after all). Used internally to make
+CI's get_config() work.
+
+	CI_TestCase::instance()  __internal__
+
+Returns an instance of the current test case. We force phpunit to
+run with backup-globals enabled, so this will always be the instance
+of the currently running test class.
+
+### Going forward
+
+#### 1. Bootstrap Test
+
+Testing common.php should be pretty simple. Include the file, and test the
+functions. May require some tweaking so that we can grab the statics from all
+methods (see is_loaded()). Testing the actual CodeIgniter.php file will most
+likely be an output test for the default view, with some object checking after
+the file runs. Needs consideration.
+
+#### 2. System Test
+
+Testing the core system relies on being able to isolate the core components
+as much as possible. A few of them access other core classes as globals. These
+should be mocked up and easy to manipulate.
+
+All functions in common.php should be a minimal implementation, or and mapped
+to a method in the test's parent class to gives us full control of their output.
+
+#### 3. Application Test:
+
+Not sure yet, needs to handle:
+
+- Libraries
+- Helpers
+- Models
+- MY_* files
+- Controllers (uh...?)
+- Views? (watir, selenium, cucumber?)
+- Database Testing
+
+#### 4. Package Test:
+
+I don't have a clue how this will work.
+
+Needs to be able to handle packages
+that are used multiple times within the application (i.e. EE/Pyro modules)
+as well as packages that are used by multiple applications (library distributions)
diff --git a/tests/codeigniter/Setup_test.php b/tests/codeigniter/Setup_test.php
new file mode 100644
index 0000000..5317c56
--- /dev/null
+++ b/tests/codeigniter/Setup_test.php
@@ -0,0 +1,13 @@
+<?php
+
+class Setup_test extends PHPUnit_Framework_TestCase {
+
+	public function test_bootstrap_constants()
+	{
+		$this->assertTrue(defined('PROJECT_BASE'));
+		$this->assertTrue(defined('BASEPATH'));
+		$this->assertTrue(defined('APPPATH'));
+		$this->assertTrue(defined('VIEWPATH'));
+	}
+
+}
\ No newline at end of file
diff --git a/tests/codeigniter/core/Benchmark_test.php b/tests/codeigniter/core/Benchmark_test.php
new file mode 100644
index 0000000..a239ba5
--- /dev/null
+++ b/tests/codeigniter/core/Benchmark_test.php
@@ -0,0 +1,43 @@
+<?php
+
+class Benchmark_test extends CI_TestCase {
+
+	public function set_up()
+	{
+		$this->benchmark = new Mock_Core_Benchmark();
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_mark()
+	{
+		$this->assertEmpty($this->benchmark->marker);
+
+		$this->benchmark->mark('code_start');
+
+		$this->assertEquals(1, count($this->benchmark->marker));
+		$this->assertArrayHasKey('code_start', $this->benchmark->marker);
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_elapsed_time()
+	{
+		$this->assertEquals('{elapsed_time}', $this->benchmark->elapsed_time());
+		$this->assertEmpty($this->benchmark->elapsed_time('undefined_point'));
+
+		$this->benchmark->mark('code_start');
+		sleep(1);
+		$this->benchmark->mark('code_end');
+
+		$this->assertEquals('1.0', $this->benchmark->elapsed_time('code_start', 'code_end', 1));
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_memory_usage()
+	{
+		$this->assertEquals('{memory_usage}', $this->benchmark->memory_usage());
+	}
+
+}
\ No newline at end of file
diff --git a/tests/codeigniter/core/Common_test.php b/tests/codeigniter/core/Common_test.php
new file mode 100644
index 0000000..f9bf6c2
--- /dev/null
+++ b/tests/codeigniter/core/Common_test.php
@@ -0,0 +1,13 @@
+<?php
+
+class Common_test extends CI_TestCase {
+
+	// ------------------------------------------------------------------------
+
+	public function test_is_php()
+	{
+		$this->assertEquals(TRUE, is_php('1.2.0'));
+		$this->assertEquals(FALSE, is_php('9999.9.9'));
+	}
+
+}
\ No newline at end of file
diff --git a/tests/codeigniter/core/Config_test.php b/tests/codeigniter/core/Config_test.php
new file mode 100644
index 0000000..30cb90a
--- /dev/null
+++ b/tests/codeigniter/core/Config_test.php
@@ -0,0 +1,93 @@
+<?php
+
+class Config_test extends CI_TestCase {
+
+	public function set_up()
+	{
+		$cls =& $this->ci_core_class('cfg');
+
+		// set predictable config values
+		$this->ci_set_config(array(
+			'index_page'		=> 'index.php',
+			'base_url'			=> 'http://example.com/',
+			'subclass_prefix'	=> 'MY_'
+		));
+
+		$this->config = new $cls;
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_item()
+	{
+		$this->assertEquals('http://example.com/', $this->config->item('base_url'));
+
+		// Bad Config value
+		$this->assertFalse($this->config->item('no_good_item'));
+
+		// Index
+		$this->assertFalse($this->config->item('no_good_item', 'bad_index'));
+		$this->assertFalse($this->config->item('no_good_item', 'default'));
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_set_item()
+	{
+		$this->assertFalse($this->config->item('not_yet_set'));
+
+		$this->config->set_item('not_yet_set', 'is set');
+
+		$this->assertEquals('is set', $this->config->item('not_yet_set'));
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_slash_item()
+	{
+		// Bad Config value
+		$this->assertFalse($this->config->slash_item('no_good_item'));
+
+		$this->assertEquals('http://example.com/', $this->config->slash_item('base_url'));
+
+		$this->assertEquals('MY_/', $this->config->slash_item('subclass_prefix'));
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_site_url()
+	{
+		$this->assertEquals('http://example.com/index.php', $this->config->site_url());
+
+		$base_url = $this->config->item('base_url');
+
+		$this->config->set_item('base_url', '');
+
+		$q_string = $this->config->item('enable_query_strings');
+
+		$this->config->set_item('enable_query_strings', FALSE);
+
+		$this->assertEquals('index.php/test', $this->config->site_url('test'));
+		$this->assertEquals('index.php/test/1', $this->config->site_url(array('test', '1')));
+
+		$this->config->set_item('enable_query_strings', TRUE);
+
+		$this->assertEquals('index.php?test', $this->config->site_url('test'));
+		$this->assertEquals('index.php?0=test&1=1', $this->config->site_url(array('test', '1')));
+
+		$this->config->set_item('base_url', $base_url);
+
+		$this->assertEquals('http://example.com/index.php?test', $this->config->site_url('test'));
+
+		// back to home base
+		$this->config->set_item('enable_query_strings', $q_string);
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_system_url()
+	{
+		$this->assertEquals('http://example.com/system/', $this->config->system_url());
+	}
+
+}
\ No newline at end of file
diff --git a/tests/codeigniter/core/Input_test.php b/tests/codeigniter/core/Input_test.php
new file mode 100644
index 0000000..fe87388
--- /dev/null
+++ b/tests/codeigniter/core/Input_test.php
@@ -0,0 +1,161 @@
+<?php
+
+class Input_test extends CI_TestCase {
+
+	public function set_up()
+	{
+		// Set server variable to GET as default, since this will leave unset in STDIN env
+		$_SERVER['REQUEST_METHOD'] = 'GET';
+
+		// Set config for Input class
+		$this->ci_set_config('allow_get_array',	TRUE);
+		$this->ci_set_config('global_xss_filtering', FALSE);
+		$this->ci_set_config('csrf_protection', FALSE);
+
+		$security = new Mock_Core_Security();
+		$utf8 = new Mock_Core_Utf8();
+
+		$this->input = new Mock_Core_Input($security, $utf8);
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_get_not_exists()
+	{
+		$this->assertEmpty($this->input->get());
+		$this->assertEmpty($this->input->get('foo'));
+
+		$this->assertTrue( ! $this->input->get());
+		$this->assertTrue( ! $this->input->get('foo'));
+
+		// Test we're getting empty results
+		$this->assertTrue($this->input->get() === NULL);
+		$this->assertTrue($this->input->get('foo') === NULL);
+
+		// Test new 3.0 behaviour for non existant results (used to be FALSE)
+		$this->assertTrue($this->input->get() === NULL);
+		$this->assertTrue($this->input->get('foo') === NULL);
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_get_exist()
+	{
+		$_SERVER['REQUEST_METHOD'] = 'GET';
+		$_GET['foo'] = 'bar';
+
+		$this->assertArrayHasKey('foo', $this->input->get());
+		$this->assertEquals('bar', $this->input->get('foo'));
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_get_exist_with_xss_clean()
+	{
+		$_SERVER['REQUEST_METHOD'] = 'GET';
+		$_GET['harm'] = "Hello, i try to <script>alert('Hack');</script> your site";
+
+		$this->assertArrayHasKey('harm', $this->input->get());
+		$this->assertEquals("Hello, i try to <script>alert('Hack');</script> your site", $this->input->get('harm'));
+		$this->assertEquals("Hello, i try to [removed]alert&#40;'Hack'&#41;;[removed] your site", $this->input->get('harm', TRUE));
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_post_not_exists()
+	{
+		$this->assertEmpty($this->input->post());
+		$this->assertEmpty($this->input->post('foo'));
+
+		$this->assertTrue( ! $this->input->post());
+		$this->assertTrue( ! $this->input->post('foo'));
+
+		$this->assertTrue($this->input->post() === NULL);
+		$this->assertTrue($this->input->post('foo') === NULL);
+
+		$this->assertTrue($this->input->post() === NULL);
+		$this->assertTrue($this->input->post('foo') === NULL);
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_post_exist()
+	{
+		$_SERVER['REQUEST_METHOD'] = 'POST';
+		$_POST['foo'] = 'bar';
+
+		$this->assertArrayHasKey('foo', $this->input->post());
+		$this->assertEquals('bar', $this->input->post('foo'));
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_post_exist_with_xss_clean()
+	{
+		$_SERVER['REQUEST_METHOD'] = 'POST';
+		$_POST['harm'] = "Hello, i try to <script>alert('Hack');</script> your site";
+
+		$this->assertArrayHasKey('harm', $this->input->post());
+		$this->assertEquals("Hello, i try to <script>alert('Hack');</script> your site", $this->input->post('harm'));
+		$this->assertEquals("Hello, i try to [removed]alert&#40;'Hack'&#41;;[removed] your site", $this->input->post('harm', TRUE));
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_get_post()
+	{
+		$_SERVER['REQUEST_METHOD'] = 'POST';
+		$_POST['foo'] = 'bar';
+
+		$this->assertEquals('bar', $this->input->get_post('foo'));
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_cookie()
+	{
+		$_COOKIE['foo'] = 'bar';
+
+		$this->assertEquals('bar', $this->input->cookie('foo'));
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_server()
+	{
+		$this->assertEquals('GET', $this->input->server('REQUEST_METHOD'));
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_fetch_from_array()
+	{
+		$data = array(
+			'foo' => 'bar',
+			'harm' => 'Hello, i try to <script>alert(\'Hack\');</script> your site',
+		);
+
+		$foo = $this->input->fetch_from_array($data, 'foo');
+		$harm = $this->input->fetch_from_array($data, 'harm');
+		$harmless = $this->input->fetch_from_array($data, 'harm', TRUE);
+
+		$this->assertEquals('bar', $foo);
+		$this->assertEquals("Hello, i try to <script>alert('Hack');</script> your site", $harm);
+		$this->assertEquals("Hello, i try to [removed]alert&#40;'Hack'&#41;;[removed] your site", $harmless);
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_valid_ip()
+	{
+		$ip_v4 = '192.18.0.1';
+		$this->assertTrue($this->input->valid_ip($ip_v4));
+
+		$ip_v6 = array('2001:0db8:0000:85a3:0000:0000:ac1f:8001', '2001:db8:0:85a3:0:0:ac1f:8001', '2001:db8:0:85a3::ac1f:8001');
+		foreach ($ip_v6 as $ip)
+		{
+			$this->assertTrue($this->input->valid_ip($ip));
+		}
+	}
+
+}
\ No newline at end of file
diff --git a/tests/codeigniter/core/Lang_test.php b/tests/codeigniter/core/Lang_test.php
new file mode 100644
index 0000000..a410dab
--- /dev/null
+++ b/tests/codeigniter/core/Lang_test.php
@@ -0,0 +1,32 @@
+<?php
+
+class Lang_test extends CI_TestCase {
+
+	protected $lang;
+
+	public function set_up()
+	{
+		$loader_cls = $this->ci_core_class('load');
+		$this->ci_instance_var('load', new $loader_cls);
+
+		$cls = $this->ci_core_class('lang');
+		$this->lang = new $cls;
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_load()
+	{
+		$this->assertTrue($this->lang->load('profiler', 'english'));
+		$this->assertEquals('URI STRING', $this->lang->line('profiler_uri_string'));
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_load_with_unspecified_language()
+	{
+		$this->assertTrue($this->lang->load('profiler'));
+		$this->assertEquals('URI STRING', $this->lang->line('profiler_uri_string'));
+	}
+
+}
\ No newline at end of file
diff --git a/tests/codeigniter/core/Loader_test.php b/tests/codeigniter/core/Loader_test.php
new file mode 100644
index 0000000..fdea962
--- /dev/null
+++ b/tests/codeigniter/core/Loader_test.php
@@ -0,0 +1,221 @@
+<?php
+
+class Loader_test extends CI_TestCase {
+
+	private $ci_obj;
+
+	public function set_up()
+	{
+		// Instantiate a new loader
+		$this->load = new Mock_Core_Loader();
+
+		// mock up a ci instance
+		$this->ci_obj = new stdClass;
+
+		// Fix get_instance()
+		$this->ci_instance($this->ci_obj);
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_library()
+	{
+		$this->_setup_config_mock();
+
+		// Test loading as an array.
+		$this->assertNull($this->load->library(array('table')));
+		$this->assertTrue(class_exists('CI_Table'), 'Table class exists');
+		$this->assertAttributeInstanceOf('CI_Table', 'table', $this->ci_obj);
+
+		// Test no lib given
+		$this->assertEquals(FALSE, $this->load->library());
+
+		// Test a string given to params
+		$this->assertEquals(NULL, $this->load->library('table', ' '));
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_load_library_in_application_dir()
+	{
+		$this->_setup_config_mock();
+
+		$content = '<?php class Super_test_library {} ';
+
+		$model = vfsStream::newFile('Super_test_library.php')->withContent($content)->at($this->load->libs_dir);
+		$this->assertNull($this->load->library('super_test_library'));
+
+		// Was the model class instantiated.
+		$this->assertTrue(class_exists('Super_test_library'));
+	}
+
+	// --------------------------------------------------------------------
+
+	private function _setup_config_mock()
+	{
+		// Mock up a config object until we
+		// figure out how to test the library configs
+		$config = $this->getMock('CI_Config', NULL, array(), '', FALSE);
+		$config->expects($this->any())
+			   ->method('load')
+			   ->will($this->returnValue(TRUE));
+
+		// Add the mock to our stdClass
+		$this->ci_instance_var('config', $config);
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_non_existent_model()
+	{
+		$this->setExpectedException(
+			'RuntimeException',
+			'CI Error: Unable to locate the model you have specified: ci_test_nonexistent_model.php'
+		);
+
+		$this->load->model('ci_test_nonexistent_model.php');
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * @coverts CI_Loader::model
+	 */
+	public function test_models()
+	{
+		$this->ci_set_core_class('model', 'CI_Model');
+
+		$content = '<?php class Unit_test_model extends CI_Model {} ';
+
+		$model = vfsStream::newFile('unit_test_model.php')->withContent($content)->at($this->load->models_dir);
+
+		$this->assertNull($this->load->model('unit_test_model'));
+
+		// Was the model class instantiated.
+		$this->assertTrue(class_exists('Unit_test_model'));
+
+		// Test no model given
+		$this->assertNull($this->load->model(''));
+	}
+
+	// --------------------------------------------------------------------
+
+	// public function testDatabase()
+	// {
+	// 	$this->assertEquals(NULL, $this->load->database());
+	// 	$this->assertEquals(NULL, $this->load->dbutil());
+	// }
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * @coverts CI_Loader::view
+	 */
+	public function test_load_view()
+	{
+		$this->ci_set_core_class('output', 'CI_Output');
+
+		$content = 'This is my test page.  <?php echo $hello; ?>';
+		$view = vfsStream::newFile('unit_test_view.php')->withContent($content)->at($this->load->views_dir);
+
+		// Use the optional return parameter in this test, so the view is not
+		// run through the output class.
+		$this->assertEquals('This is my test page.  World!',
+		$this->load->view('unit_test_view', array('hello' => "World!"), TRUE));
+
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * @coverts CI_Loader::view
+	 */
+	public function test_non_existent_view()
+	{
+		$this->setExpectedException(
+			'RuntimeException',
+			'CI Error: Unable to load the requested file: ci_test_nonexistent_view.php'
+		);
+
+		$this->load->view('ci_test_nonexistent_view', array('foo' => 'bar'));
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_file()
+	{
+		$content = 'Here is a test file, which we will load now.';
+		$file = vfsStream::newFile('ci_test_mock_file.php')->withContent($content)->at($this->load->views_dir);
+
+		// Just like load->view(), take the output class out of the mix here.
+		$load = $this->load->file(vfsStream::url('application').'/views/ci_test_mock_file.php', TRUE);
+
+		$this->assertEquals($content, $load);
+
+		$this->setExpectedException(
+			'RuntimeException',
+			'CI Error: Unable to load the requested file: ci_test_file_not_exists'
+		);
+
+		$this->load->file('ci_test_file_not_exists', TRUE);
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_vars()
+	{
+		$this->assertNull($this->load->vars(array('foo' => 'bar')));
+		$this->assertNull($this->load->vars('foo', 'bar'));
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_helper()
+	{
+		$this->assertEquals(NULL, $this->load->helper('array'));
+
+		$this->setExpectedException(
+			'RuntimeException',
+			'CI Error: Unable to load the requested file: helpers/bad_helper.php'
+		);
+
+		$this->load->helper('bad');
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_loading_multiple_helpers()
+	{
+		$this->assertEquals(NULL, $this->load->helpers(array('file', 'array', 'string')));
+	}
+
+	// --------------------------------------------------------------------
+
+	// public function testLanguage()
+	// {
+	// 	$this->assertEquals(NULL, $this->load->language('test'));
+	// }
+
+	// --------------------------------------------------------------------
+
+	public function test_load_config()
+	{
+		$this->_setup_config_mock();
+		$this->assertNull($this->load->config('config', FALSE));
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_load_bad_config()
+	{
+		$this->_setup_config_mock();
+
+		$this->setExpectedException(
+			'RuntimeException',
+			'CI Error: The configuration file foobar.php does not exist.'
+		);
+
+		$this->load->config('foobar', FALSE);
+	}
+
+}
\ No newline at end of file
diff --git a/tests/codeigniter/core/Security_test.php b/tests/codeigniter/core/Security_test.php
new file mode 100644
index 0000000..3f6e3b0
--- /dev/null
+++ b/tests/codeigniter/core/Security_test.php
@@ -0,0 +1,106 @@
+<?php
+
+class Security_test extends CI_TestCase {
+
+	public function set_up()
+	{
+		// Set cookie for security test
+		$_COOKIE['ci_csrf_cookie'] = md5(uniqid(rand(), TRUE));
+
+		// Set config for Security class
+		$this->ci_set_config('csrf_protection', TRUE);
+		$this->ci_set_config('csrf_token_name', 'ci_csrf_token');
+		$this->ci_set_config('csrf_cookie_name', 'ci_csrf_cookie');
+
+		$this->security = new Mock_Core_Security();
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_csrf_verify()
+	{
+		$_SERVER['REQUEST_METHOD'] = 'GET';
+
+		$this->assertInstanceOf('CI_Security', $this->security->csrf_verify());
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_csrf_verify_invalid()
+	{
+		// Without issuing $_POST[csrf_token_name], this request will triggering CSRF error
+		$_SERVER['REQUEST_METHOD'] = 'POST';
+
+		$this->setExpectedException('RuntimeException', 'CI Error: The action you have requested is not allowed');
+
+		$this->security->csrf_verify();
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_csrf_verify_valid()
+	{
+		$_SERVER['REQUEST_METHOD'] = 'POST';
+		$_POST[$this->security->csrf_token_name] = $this->security->csrf_hash;
+
+		$this->assertInstanceOf('CI_Security', $this->security->csrf_verify());
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_get_csrf_hash()
+	{
+		$this->assertEquals($this->security->csrf_hash, $this->security->get_csrf_hash());
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_get_csrf_token_name()
+	{
+		$this->assertEquals('ci_csrf_token', $this->security->get_csrf_token_name());
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_xss_clean()
+	{
+		$harm_string = "Hello, i try to <script>alert('Hack');</script> your site";
+
+		$harmless_string = $this->security->xss_clean($harm_string);
+
+		$this->assertEquals("Hello, i try to [removed]alert&#40;'Hack'&#41;;[removed] your site", $harmless_string);
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_xss_hash()
+	{
+		$this->assertEmpty($this->security->xss_hash);
+
+		// Perform hash
+		$this->security->xss_hash();
+
+		$this->assertTrue(preg_match('#^[0-9a-f]{32}$#iS', $this->security->xss_hash) === 1);
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_entity_decode()
+	{
+		$encoded = '&lt;div&gt;Hello &lt;b&gt;Booya&lt;/b&gt;&lt;/div&gt;';
+		$decoded = $this->security->entity_decode($encoded);
+
+		$this->assertEquals('<div>Hello <b>Booya</b></div>', $decoded);
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_sanitize_filename()
+	{
+		$filename = './<!--foo-->';
+		$safe_filename = $this->security->sanitize_filename($filename);
+
+		$this->assertEquals('foo', $safe_filename);
+	}
+
+}
\ No newline at end of file
diff --git a/tests/codeigniter/core/URI_test.php b/tests/codeigniter/core/URI_test.php
new file mode 100644
index 0000000..0ba694b
--- /dev/null
+++ b/tests/codeigniter/core/URI_test.php
@@ -0,0 +1,276 @@
+<?php
+
+class URI_test extends CI_TestCase {
+
+	public function set_up()
+	{
+		$this->uri = new Mock_Core_URI();
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_set_uri_string()
+	{
+		// Slashes get killed
+		$this->uri->_set_uri_string('/');
+		$this->assertEquals('', $this->uri->uri_string);
+
+		$this->uri->_set_uri_string('nice/uri');
+		$this->assertEquals('nice/uri', $this->uri->uri_string);
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_fetch_uri_string()
+	{
+		define('SELF', 'index.php');
+
+		// uri_protocol: AUTO
+		$this->uri->config->set_item('uri_protocol', 'AUTO');
+
+		// Test a variety of request uris
+		$requests = array(
+			'/index.php/controller/method' => 'controller/method',
+			'/index.php?/controller/method' => 'controller/method',
+			'/index.php?/controller/method/?var=foo' => 'controller/method'
+		);
+
+		foreach($requests as $request => $expected)
+		{
+			$_SERVER['SCRIPT_NAME'] = '/index.php';
+			$_SERVER['REQUEST_URI'] = $request;
+
+			$this->uri->_fetch_uri_string();
+			$this->assertEquals($expected, $this->uri->uri_string );
+		}
+
+		// Test a subfolder
+		$_SERVER['SCRIPT_NAME'] = '/subfolder/index.php';
+		$_SERVER['REQUEST_URI'] = '/subfolder/index.php/controller/method';
+
+		$this->uri->_fetch_uri_string();
+		$this->assertEquals('controller/method', $this->uri->uri_string);
+
+		// death to request uri
+		unset($_SERVER['REQUEST_URI']);
+
+		// life to path info
+		$_SERVER['PATH_INFO'] = $a = '/controller/method/';
+
+		$this->uri->_fetch_uri_string();
+		$this->assertEquals($a, $this->uri->uri_string);
+
+		// death to path info
+		// At this point your server must be seriously drunk
+		unset($_SERVER['PATH_INFO']);
+
+		$_SERVER['QUERY_STRING'] = '/controller/method/';
+
+		$this->uri->_fetch_uri_string();
+		$this->assertEquals($a, $this->uri->uri_string);
+
+		// At this point your server is a labotomy victim
+		unset($_SERVER['QUERY_STRING']);
+
+		$_GET['/controller/method/'] = '';
+
+		$this->uri->_fetch_uri_string();
+		$this->assertEquals($a, $this->uri->uri_string);
+
+		// Test coverage implies that these will work
+		// uri_protocol: REQUEST_URI
+		// uri_protocol: CLI
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_explode_segments()
+	{
+		// Lets test the function's ability to clean up this mess
+		$uris = array(
+			'test/uri' => array('test', 'uri'),
+			'/test2/uri2' => array('test2', 'uri2'),
+			'//test3/test3///' => array('test3', 'test3')
+		);
+
+		foreach ($uris as $uri => $a)
+		{
+			$this->uri->segments = array();
+			$this->uri->uri_string = $uri;
+			$this->uri->_explode_segments();
+
+			$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~%.:_\-');
+
+		$str_in = 'abc01239~%.:_-';
+		$str = $this->uri->_filter_uri($str_in);
+
+		$this->assertEquals($str, $str_in);
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_filter_uri_escaping()
+	{
+		// ensure escaping even if dodgey characters are permitted
+
+		$this->uri->config->set_item('enable_query_strings', FALSE);
+		$this->uri->config->set_item('permitted_uri_chars', 'a-z 0-9~%.:_\-()$');
+
+		$str = $this->uri->_filter_uri('$destroy_app(foo)');
+
+		$this->assertEquals($str, '&#36;destroy_app&#40;foo&#41;');
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_filter_uri_throws_error()
+	{
+		$this->setExpectedException('RuntimeException');
+
+		$this->uri->config->set_item('enable_query_strings', FALSE);
+		$this->uri->config->set_item('permitted_uri_chars', 'a-z 0-9~%.:_\-');
+		$this->uri->_filter_uri('$this()');
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_remove_url_suffix()
+	{
+		$this->uri->config->set_item('url_suffix', '.html');
+
+		$this->uri->uri_string = 'controller/method/index.html';
+		$this->uri->_remove_url_suffix();
+
+		$this->assertEquals($this->uri->uri_string, 'controller/method/index');
+
+		$this->uri->uri_string = 'controller/method/index.htmlify.html';
+		$this->uri->_remove_url_suffix();
+
+		$this->assertEquals($this->uri->uri_string, 'controller/method/index.htmlify');
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_segment()
+	{
+		$this->uri->segments = array(1 => 'controller');
+		$this->assertEquals($this->uri->segment(1), 'controller');
+		$this->assertEquals($this->uri->segment(2, 'default'), 'default');
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_rsegment()
+	{
+		$this->uri->rsegments = array(1 => 'method');
+		$this->assertEquals($this->uri->rsegment(1), 'method');
+		$this->assertEquals($this->uri->rsegment(2, 'default'), 'default');
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_uri_to_assoc()
+	{
+		$this->uri->segments = array('a', '1', 'b', '2', 'c', '3');
+
+		$this->assertEquals(
+			array('a' => '1', 'b' => '2', 'c' => '3'),
+			$this->uri->uri_to_assoc(1)
+		);
+
+		$this->assertEquals(
+			array('b' => '2', 'c' => '3'),
+			$this->uri->uri_to_assoc(3)
+		);
+
+		$this->uri->keyval = array(); // reset cache
+		$this->uri->segments = array('a', '1', 'b', '2', 'c');
+
+		$this->assertEquals(
+			array('a' => '1', 'b' => '2', 'c' => FALSE),
+			$this->uri->uri_to_assoc(1)
+		);
+
+		$this->uri->keyval = array(); // reset cache
+		$this->uri->segments = array('a', '1');
+
+		// test default
+		$this->assertEquals(
+			array('a' => '1', 'b' => FALSE),
+			$this->uri->uri_to_assoc(1, array('a', 'b'))
+		);
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_ruri_to_assoc()
+	{
+		$this->uri->rsegments = array('x', '1', 'y', '2', 'z', '3');
+
+		$this->assertEquals(
+			array('x' => '1', 'y' => '2', 'z' => '3'),
+			$this->uri->ruri_to_assoc(1)
+		);
+
+		$this->assertEquals(
+			array('y' => '2', 'z' => '3'),
+			$this->uri->ruri_to_assoc(3)
+		);
+
+		$this->uri->keyval = array(); // reset cache
+		$this->uri->rsegments = array('x', '1', 'y', '2', 'z');
+
+		$this->assertEquals(
+			array('x' => '1', 'y' => '2', 'z' => FALSE),
+			$this->uri->ruri_to_assoc(1)
+		);
+
+		$this->uri->keyval = array(); // reset cache
+		$this->uri->rsegments = array('x', '1');
+
+		// test default
+		$this->assertEquals(
+			array('x' => '1', 'y' => FALSE),
+			$this->uri->ruri_to_assoc(1, array('x', 'y'))
+		);
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_assoc_to_uri()
+	{
+		$this->uri->config->set_item('uri_string_slashes', 'none');
+		$this->assertEquals('a/1/b/2', $this->uri->assoc_to_uri(array('a' => '1', 'b' => '2')));
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_slash_segment()
+	{
+		$this->uri->segments[1] = 'segment';
+		$this->uri->rsegments[1] = 'segment';
+
+		$this->assertEquals('/segment/', $this->uri->slash_segment(1, 'both'));
+		$this->assertEquals('/segment/', $this->uri->slash_rsegment(1, 'both'));
+
+		$a = '/segment';
+		$this->assertEquals('/segment', $this->uri->slash_segment(1, 'leading'));
+		$this->assertEquals('/segment', $this->uri->slash_rsegment(1, 'leading'));
+
+		$this->assertEquals('segment/', $this->uri->slash_segment(1, 'trailing'));
+		$this->assertEquals('segment/', $this->uri->slash_rsegment(1, 'trailing'));
+	}
+
+}
+
+/* End of file URI_test.php */
+/* Location: ./tests/core/URI_test.php */
\ No newline at end of file
diff --git a/tests/codeigniter/database/DB_driver_test.php b/tests/codeigniter/database/DB_driver_test.php
new file mode 100644
index 0000000..9e16e29
--- /dev/null
+++ b/tests/codeigniter/database/DB_driver_test.php
@@ -0,0 +1,34 @@
+<?php
+
+class DB_driver_test extends CI_TestCase {
+
+	public function test_initialize()
+	{
+		$config = Mock_Database_DB::config(DB_DRIVER);
+		$driver_name = current(explode('/', DB_DRIVER));
+		$driver = $this->$driver_name($config[DB_DRIVER]);
+
+		$this->assertTrue($driver->initialize());
+	}
+
+	protected function pdo($config)
+	{
+		return new Mock_Database_Drivers_PDO($config);
+	}
+
+	protected function mysql($config)
+	{
+		return new Mock_Database_Drivers_Mysql($config);
+	}
+
+	protected function sqlite($config)
+	{
+		return new Mock_Database_Drivers_Sqlite($config);
+	}
+
+	protected function pgsql($config)
+	{
+		return new Mock_Database_Drivers_Postgre($config);
+	}
+
+}
\ No newline at end of file
diff --git a/tests/codeigniter/database/DB_test.php b/tests/codeigniter/database/DB_test.php
new file mode 100644
index 0000000..d5c0dea
--- /dev/null
+++ b/tests/codeigniter/database/DB_test.php
@@ -0,0 +1,47 @@
+<?php
+
+class DB_test extends CI_TestCase {
+
+	public function test_db_invalid()
+	{
+		$connection = new Mock_Database_DB(array(
+			'undefined' => array(
+				'dsn' => '',
+				'hostname' => 'undefined',
+				'username' => 'undefined',
+				'password' => 'undefined',
+				'database' => 'undefined',
+				'dbdriver' => 'undefined',
+			),
+		));
+
+		$this->setExpectedException('InvalidArgumentException', 'CI Error: Invalid DB driver');
+
+		Mock_Database_DB::DB($connection->set_dsn('undefined'), TRUE);
+	}
+
+	// ------------------------------------------------------------------------
+
+	public function test_db_valid()
+	{
+		$config = Mock_Database_DB::config(DB_DRIVER);
+		$connection = new Mock_Database_DB($config);
+		$db = Mock_Database_DB::DB($connection->set_dsn(DB_DRIVER), TRUE);
+
+		$this->assertTrue($db instanceof CI_DB);
+		$this->assertTrue($db instanceof CI_DB_Driver);
+	}
+
+	// ------------------------------------------------------------------------
+
+	public function test_db_failover()
+	{
+		$config = Mock_Database_DB::config(DB_DRIVER);
+		$connection = new Mock_Database_DB($config);
+		$db = Mock_Database_DB::DB($connection->set_dsn(DB_DRIVER.'_failover'), TRUE);
+
+		$this->assertTrue($db instanceof CI_DB);
+		$this->assertTrue($db instanceof CI_DB_Driver);
+	}
+
+}
\ No newline at end of file
diff --git a/tests/codeigniter/database/query_builder/count_test.php b/tests/codeigniter/database/query_builder/count_test.php
new file mode 100644
index 0000000..90ac528
--- /dev/null
+++ b/tests/codeigniter/database/query_builder/count_test.php
@@ -0,0 +1,38 @@
+<?php
+
+class Count_test extends CI_TestCase {
+
+	/**
+	 * @var object Database/Query Builder holder
+	 */
+	protected $db;
+
+	public function set_up()
+	{
+		$this->db = Mock_Database_Schema_Skeleton::init(DB_DRIVER);
+
+		Mock_Database_Schema_Skeleton::create_tables();
+		Mock_Database_Schema_Skeleton::create_data();
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * @see ./mocks/schema/skeleton.php
+	 */
+	public function test_count_all()
+	{
+		$this->assertEquals(4, $this->db->count_all('job'));
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * @see ./mocks/schema/skeleton.php
+	 */
+	public function test_count_all_results()
+	{
+		$this->assertEquals(2, $this->db->like('name', 'ian')->count_all_results('job'));
+	}
+
+}
\ No newline at end of file
diff --git a/tests/codeigniter/database/query_builder/delete_test.php b/tests/codeigniter/database/query_builder/delete_test.php
new file mode 100644
index 0000000..ab9d97f
--- /dev/null
+++ b/tests/codeigniter/database/query_builder/delete_test.php
@@ -0,0 +1,64 @@
+<?php
+
+class Delete_test extends CI_TestCase {
+
+	/**
+	 * @var object Database/Query Builder holder
+	 */
+	protected $db;
+
+	public function set_up()
+	{
+		$this->db = Mock_Database_Schema_Skeleton::init(DB_DRIVER);
+
+		Mock_Database_Schema_Skeleton::create_tables();
+		Mock_Database_Schema_Skeleton::create_data();
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * @see ./mocks/schema/skeleton.php
+	 */
+	public function test_delete()
+	{
+		// Check initial record
+		$job1 = $this->db->where('id', 1)->get('job')->row();
+
+		$this->assertEquals('Developer', $job1->name);
+
+		// Do the delete
+		$this->db->delete('job', array('id' => 1));
+
+		// Check the record
+		$job1 = $this->db->where('id', 1)->get('job');
+
+		$this->assertEmpty($job1->result_array());
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * @see ./mocks/schema/skeleton.php
+	 */
+	public function test_delete_several_tables()
+	{
+		// Check initial record
+		$user4 = $this->db->where('id', 4)->get('user')->row();
+		$job4 = $this->db->where('id', 4)->get('job')->row();
+
+		$this->assertEquals('Musician', $job4->name);
+		$this->assertEquals('Chris Martin', $user4->name);
+
+		// Do the delete
+		$this->db->delete(array('job', 'user'), array('id' => 4));
+
+		// Check the record
+		$job4 = $this->db->where('id', 4)->get('job');
+		$user4 = $this->db->where('id', 4)->get('user');
+
+		$this->assertEmpty($job4->result_array());
+		$this->assertEmpty($user4->result_array());
+	}
+
+}
\ No newline at end of file
diff --git a/tests/codeigniter/database/query_builder/distinct_test.php b/tests/codeigniter/database/query_builder/distinct_test.php
new file mode 100644
index 0000000..cc98009
--- /dev/null
+++ b/tests/codeigniter/database/query_builder/distinct_test.php
@@ -0,0 +1,33 @@
+<?php
+
+class Distinct_test extends CI_TestCase {
+
+	/**
+	 * @var object Database/Query Builder holder
+	 */
+	protected $db;
+
+	public function set_up()
+	{
+		$this->db = Mock_Database_Schema_Skeleton::init(DB_DRIVER);
+
+		Mock_Database_Schema_Skeleton::create_tables();
+		Mock_Database_Schema_Skeleton::create_data();
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * @see ./mocks/schema/skeleton.php
+	 */
+	public function test_distinct()
+	{
+		$users = $this->db->select('country')
+					->distinct()
+					->get('user')
+					->result_array();
+
+		$this->assertEquals(3, count($users));
+	}
+
+}
\ No newline at end of file
diff --git a/tests/codeigniter/database/query_builder/empty_test.php b/tests/codeigniter/database/query_builder/empty_test.php
new file mode 100644
index 0000000..d1f5628
--- /dev/null
+++ b/tests/codeigniter/database/query_builder/empty_test.php
@@ -0,0 +1,39 @@
+<?php
+
+class Empty_test extends CI_TestCase {
+
+	/**
+	 * @var object Database/Query Builder holder
+	 */
+	protected $db;
+
+	public function set_up()
+	{
+		$this->db = Mock_Database_Schema_Skeleton::init(DB_DRIVER);
+
+		Mock_Database_Schema_Skeleton::create_tables();
+		Mock_Database_Schema_Skeleton::create_data();
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * @see ./mocks/schema/skeleton.php
+	 */
+	public function test_empty_table()
+	{
+		// Check initial record
+		$jobs = $this->db->get('job')->result_array();
+
+		$this->assertEquals(4, count($jobs));
+
+		// Do the empty
+		$this->db->empty_table('job');
+
+		// Check the record
+		$jobs = $this->db->get('job');
+
+		$this->assertEmpty($jobs->result_array());
+	}
+
+}
\ No newline at end of file
diff --git a/tests/codeigniter/database/query_builder/escape_test.php b/tests/codeigniter/database/query_builder/escape_test.php
new file mode 100644
index 0000000..c6380dd
--- /dev/null
+++ b/tests/codeigniter/database/query_builder/escape_test.php
@@ -0,0 +1,68 @@
+<?php
+
+class Escape_test extends CI_TestCase {
+
+	/**
+	 * @var object Database/Query Builder holder
+	 */
+	protected $db;
+
+	public function set_up()
+	{
+		$this->db = Mock_Database_Schema_Skeleton::init(DB_DRIVER);
+
+		Mock_Database_Schema_Skeleton::create_tables();
+		Mock_Database_Schema_Skeleton::create_data();
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * @see ./mocks/schema/skeleton.php
+	 */
+	public function test_escape_like_percent_sign()
+	{
+		// Escape the like string
+		$string = $this->db->escape_like_str('\%foo');
+
+		if (strpos(DB_DRIVER, 'mysql') !== FALSE)
+		{
+			$sql = "SELECT `value` FROM `misc` WHERE `key` LIKE '$string%' ESCAPE '';";
+		}
+		else
+		{
+			$sql = 'SELECT "value" FROM "misc" WHERE "key" LIKE \''.$string.'%\' ESCAPE \'!\';';
+		}
+
+		$res = $this->db->query($sql)->result_array();
+
+		// Check the result
+		$this->assertEquals(1, count($res));
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * @see ./mocks/schema/skeleton.php
+	 */
+	public function test_escape_like_backslash_sign()
+	{
+		// Escape the like string
+		$string = $this->db->escape_like_str('\\');
+
+		if (strpos(DB_DRIVER, 'mysql') !== FALSE)
+		{
+			$sql = "SELECT `value` FROM `misc` WHERE `key` LIKE '$string%' ESCAPE '';";
+		}
+		else
+		{
+			$sql = 'SELECT "value" FROM "misc" WHERE "key" LIKE \''.$string.'%\' ESCAPE \'!\';';
+		}
+
+		$res = $this->db->query($sql)->result_array();
+
+		// Check the result
+		$this->assertEquals(2, count($res));
+	}
+
+}
\ No newline at end of file
diff --git a/tests/codeigniter/database/query_builder/from_test.php b/tests/codeigniter/database/query_builder/from_test.php
new file mode 100644
index 0000000..7aaae34
--- /dev/null
+++ b/tests/codeigniter/database/query_builder/from_test.php
@@ -0,0 +1,49 @@
+<?php
+
+class From_test extends CI_TestCase {
+
+	/**
+	 * @var object Database/Query Builder holder
+	 */
+	protected $db;
+
+	public function set_up()
+	{
+		$this->db = Mock_Database_Schema_Skeleton::init(DB_DRIVER);
+
+		Mock_Database_Schema_Skeleton::create_tables();
+		Mock_Database_Schema_Skeleton::create_data();
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * @see ./mocks/schema/skeleton.php
+	 */
+	public function test_from_simple()
+	{
+		$jobs = $this->db->from('job')
+					->get()
+					->result_array();
+
+		$this->assertEquals(4, count($jobs));
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * @see ./mocks/schema/skeleton.php
+	 */
+	public function test_from_with_where()
+	{
+		$job1 = $this->db->from('job')
+					->where('id', 1)
+					->get()
+					->row();
+
+		$this->assertEquals('1', $job1->id);
+		$this->assertEquals('Developer', $job1->name);
+		$this->assertEquals('Awesome job, but sometimes makes you bored', $job1->description);
+	}
+
+}
\ No newline at end of file
diff --git a/tests/codeigniter/database/query_builder/get_test.php b/tests/codeigniter/database/query_builder/get_test.php
new file mode 100644
index 0000000..699d290
--- /dev/null
+++ b/tests/codeigniter/database/query_builder/get_test.php
@@ -0,0 +1,53 @@
+<?php
+
+class Get_test extends CI_TestCase {
+
+	/**
+	 * @var object Database/Query Builder holder
+	 */
+	protected $db;
+
+	public function set_up()
+	{
+		$this->db = Mock_Database_Schema_Skeleton::init(DB_DRIVER);
+
+		Mock_Database_Schema_Skeleton::create_tables();
+		Mock_Database_Schema_Skeleton::create_data();
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * @see ./mocks/schema/skeleton.php
+	 */
+	public function test_get_simple()
+	{
+		$jobs = $this->db->get('job')->result_array();
+
+		// Dummy jobs contain 4 rows
+		$this->assertCount(4, $jobs);
+
+		// Check rows item
+		$this->assertEquals('Developer', $jobs[0]['name']);
+		$this->assertEquals('Politician', $jobs[1]['name']);
+		$this->assertEquals('Accountant', $jobs[2]['name']);
+		$this->assertEquals('Musician', $jobs[3]['name']);
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * @see ./mocks/schema/skeleton.php
+	 */
+	public function test_get_where()
+	{
+		$job1 = $this->db->get('job', array('id' => 1))->result_array();
+
+		// Dummy jobs contain 1 rows
+		$this->assertCount(1, $job1);
+
+		// Check rows item
+		$this->assertEquals('Developer', $job1[0]['name']);
+	}
+
+}
\ No newline at end of file
diff --git a/tests/codeigniter/database/query_builder/group_test.php b/tests/codeigniter/database/query_builder/group_test.php
new file mode 100644
index 0000000..5249f7c
--- /dev/null
+++ b/tests/codeigniter/database/query_builder/group_test.php
@@ -0,0 +1,51 @@
+<?php
+
+class Group_test extends CI_TestCase {
+
+	/**
+	 * @var object Database/Query Builder holder
+	 */
+	protected $db;
+
+	public function set_up()
+	{
+		$this->db = Mock_Database_Schema_Skeleton::init(DB_DRIVER);
+
+		Mock_Database_Schema_Skeleton::create_tables();
+		Mock_Database_Schema_Skeleton::create_data();
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * @see ./mocks/schema/skeleton.php
+	 */
+	public function test_group_by()
+	{
+		$jobs = $this->db->select('name')
+					->from('job')
+					->group_by('name')
+					->get()
+					->result_array();
+
+		$this->assertEquals(4, count($jobs));
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * @see ./mocks/schema/skeleton.php
+	 */
+	public function test_having_by()
+	{
+		$jobs = $this->db->select('name')
+					->from('job')
+					->group_by('name')
+					->having('SUM(id) > 2')
+					->get()
+					->result_array();
+
+		$this->assertEquals(2, count($jobs));
+	}
+
+}
\ No newline at end of file
diff --git a/tests/codeigniter/database/query_builder/insert_test.php b/tests/codeigniter/database/query_builder/insert_test.php
new file mode 100644
index 0000000..a9aafb6
--- /dev/null
+++ b/tests/codeigniter/database/query_builder/insert_test.php
@@ -0,0 +1,66 @@
+<?php
+
+class Insert_test extends CI_TestCase {
+
+	/**
+	 * @var object Database/Query Builder holder
+	 * @see ./mocks/schema/skeleton.php
+	 */
+	protected $db;
+
+	public function set_up()
+	{
+		$this->db = Mock_Database_Schema_Skeleton::init(DB_DRIVER);
+
+		Mock_Database_Schema_Skeleton::create_tables();
+
+		// Truncate the current datas
+		$this->db->truncate('job');
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * @see ./mocks/schema/skeleton.php
+	 */
+	public function test_insert()
+	{
+		$job_data = array('id' => 1, 'name' => 'Grocery Sales', 'description' => 'Discount!');
+
+		// Do normal insert
+		$this->assertTrue($this->db->insert('job', $job_data));
+
+		$job1 = $this->db->get('job')->row();
+
+		// Check the result
+		$this->assertEquals('Grocery Sales', $job1->name);
+
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * @see ./mocks/schema/skeleton.php
+	 */
+	public function test_insert_batch()
+	{
+		$job_datas = array(
+			array('id' => 2, 'name' => 'Commedian', 'description' => 'Theres something in your teeth'),
+			array('id' => 3, 'name' => 'Cab Driver', 'description' => 'Iam yellow'),
+		);
+
+		// Do insert batch except for sqlite driver
+		if (strpos(DB_DRIVER, 'sqlite') === FALSE)
+		{
+			$this->assertTrue($this->db->insert_batch('job', $job_datas));
+
+			$job_2 = $this->db->where('id', 2)->get('job')->row();
+			$job_3 = $this->db->where('id', 3)->get('job')->row();
+
+			// Check the result
+			$this->assertEquals('Commedian', $job_2->name);
+			$this->assertEquals('Cab Driver', $job_3->name);
+		}
+	}
+
+}
\ No newline at end of file
diff --git a/tests/codeigniter/database/query_builder/join_test.php b/tests/codeigniter/database/query_builder/join_test.php
new file mode 100644
index 0000000..b8cf2a8
--- /dev/null
+++ b/tests/codeigniter/database/query_builder/join_test.php
@@ -0,0 +1,38 @@
+<?php
+
+class Join_test extends CI_TestCase {
+
+	/**
+	 * @var object Database/Query Builder holder
+	 */
+	protected $db;
+
+	public function set_up()
+	{
+		$this->db = Mock_Database_Schema_Skeleton::init(DB_DRIVER);
+
+		Mock_Database_Schema_Skeleton::create_tables();
+		Mock_Database_Schema_Skeleton::create_data();
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * @see ./mocks/schema/skeleton.php
+	 */
+	public function test_join_simple()
+	{
+		$job_user = $this->db->select('job.id as job_id, job.name as job_name, user.id as user_id, user.name as user_name')
+							->from('job')
+							->join('user', 'user.id = job.id')
+							->get()
+							->result_array();
+
+		// Check the result
+		$this->assertEquals('1', $job_user[0]['job_id']);
+		$this->assertEquals('1', $job_user[0]['user_id']);
+		$this->assertEquals('Derek Jones', $job_user[0]['user_name']);
+		$this->assertEquals('Developer', $job_user[0]['job_name']);
+	}
+
+}
\ No newline at end of file
diff --git a/tests/codeigniter/database/query_builder/like_test.php b/tests/codeigniter/database/query_builder/like_test.php
new file mode 100644
index 0000000..5f3e522
--- /dev/null
+++ b/tests/codeigniter/database/query_builder/like_test.php
@@ -0,0 +1,90 @@
+<?php
+
+class Like_test extends CI_TestCase {
+
+	/**
+	 * @var object Database/Query Builder holder
+	 */
+	protected $db;
+
+	public function set_up()
+	{
+		$this->db = Mock_Database_Schema_Skeleton::init(DB_DRIVER);
+
+		Mock_Database_Schema_Skeleton::create_tables();
+		Mock_Database_Schema_Skeleton::create_data();
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * @see ./mocks/schema/skeleton.php
+	 */
+	public function test_like()
+	{
+		$job1 = $this->db->like('name', 'veloper')
+							->get('job')
+							->row();
+
+		// Check the result
+		$this->assertEquals('1', $job1->id);
+		$this->assertEquals('Developer', $job1->name);
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * @see ./mocks/schema/skeleton.php
+	 */
+	public function test_or_like()
+	{
+		$jobs = $this->db->like('name', 'ian')
+							->or_like('name', 'veloper')
+							->get('job')
+							->result_array();
+
+		// Check the result
+		$this->assertEquals(3, count($jobs));
+		$this->assertEquals('Developer', $jobs[0]['name']);
+		$this->assertEquals('Politician', $jobs[1]['name']);
+		$this->assertEquals('Musician', $jobs[2]['name']);
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * @see ./mocks/schema/skeleton.php
+	 */
+	public function test_not_like()
+	{
+		$jobs = $this->db->not_like('name', 'veloper')
+							->get('job')
+							->result_array();
+
+		// Check the result
+		$this->assertEquals(3, count($jobs));
+		$this->assertEquals('Politician', $jobs[0]['name']);
+		$this->assertEquals('Accountant', $jobs[1]['name']);
+		$this->assertEquals('Musician', $jobs[2]['name']);
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * @see ./mocks/schema/skeleton.php
+	 */
+	public function test_or_not_like()
+	{
+		$jobs = $this->db->like('name', 'an')
+							->or_not_like('name', 'veloper')
+							->get('job')
+							->result_array();
+
+		// Check the result
+		$this->assertEquals(3, count($jobs));
+		$this->assertEquals('Politician', $jobs[0]['name']);
+		$this->assertEquals('Accountant', $jobs[1]['name']);
+		$this->assertEquals('Musician', $jobs[2]['name']);
+	}
+
+}
\ No newline at end of file
diff --git a/tests/codeigniter/database/query_builder/limit_test.php b/tests/codeigniter/database/query_builder/limit_test.php
new file mode 100644
index 0000000..a0954c7
--- /dev/null
+++ b/tests/codeigniter/database/query_builder/limit_test.php
@@ -0,0 +1,48 @@
+<?php
+
+class Limit_test extends CI_TestCase {
+
+	/**
+	 * @var object Database/Query Builder holder
+	 */
+	protected $db;
+
+	public function set_up()
+	{
+		$this->db = Mock_Database_Schema_Skeleton::init(DB_DRIVER);
+
+		Mock_Database_Schema_Skeleton::create_tables();
+		Mock_Database_Schema_Skeleton::create_data();
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * @see ./mocks/schema/skeleton.php
+	 */
+	public function test_limit()
+	{
+		$jobs = $this->db->limit(2)
+		                      ->get('job')
+		                      ->result_array();
+
+		$this->assertEquals(2, count($jobs));
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * @see ./mocks/schema/skeleton.php
+	 */
+	public function test_limit_and_offset()
+	{
+		$jobs = $this->db->limit(2, 2)
+		                      ->get('job')
+		                      ->result_array();
+
+		$this->assertEquals(2, count($jobs));
+		$this->assertEquals('Accountant', $jobs[0]['name']);
+		$this->assertEquals('Musician', $jobs[1]['name']);
+	}
+
+}
\ No newline at end of file
diff --git a/tests/codeigniter/database/query_builder/order_test.php b/tests/codeigniter/database/query_builder/order_test.php
new file mode 100644
index 0000000..46f452b
--- /dev/null
+++ b/tests/codeigniter/database/query_builder/order_test.php
@@ -0,0 +1,55 @@
+<?php
+
+class Order_test extends CI_TestCase {
+
+	/**
+	 * @var object Database/Query Builder holder
+	 */
+	protected $db;
+
+	public function set_up()
+	{
+		$this->db = Mock_Database_Schema_Skeleton::init(DB_DRIVER);
+
+		Mock_Database_Schema_Skeleton::create_tables();
+		Mock_Database_Schema_Skeleton::create_data();
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * @see ./mocks/schema/skeleton.php
+	 */
+	public function test_order_ascending()
+	{
+		$jobs = $this->db->order_by('name', 'asc')
+		                      ->get('job')
+		                      ->result_array();
+
+		// Check the result
+		$this->assertEquals(4, count($jobs));
+		$this->assertEquals('Accountant', $jobs[0]['name']);
+		$this->assertEquals('Developer', $jobs[1]['name']);
+		$this->assertEquals('Musician', $jobs[2]['name']);
+		$this->assertEquals('Politician', $jobs[3]['name']);
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * @see ./mocks/schema/skeleton.php
+	 */
+	public function test_order_descending()
+	{
+		$jobs = $this->db->order_by('name', 'desc')
+		                      ->get('job')
+		                      ->result_array();
+
+		$this->assertEquals(4, count($jobs));
+		$this->assertEquals('Politician', $jobs[0]['name']);
+		$this->assertEquals('Musician', $jobs[1]['name']);
+		$this->assertEquals('Developer', $jobs[2]['name']);
+		$this->assertEquals('Accountant', $jobs[3]['name']);
+	}
+
+}
\ No newline at end of file
diff --git a/tests/codeigniter/database/query_builder/select_test.php b/tests/codeigniter/database/query_builder/select_test.php
new file mode 100644
index 0000000..877b5d8
--- /dev/null
+++ b/tests/codeigniter/database/query_builder/select_test.php
@@ -0,0 +1,95 @@
+<?php
+
+class Select_test extends CI_TestCase {
+
+	/**
+	 * @var object Database/Query Builder holder
+	 */
+	protected $db;
+
+	public function set_up()
+	{
+		$this->db = Mock_Database_Schema_Skeleton::init(DB_DRIVER);
+
+		Mock_Database_Schema_Skeleton::create_tables();
+		Mock_Database_Schema_Skeleton::create_data();
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * @see ./mocks/schema/skeleton.php
+	 */
+	public function test_select_only_one_collumn()
+	{
+		$jobs_name = $this->db->select('name')
+		                      ->get('job')
+		                      ->result_array();
+
+		// Check rows item
+		$this->assertArrayHasKey('name',$jobs_name[0]);
+		$this->assertFalse(array_key_exists('id', $jobs_name[0]));
+		$this->assertFalse(array_key_exists('description', $jobs_name[0]));
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * @see ./mocks/schema/skeleton.php
+	 */
+	public function test_select_min()
+	{
+		$job_min = $this->db->select_min('id')
+		                    ->get('job')
+		                    ->row();
+
+		// Minimum id was 1
+		$this->assertEquals('1', $job_min->id);
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * @see ./mocks/schema/skeleton.php
+	 */
+	public function test_select_max()
+	{
+		$job_max = $this->db->select_max('id')
+		                    ->get('job')
+		                    ->row();
+
+		// Maximum id was 4
+		$this->assertEquals('4', $job_max->id);
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * @see ./mocks/schema/skeleton.php
+	 */
+	public function test_select_avg()
+	{
+		$job_avg = $this->db->select_avg('id')
+		                    ->get('job')
+		                    ->row();
+
+		// Average should be 2.5
+		$this->assertEquals('2.5', $job_avg->id);
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * @see ./mocks/schema/skeleton.php
+	 */
+	public function test_select_sum()
+	{
+		$job_sum = $this->db->select_sum('id')
+		                    ->get('job')
+		                    ->row();
+
+		// Sum of ids should be 10
+		$this->assertEquals('10', $job_sum->id);
+	}
+
+}
\ No newline at end of file
diff --git a/tests/codeigniter/database/query_builder/truncate_test.php b/tests/codeigniter/database/query_builder/truncate_test.php
new file mode 100644
index 0000000..09923c7
--- /dev/null
+++ b/tests/codeigniter/database/query_builder/truncate_test.php
@@ -0,0 +1,56 @@
+<?php
+
+class Truncate_test extends CI_TestCase {
+
+	/**
+	 * @var object Database/Query Builder holder
+	 */
+	protected $db;
+
+	public function set_up()
+	{
+		$this->db = Mock_Database_Schema_Skeleton::init(DB_DRIVER);
+
+		Mock_Database_Schema_Skeleton::create_tables();
+		Mock_Database_Schema_Skeleton::create_data();
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * @see ./mocks/schema/skeleton.php
+	 */
+	public function test_truncate()
+	{
+		// Check initial record
+		$jobs = $this->db->get('job')->result_array();
+		$this->assertEquals(4, count($jobs));
+
+		// Do the empty
+		$this->db->truncate('job');
+
+		// Check the record
+		$jobs = $this->db->get('job');
+		$this->assertEmpty($jobs->result_array());
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * @see ./mocks/schema/skeleton.php
+	 */
+	public function test_truncate_with_from()
+	{
+		// Check initial record
+		$users = $this->db->get('user')->result_array();
+		$this->assertEquals(4, count($users));
+
+		// Do the empty
+		$this->db->from('user')->truncate();
+
+		// Check the record
+		$users = $this->db->get('user');
+		$this->assertEmpty($users->result_array());
+	}
+
+}
\ No newline at end of file
diff --git a/tests/codeigniter/database/query_builder/update_test.php b/tests/codeigniter/database/query_builder/update_test.php
new file mode 100644
index 0000000..27a647c
--- /dev/null
+++ b/tests/codeigniter/database/query_builder/update_test.php
@@ -0,0 +1,57 @@
+<?php
+
+class Update_test extends CI_TestCase {
+
+	/**
+	 * @var object Database/Query Builder holder
+	 */
+	protected $db;
+
+	public function set_up()
+	{
+		$this->db = Mock_Database_Schema_Skeleton::init(DB_DRIVER);
+
+		Mock_Database_Schema_Skeleton::create_tables();
+		Mock_Database_Schema_Skeleton::create_data();
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * @see ./mocks/schema/skeleton.php
+	 */
+	public function test_update()
+	{
+		// Check initial record
+		$job1 = $this->db->where('id', 1)->get('job')->row();
+		$this->assertEquals('Developer', $job1->name);
+
+		// Do the update
+		$this->db->where('id', 1)->update('job', array('name' => 'Programmer'));
+
+		// Check updated record
+		$job1 = $this->db->where('id', 1)->get('job')->row();
+		$this->assertEquals('Programmer', $job1->name);
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * @see ./mocks/schema/skeleton.php
+	 */
+	public function test_update_with_set()
+	{
+		// Check initial record
+		$job1 = $this->db->where('id', 4)->get('job')->row();
+		$this->assertEquals('Musician', $job1->name);
+
+		// Do the update
+		$this->db->set('name', 'Vocalist');
+		$this->db->update('job', NULL, 'id = 4');
+
+		// Check updated record
+		$job1 = $this->db->where('id', 4)->get('job')->row();
+		$this->assertEquals('Vocalist', $job1->name);
+	}
+
+}
\ No newline at end of file
diff --git a/tests/codeigniter/database/query_builder/where_test.php b/tests/codeigniter/database/query_builder/where_test.php
new file mode 100644
index 0000000..20b7a56
--- /dev/null
+++ b/tests/codeigniter/database/query_builder/where_test.php
@@ -0,0 +1,126 @@
+<?php
+
+class Where_test extends CI_TestCase {
+
+	/**
+	 * @var object Database/Query Builder holder
+	 */
+	protected $db;
+
+	public function set_up()
+	{
+		$this->db = Mock_Database_Schema_Skeleton::init(DB_DRIVER);
+
+		Mock_Database_Schema_Skeleton::create_tables();
+		Mock_Database_Schema_Skeleton::create_data();
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * @see ./mocks/schema/skeleton.php
+	 */
+	public function test_where_simple_key_value()
+	{
+		$job1 = $this->db->where('id', 1)->get('job')->row();
+
+		$this->assertEquals('1', $job1->id);
+		$this->assertEquals('Developer', $job1->name);
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * @see ./mocks/schema/skeleton.php
+	 */
+	public function test_where_custom_key_value()
+	{
+		$jobs = $this->db->where('id !=', 1)->get('job')->result_array();
+		$this->assertEquals(3, count($jobs));
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * @see ./mocks/schema/skeleton.php
+	 */
+	public function test_where_associative_array()
+	{
+		$where = array('id >' => 2, 'name !=' => 'Accountant');
+		$jobs = $this->db->where($where)->get('job')->result_array();
+
+		$this->assertEquals(1, count($jobs));
+
+		// Should be Musician
+		$job = current($jobs);
+		$this->assertEquals('Musician', $job['name']);
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * @see ./mocks/schema/skeleton.php
+	 */
+	public function test_where_custom_string()
+	{
+		$where = "id > 2 AND name != 'Accountant'";
+		$jobs = $this->db->where($where)->get('job')->result_array();
+
+		$this->assertEquals(1, count($jobs));
+
+		// Should be Musician
+		$job = current($jobs);
+		$this->assertEquals('Musician', $job['name']);
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * @see ./mocks/schema/skeleton.php
+	 */
+	public function test_where_or()
+	{
+		$jobs = $this->db->where('name !=', 'Accountant')
+							->or_where('id >', 3)
+							->get('job')
+							->result_array();
+
+		$this->assertEquals(3, count($jobs));
+		$this->assertEquals('Developer', $jobs[0]['name']);
+		$this->assertEquals('Politician', $jobs[1]['name']);
+		$this->assertEquals('Musician', $jobs[2]['name']);
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * @see ./mocks/schema/skeleton.php
+	 */
+	public function test_where_in()
+	{
+		$jobs = $this->db->where_in('name', array('Politician', 'Accountant'))
+							->get('job')
+							->result_array();
+
+		$this->assertEquals(2, count($jobs));
+		$this->assertEquals('Politician', $jobs[0]['name']);
+		$this->assertEquals('Accountant', $jobs[1]['name']);
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * @see ./mocks/schema/skeleton.php
+	 */
+	public function test_where_not_in()
+	{
+		$jobs = $this->db->where_not_in('name', array('Politician', 'Accountant'))
+							->get('job')
+							->result_array();
+
+		$this->assertEquals(2, count($jobs));
+		$this->assertEquals('Developer', $jobs[0]['name']);
+		$this->assertEquals('Musician', $jobs[1]['name']);
+	}
+
+}
\ No newline at end of file
diff --git a/tests/codeigniter/helpers/array_helper_test.php b/tests/codeigniter/helpers/array_helper_test.php
new file mode 100644
index 0000000..ba46e86
--- /dev/null
+++ b/tests/codeigniter/helpers/array_helper_test.php
@@ -0,0 +1,47 @@
+<?php
+
+class Array_helper_test extends CI_TestCase {
+
+	public function set_up()
+	{
+		$this->helper('array');
+
+		$this->my_array = array(
+			'foo'		=> 'bar',
+			'sally'		=> 'jim',
+			'maggie'	=> 'bessie',
+			'herb'		=> 'cook'
+		);
+	}
+
+	// ------------------------------------------------------------------------
+
+	public function test_element_with_existing_item()
+	{
+		$this->assertEquals(FALSE, element('testing', $this->my_array));
+
+		$this->assertEquals('not set', element('testing', $this->my_array, 'not set'));
+
+		$this->assertEquals('bar', element('foo', $this->my_array));
+	}
+
+	// ------------------------------------------------------------------------
+
+	public function test_random_element()
+	{
+		// Send a string, not an array to random_element
+		$this->assertEquals('my string', random_element('my string'));
+
+		// Test sending an array
+		$this->assertEquals(TRUE, in_array(random_element($this->my_array), $this->my_array));
+	}
+
+	// ------------------------------------------------------------------------
+
+	public function test_elements()
+	{
+		$this->assertEquals(TRUE, is_array(elements('test', $this->my_array)));
+		$this->assertEquals(TRUE, is_array(elements('foo', $this->my_array)));
+	}
+
+}
\ No newline at end of file
diff --git a/tests/codeigniter/helpers/date_helper_test.php b/tests/codeigniter/helpers/date_helper_test.php
new file mode 100644
index 0000000..4b747b8
--- /dev/null
+++ b/tests/codeigniter/helpers/date_helper_test.php
@@ -0,0 +1,286 @@
+<?php
+
+class Date_helper_test extends CI_TestCase {
+
+	public function set_up()
+	{
+		$this->helper('date');
+
+		$this->time = time();
+	}
+
+	// ------------------------------------------------------------------------
+
+	public function test_now_local()
+	{
+		// This stub job, is simply to cater $config['time_reference']
+		$config = $this->getMock('CI_Config');
+		$config->expects($this->any())
+			   ->method('item')
+			   ->will($this->returnValue('local'));
+
+		// Add the stub to our test instance
+		$this->ci_instance_var('config', $config);
+
+		$this->assertEquals(time(), now());
+	}
+
+	// ------------------------------------------------------------------------
+
+	public function test_now_gmt()
+	{
+		// This stub job, is simply to cater $config['time_reference']
+		$config = $this->getMock('CI_Config');
+		$config->expects($this->any())
+			   ->method('item')
+			   ->will($this->returnValue('gmt'));
+
+		// Add the stub to our stdClass
+		$this->ci_instance_var('config', $config);
+
+		$t = time();
+		$this->assertEquals(
+			mktime(gmdate('H', $t), gmdate('i', $t), gmdate('s', $t), gmdate('m', $t), gmdate('d', $t), gmdate('Y', $t)),
+			now()
+		);
+	}
+
+	// ------------------------------------------------------------------------
+
+	public function test_mdate()
+	{
+		$this->assertEquals(
+			date('Y-m-d - h:i a', $this->time),
+			mdate('%Y-%m-%d - %h:%i %a', $this->time)
+		);
+	}
+
+	// ------------------------------------------------------------------------
+
+	public function test_standard_date_rfc822()
+	{
+		$this->assertEquals(
+			date('D, d M y H:i:s O', $this->time),
+			standard_date('DATE_RFC822', $this->time)
+		);
+	}
+
+	// ------------------------------------------------------------------------
+
+	public function test_standard_date_atom()
+	{
+		$this->assertEquals(
+			date("Y-m-d\TH:i:sO", $this->time),
+			standard_date('DATE_ATOM', $this->time)
+		);
+	}
+
+	// ------------------------------------------------------------------------
+
+	public function test_standard_date_cookie()
+	{
+		$this->assertEquals(
+			date("l, d-M-y H:i:s \U\T\C", $this->time),
+			standard_date('DATE_COOKIE', $this->time)
+		);
+	}
+
+	// ------------------------------------------------------------------------
+
+	public function test_standard_date_iso8601()
+	{
+		$this->assertEquals(
+			date("Y-m-d\TH:i:sO", $this->time),
+			standard_date('DATE_ISO8601', $this->time)
+		);
+	}
+
+	// ------------------------------------------------------------------------
+
+	public function test_standard_date_rfc850()
+	{
+		$this->assertEquals(
+			date("l, d-M-y H:i:s \U\T\C", $this->time),
+			standard_date('DATE_RFC850', $this->time)
+		);
+	}
+
+	// ------------------------------------------------------------------------
+
+	public function test_standard_date_rfc1036()
+	{
+		$this->assertEquals(
+			date('D, d M y H:i:s O', $this->time),
+			standard_date('DATE_RFC1036', $this->time)
+		);
+	}
+
+	// ------------------------------------------------------------------------
+
+	public function test_standard_date_rfc1123()
+	{
+		$this->assertEquals(
+			date('D, d M Y H:i:s O', $this->time),
+			standard_date('DATE_RFC1123', $this->time)
+		);
+	}
+
+	// ------------------------------------------------------------------------
+
+	public function test_standard_date_rfc2822()
+	{
+		$this->assertEquals(
+			date('D, d M Y H:i:s O', $this->time),
+			standard_date('DATE_RFC2822', $this->time)
+		);
+	}
+
+	// ------------------------------------------------------------------------
+
+	public function test_standard_date_rss()
+	{
+		$this->assertEquals(
+			date('D, d M Y H:i:s O', $this->time),
+			standard_date('DATE_RSS', $this->time)
+		);
+	}
+
+	// ------------------------------------------------------------------------
+
+	public function test_standard_date_w3c()
+	{
+		$this->assertEquals(
+			date("Y-m-d\TH:i:sO", $this->time),
+			standard_date('DATE_W3C', $this->time)
+		);
+	}
+
+	// ------------------------------------------------------------------------
+
+	public function test_timespan()
+	{
+		$loader_cls = $this->ci_core_class('load');
+		$this->ci_instance_var('load', new $loader_cls);
+
+		$lang_cls = $this->ci_core_class('lang');
+		$this->ci_instance_var('lang', new $lang_cls);
+
+		$this->assertEquals('1 Second', timespan(time(), time()+1));
+		$this->assertEquals('1 Minute', timespan(time(), time()+60));
+		$this->assertEquals('1 Hour', timespan(time(), time()+3600));
+		$this->assertEquals('2 Hours', timespan(time(), time()+7200));
+	}
+
+	// ------------------------------------------------------------------------
+
+	public function test_days_in_month()
+	{
+		$this->assertEquals(30, days_in_month(06, 2005));
+		$this->assertEquals(28, days_in_month(02, 2011));
+		$this->assertEquals(29, days_in_month(02, 2012));
+	}
+
+	// ------------------------------------------------------------------------
+
+	public function test_local_to_gmt()
+	{
+		$this->assertEquals(
+			mktime(
+				gmdate('H', $this->time), gmdate('i', $this->time), gmdate('s', $this->time),
+				gmdate('m', $this->time), gmdate('d', $this->time), gmdate('Y', $this->time)
+			),
+			local_to_gmt($this->time)
+		);
+	}
+
+	// ------------------------------------------------------------------------
+
+	public function test_gmt_to_local()
+	{
+		$this->assertEquals(1140128493, gmt_to_local('1140153693', 'UM8', TRUE));
+	}
+
+	// ------------------------------------------------------------------------
+
+	public function test_mysql_to_unix()
+	{
+		$this->assertEquals($this->time, mysql_to_unix(date('Y-m-d H:i:s', $this->time)));
+	}
+
+	// ------------------------------------------------------------------------
+
+	public function test_unix_to_human()
+	{
+		$this->assertEquals(date('Y-m-d h:i A', $this->time), unix_to_human($this->time));
+		$this->assertEquals(date('Y-m-d h:i:s A', $this->time), unix_to_human($this->time, TRUE, 'us'));
+		$this->assertEquals(date('Y-m-d H:i:s', $this->time), unix_to_human($this->time, TRUE, 'eu'));
+	}
+
+	// ------------------------------------------------------------------------
+
+	public function test_human_to_unix()
+	{
+		$date = '2000-12-31 10:00:00 PM';
+		$this->assertEquals(strtotime($date), human_to_unix($date));
+		$this->assertFalse(human_to_unix());
+	}
+
+	// ------------------------------------------------------------------------
+
+	public function test_timezones()
+	{
+		$zones = array(
+			'UM12'		=> -12,
+			'UM11'		=> -11,
+			'UM10'		=> -10,
+			'UM95'		=> -9.5,
+			'UM9'		=> -9,
+			'UM8'		=> -8,
+			'UM7'		=> -7,
+			'UM6'		=> -6,
+			'UM5'		=> -5,
+			'UM45'		=> -4.5,
+			'UM4'		=> -4,
+			'UM35'		=> -3.5,
+			'UM3'		=> -3,
+			'UM2'		=> -2,
+			'UM1'		=> -1,
+			'UTC'		=> 0,
+			'UP1'		=> +1,
+			'UP2'		=> +2,
+			'UP3'		=> +3,
+			'UP35'		=> +3.5,
+			'UP4'		=> +4,
+			'UP45'		=> +4.5,
+			'UP5'		=> +5,
+			'UP55'		=> +5.5,
+			'UP575'		=> +5.75,
+			'UP6'		=> +6,
+			'UP65'		=> +6.5,
+			'UP7'		=> +7,
+			'UP8'		=> +8,
+			'UP875'		=> +8.75,
+			'UP9'		=> +9,
+			'UP95'		=> +9.5,
+			'UP10'		=> +10,
+			'UP105'		=> +10.5,
+			'UP11'		=> +11,
+			'UP115'		=> +11.5,
+			'UP12'		=> +12,
+			'UP1275'	=> +12.75,
+			'UP13'		=> +13,
+			'UP14'		=> +14
+		);
+
+		foreach ($zones AS $test => $expected)
+		{
+			$this->assertEquals($expected, timezones($test));
+		}
+
+		$this->assertArrayHasKey('UP3', timezones());
+		$this->assertEquals(0, timezones('non_existant'));
+	}
+
+}
+
+/* End of file date_helper_test.php */
\ No newline at end of file
diff --git a/tests/codeigniter/helpers/directory_helper_test.php b/tests/codeigniter/helpers/directory_helper_test.php
new file mode 100644
index 0000000..176ff1d
--- /dev/null
+++ b/tests/codeigniter/helpers/directory_helper_test.php
@@ -0,0 +1,50 @@
+<?php
+
+class Directory_helper_test extends CI_TestCase {
+
+	public function set_up()
+	{
+		$this->helper('directory');
+
+		vfsStreamWrapper::register();
+		vfsStreamWrapper::setRoot(new vfsStreamDirectory('testDir'));
+
+		$this->_test_dir = vfsStreamWrapper::getRoot();
+	}
+
+	public function test_directory_map()
+	{
+		$structure = array(
+			'libraries' => array(
+				'benchmark.html' => '',
+				'database' => array('active_record.html' => '', 'binds.html' => ''),
+				'email.html' => '',
+				'.hiddenfile.txt' => ''
+			)
+		);
+
+		vfsStream::create($structure, $this->_test_dir);
+
+		// test default recursive behavior
+		$expected = array(
+			'libraries' => array(
+				'benchmark.html',
+				'database' => array('active_record.html', 'binds.html'),
+				'email.html'
+			)
+		);
+
+		$this->assertEquals($expected, directory_map(vfsStream::url('testDir')));
+
+		// test detection of hidden files
+		$expected['libraries'][] = '.hiddenfile.txt';
+
+		$this->assertEquals($expected, directory_map(vfsStream::url('testDir'), FALSE, TRUE));
+
+		// test recursion depth behavior
+		$this->assertEquals(array('libraries'), directory_map(vfsStream::url('testDir'), 1));
+	}
+
+}
+
+/* End of file directory_helper_test.php */
\ No newline at end of file
diff --git a/tests/codeigniter/helpers/email_helper_test.php b/tests/codeigniter/helpers/email_helper_test.php
new file mode 100644
index 0000000..fea452f
--- /dev/null
+++ b/tests/codeigniter/helpers/email_helper_test.php
@@ -0,0 +1,18 @@
+<?php
+
+class Email_helper_test extends CI_TestCase {
+
+	public function set_up()
+	{
+		$this->helper('email');
+	}
+
+	public function test_valid_email()
+	{
+		$this->assertEquals(FALSE, valid_email('test'));
+		$this->assertEquals(FALSE, valid_email('test@test@test.com'));
+		$this->assertEquals(TRUE, valid_email('test@test.com'));
+		$this->assertEquals(TRUE, valid_email('my.test@test.com'));
+	}
+
+}
\ No newline at end of file
diff --git a/tests/codeigniter/helpers/file_helper_test.php b/tests/codeigniter/helpers/file_helper_test.php
new file mode 100644
index 0000000..9b03da9
--- /dev/null
+++ b/tests/codeigniter/helpers/file_helper_test.php
@@ -0,0 +1,153 @@
+<?php
+
+class File_helper_Test extends CI_TestCase {
+
+	public function set_up()
+	{
+		$this->helper('file');
+
+		vfsStreamWrapper::register();
+		vfsStreamWrapper::setRoot(new vfsStreamDirectory('testDir'));
+
+		$this->_test_dir = vfsStreamWrapper::getRoot();
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_read_file()
+	{
+		$this->assertFalse(read_file('does_not_exist'));
+
+		$content = 'Jack and Jill went up the mountain to fight a billy goat.';
+
+		$file = vfsStream::newFile('my_file.txt')->withContent($content)->at($this->_test_dir);
+
+		$this->assertEquals($content, read_file(vfsStream::url('my_file.txt')));
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_octal_permissions()
+	{
+		$content = 'Jack and Jill went up the mountain to fight a billy goat.';
+
+		$file = vfsStream::newFile('my_file.txt', 0777)->withContent($content)
+											 ->lastModified(time() - 86400)
+											 ->at($this->_test_dir);
+
+		$this->assertEquals('777', octal_permissions($file->getPermissions()));
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * More tests should happen here, since I'm not hitting the whole function.
+	 */
+	public function test_symbolic_permissions()
+	{
+		$content = 'Jack and Jill went up the mountain to fight a billy goat.';
+
+		$file = vfsStream::newFile('my_file.txt', 0777)->withContent($content)
+											 ->lastModified(time() - 86400)
+											 ->at($this->_test_dir);
+
+		$this->assertEquals('urwxrwxrwx', symbolic_permissions($file->getPermissions()));
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_get_mime_by_extension()
+	{
+		$content = 'Jack and Jill went up the mountain to fight a billy goat.';
+
+		$file = vfsStream::newFile('my_file.txt', 0777)->withContent($content)
+											 ->lastModified(time() - 86400)
+											 ->at($this->_test_dir);
+
+		$this->assertEquals('text/plain', get_mime_by_extension(vfsStream::url('my_file.txt')));
+
+		// Test a mime with an array, such as png
+		$file = vfsStream::newFile('foo.png')->at($this->_test_dir);
+
+		$this->assertEquals('image/png', get_mime_by_extension(vfsStream::url('foo.png')));
+
+		// Test a file not in the mimes array
+		$file = vfsStream::newFile('foo.blarfengar')->at($this->_test_dir);
+
+		$this->assertFalse(get_mime_by_extension(vfsStream::url('foo.blarfengar')));
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_get_file_info()
+	{
+		// Test Bad File
+		$this->assertFalse(get_file_info('i_am_bad_boo'));
+
+		// Test the rest
+
+		// First pass in an array
+		$vals = array(
+			'name', 'server_path', 'size', 'date',
+			'readable', 'writable', 'executable', 'fileperms'
+		);
+
+		$this->_test_get_file_info($vals);
+
+		// Test passing in vals as a string.
+		$this->_test_get_file_info(implode(', ', $vals));
+	}
+
+	private function _test_get_file_info($vals)
+	{
+		$content = 'Jack and Jill went up the mountain to fight a billy goat.';
+		$last_modified = time() - 86400;
+
+		$file = vfsStream::newFile('my_file.txt', 0777)->withContent($content)
+											 ->lastModified($last_modified)
+											 ->at($this->_test_dir);
+
+		$ret_values = array(
+			'name'			=> 'my_file.txt',
+			'server_path'	=> 'vfs://my_file.txt',
+			'size'			=> 57,
+			'date'			=> $last_modified,
+			'readable'		=> TRUE,
+			'writable'		=> TRUE,
+			'executable'	=> TRUE,
+			'fileperms'		=> 33279
+		);
+
+		$info = get_file_info(vfsStream::url('my_file.txt'), $vals);
+
+		foreach ($info as $k => $v)
+		{
+			$this->assertEquals($ret_values[$k], $v);
+		}
+	}
+
+	// --------------------------------------------------------------------
+
+	// Skipping for now, as it's not implemented in vfsStreamWrapper
+	// flock(): vfsStreamWrapper::stream_lock is not implemented!
+
+	// public function test_write_file()
+	// {
+	//	if ( ! defined('FOPEN_WRITE_CREATE_DESTRUCTIVE'))
+	//	{
+	//		define('FOPEN_WRITE_CREATE_DESTRUCTIVE', 'wb');
+	//	}
+	//
+	//	$content = 'Jack and Jill went up the mountain to fight a billy goat.';
+	//
+	//	$file = vfsStream::newFile('write.txt', 0777)->withContent('')
+	//								 	 ->lastModified(time() - 86400)
+	//								 	 ->at($this->_test_dir);
+	//
+	//	$this->assertTrue(write_file(vfsStream::url('write.txt'), $content));
+	//
+	// }
+
+	// --------------------------------------------------------------------
+
+}
\ No newline at end of file
diff --git a/tests/codeigniter/helpers/form_helper_test.php b/tests/codeigniter/helpers/form_helper_test.php
new file mode 100644
index 0000000..1a30ed9
--- /dev/null
+++ b/tests/codeigniter/helpers/form_helper_test.php
@@ -0,0 +1,250 @@
+<?php
+
+require BASEPATH . 'core/Common.php';
+require BASEPATH . 'helpers/form_helper.php';
+
+class Form_helper_test extends CI_TestCase
+{
+	public function test_form_hidden()
+	{
+		$expected = <<<EOH
+
+<input type="hidden" name="username" value="johndoe" />
+
+EOH;
+
+		$this->assertEquals($expected, form_hidden('username', 'johndoe'));
+	}
+
+	public function test_form_input()
+	{
+		$expected = <<<EOH
+<input type="text" name="username" value="johndoe" id="username" maxlength="100" size="50" style="width:50%"  />
+
+EOH;
+
+		$data = array(
+			'name'        => 'username',
+			'id'          => 'username',
+			'value'       => 'johndoe',
+			'maxlength'   => '100',
+			'size'        => '50',
+			'style'       => 'width:50%',
+		);
+
+		$this->assertEquals($expected, form_input($data));
+	}
+
+	public function test_form_password()
+	{
+		$expected = <<<EOH
+<input type="password" name="password" value=""  />
+
+EOH;
+
+		$this->assertEquals($expected, form_password('password'));
+	}
+
+	public function test_form_upload()
+	{
+		$expected = <<<EOH
+<input type="file" name="attachment" value=""  />
+
+EOH;
+
+		$this->assertEquals($expected, form_upload('attachment'));
+	}
+
+	public function test_form_textarea()
+	{
+		$expected = <<<EOH
+<textarea name="notes" cols="40" rows="10" >Notes</textarea>
+
+EOH;
+
+		$this->assertEquals($expected, form_textarea('notes', 'Notes'));
+	}
+
+	public function test_form_dropdown()
+	{
+		$expected = <<<EOH
+<select name="shirts">
+<option value="small">Small Shirt</option>
+<option value="med">Medium Shirt</option>
+<option value="large" selected="selected">Large Shirt</option>
+<option value="xlarge">Extra Large Shirt</option>
+</select>
+
+EOH;
+
+		$options = array(
+			'small'		=> 'Small Shirt',
+			'med'		=> 'Medium Shirt',
+			'large'		=> 'Large Shirt',
+			'xlarge'	=> 'Extra Large Shirt',
+		);
+
+		$this->assertEquals($expected, form_dropdown('shirts', $options, 'large'));
+
+		$expected = <<<EOH
+<select name="shirts" multiple="multiple">
+<option value="small" selected="selected">Small Shirt</option>
+<option value="med">Medium Shirt</option>
+<option value="large" selected="selected">Large Shirt</option>
+<option value="xlarge">Extra Large Shirt</option>
+</select>
+
+EOH;
+
+		$shirts_on_sale = array('small', 'large');
+
+		$this->assertEquals($expected, form_dropdown('shirts', $options, $shirts_on_sale));
+
+		$options = array(
+			'Swedish Cars' => array(
+				'volvo'	=> 'Volvo',
+				'saab'	=> 'Saab'
+			),
+			'German Cars' => array(
+				'mercedes'	=> 'Mercedes',
+				'audi'		=> 'Audi'
+			)
+		);
+
+		$expected = <<<EOH
+<select name="cars" multiple="multiple">
+<optgroup label="Swedish Cars">
+<option value="volvo" selected="selected">Volvo</option>
+<option value="saab">Saab</option>
+</optgroup>
+<optgroup label="German Cars">
+<option value="mercedes">Mercedes</option>
+<option value="audi" selected="selected">Audi</option>
+</optgroup>
+</select>
+
+EOH;
+
+		$this->assertEquals($expected, form_dropdown('cars', $options, array('volvo', 'audi')));
+	}
+
+	public function test_form_multiselect()
+	{
+		$expected = <<<EOH
+<select name="shirts[]"  multiple="multiple">
+<option value="small">Small Shirt</option>
+<option value="med" selected="selected">Medium Shirt</option>
+<option value="large" selected="selected">Large Shirt</option>
+<option value="xlarge">Extra Large Shirt</option>
+</select>
+
+EOH;
+
+		$options = array(
+			'small'		=> 'Small Shirt',
+			'med'		=> 'Medium Shirt',
+			'large'		=> 'Large Shirt',
+			'xlarge'	=> 'Extra Large Shirt',
+		);
+
+		$this->assertEquals($expected, form_multiselect('shirts[]', $options, array('med', 'large')));
+	}
+
+	public function test_form_fieldset()
+	{
+		$expected = <<<EOH
+<fieldset>
+<legend>Address Information</legend>
+
+EOH;
+
+		$this->assertEquals($expected, form_fieldset('Address Information'));
+	}
+
+	public function test_form_fieldset_close()
+	{
+		$expected = <<<EOH
+</fieldset></div></div>
+EOH;
+
+		$this->assertEquals($expected, form_fieldset_close('</div></div>'));
+	}
+
+	public function test_form_checkbox()
+	{
+		$expected = <<<EOH
+<input type="checkbox" name="newsletter" value="accept" checked="checked"  />
+
+EOH;
+
+		$this->assertEquals($expected, form_checkbox('newsletter', 'accept', TRUE));
+	}
+
+	public function test_form_radio()
+	{
+		$expected = <<<EOH
+<input type="radio" name="newsletter" value="accept" checked="checked"  />
+
+EOH;
+
+		$this->assertEquals($expected, form_radio('newsletter', 'accept', TRUE));
+	}
+
+	public function test_form_submit()
+	{
+		$expected = <<<EOH
+<input type="submit" name="mysubmit" value="Submit Post!"  />
+
+EOH;
+
+		$this->assertEquals($expected, form_submit('mysubmit', 'Submit Post!'));
+	}
+
+	public function test_form_label()
+	{
+		$expected = <<<EOH
+<label for="username">What is your Name</label>
+EOH;
+
+		$this->assertEquals($expected, form_label('What is your Name', 'username'));
+	}
+
+	public function test_form_reset()
+	{
+		$expected = <<<EOH
+<input type="reset" name="myreset" value="Reset"  />
+
+EOH;
+
+		$this->assertEquals($expected, form_reset('myreset', 'Reset'));
+	}
+
+	public function test_form_button()
+	{
+		$expected = <<<EOH
+<button name="name" type="button" >content</button>
+
+EOH;
+
+		$this->assertEquals($expected, form_button('name', 'content'));
+	}
+
+	public function test_form_close()
+	{
+		$expected = <<<EOH
+</form></div></div>
+EOH;
+
+		$this->assertEquals($expected, form_close('</div></div>'));
+	}
+
+	public function test_form_prep()
+	{
+		$expected = 'Here is a string containing &quot;quoted&quot; text.';
+
+		$this->assertEquals($expected, form_prep('Here is a string containing "quoted" text.'));
+	}
+
+}
+
+/* End of file form_helper_test.php */
\ No newline at end of file
diff --git a/tests/codeigniter/helpers/html_helper_test.php b/tests/codeigniter/helpers/html_helper_test.php
new file mode 100644
index 0000000..9a7bb48
--- /dev/null
+++ b/tests/codeigniter/helpers/html_helper_test.php
@@ -0,0 +1,76 @@
+<?php
+
+class Html_helper_test extends CI_TestCase {
+
+	public function set_up()
+	{
+		$this->helper('html');
+	}
+
+	// ------------------------------------------------------------------------
+
+	public function test_br()
+	{
+		$this->assertEquals('<br /><br />', br(2));
+	}
+
+	// ------------------------------------------------------------------------
+
+	public function test_heading()
+	{
+		$this->assertEquals('<h1>foobar</h1>', heading('foobar'));
+		$this->assertEquals('<h2 class="bar">foobar</h2>', heading('foobar', 2, 'class="bar"'));
+	}
+
+	// ------------------------------------------------------------------------
+
+	public function test_Ul()
+	{
+		$expect = <<<EOH
+<ul>
+  <li>foo</li>
+  <li>bar</li>
+</ul>
+
+EOH;
+
+		$expect = ltrim($expect);
+		$list = array('foo', 'bar');
+
+		$this->assertEquals(ltrim($expect), ul($list));
+
+		$expect = <<<EOH
+<ul class="test">
+  <li>foo</li>
+  <li>bar</li>
+</ul>
+
+EOH;
+
+		$expect = ltrim($expect);
+
+		$this->assertEquals($expect, ul($list, 'class="test"'));
+
+		$this->assertEquals($expect, ul($list, array('class' => 'test')));
+	}
+
+	// ------------------------------------------------------------------------
+
+	public function test_NBS()
+	{
+		$this->assertEquals('&nbsp;&nbsp;&nbsp;', nbs(3));
+	}
+
+	// ------------------------------------------------------------------------
+
+	public function test_meta()
+	{
+		$this->assertEquals("<meta name=\"test\" content=\"foo\" />\n", meta('test', 'foo'));
+
+		$expect = "<meta name=\"foo\" content=\"\" />\n";
+
+		$this->assertEquals($expect, meta(array('name' => 'foo')));
+
+	}
+
+}
\ No newline at end of file
diff --git a/tests/codeigniter/helpers/inflector_helper_test.php b/tests/codeigniter/helpers/inflector_helper_test.php
new file mode 100644
index 0000000..f3b0ebb
--- /dev/null
+++ b/tests/codeigniter/helpers/inflector_helper_test.php
@@ -0,0 +1,96 @@
+<?php
+
+class Inflector_helper_test extends CI_TestCase {
+
+	public function set_up()
+	{
+		$this->helper('inflector');
+	}
+
+	public function test_singular()
+	{
+		$strs = array(
+			'tellies'		=> 'telly',
+			'smellies'		=> 'smelly',
+			'abjectnesses'	=> 'abjectness',
+			'smells'		=> 'smell',
+			'equipment'		=> 'equipment'
+		);
+
+		foreach ($strs as $str => $expect)
+		{
+			$this->assertEquals($expect, singular($str));
+		}
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_plural()
+	{
+		$strs = array(
+			'telly'			=> 'tellies',
+			'smelly'		=> 'smellies',
+			'abjectness'	=> 'abjectnesses', // ref : http://en.wiktionary.org/wiki/abjectnesses
+			'smell'			=> 'smells',
+			'witch'			=> 'witches',
+			'equipment'		=> 'equipment'
+		);
+
+		foreach ($strs as $str => $expect)
+		{
+			$this->assertEquals($expect, plural($str));
+		}
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_camelize()
+	{
+		$strs = array(
+			'this is the string'	=> 'thisIsTheString',
+			'this is another one'	=> 'thisIsAnotherOne',
+			'i-am-playing-a-trick'	=> 'i-am-playing-a-trick',
+			'what_do_you_think-yo?'	=> 'whatDoYouThink-yo?',
+		);
+
+		foreach ($strs as $str => $expect)
+		{
+			$this->assertEquals($expect, camelize($str));
+		}
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_underscore()
+	{
+		$strs = array(
+			'this is the string'	=> 'this_is_the_string',
+			'this is another one'	=> 'this_is_another_one',
+			'i-am-playing-a-trick'	=> 'i-am-playing-a-trick',
+			'what_do_you_think-yo?'	=> 'what_do_you_think-yo?',
+		);
+
+		foreach ($strs as $str => $expect)
+		{
+			$this->assertEquals($expect, underscore($str));
+		}
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_humanize()
+	{
+		$strs = array(
+			'this_is_the_string'	=> 'This Is The String',
+			'this_is_another_one'	=> 'This Is Another One',
+			'i-am-playing-a-trick'	=> 'I-am-playing-a-trick',
+			'what_do_you_think-yo?'	=> 'What Do You Think-yo?',
+		);
+
+		foreach ($strs as $str => $expect)
+		{
+			$this->assertEquals($expect, humanize($str));
+		}
+	}
+
+}
\ No newline at end of file
diff --git a/tests/codeigniter/helpers/number_helper_test.php b/tests/codeigniter/helpers/number_helper_test.php
new file mode 100644
index 0000000..ef6aae1
--- /dev/null
+++ b/tests/codeigniter/helpers/number_helper_test.php
@@ -0,0 +1,76 @@
+<?php
+
+class Number_helper_test extends CI_TestCase {
+
+	public function set_up()
+	{
+		$this->helper('number');
+
+		// Grab the core lang class
+		$lang_cls = $this->ci_core_class('lang');
+
+		// Mock away load, too much going on in there,
+		// we'll just check for the expected parameter
+
+		$lang = $this->getMock($lang_cls, array('load'));
+		$lang->expects($this->once())
+			 ->method('load')
+			 ->with($this->equalTo('number'));
+
+		// Assign the proper language array
+
+		$lang->language = $this->_get_lang('number');
+
+		// We don't have a controller, so just create
+		// a cheap class to act as our super object.
+		// Make sure it has a lang attribute.
+
+		$obj = new stdClass;
+		$obj->lang = $lang;
+		$this->ci_instance($obj);
+	}
+
+	// Quick helper to actually grab the language
+	// file. Consider moving this to ci_testcase?
+	public function _get_lang($name)
+	{
+		require BASEPATH.'language/english/'.$name.'_lang.php';
+		return $lang;
+	}
+
+	public function test_byte_format()
+	{
+		$this->assertEquals('456 Bytes', byte_format(456));
+	}
+
+	public function test_kb_format()
+	{
+		$this->assertEquals('4.5 KB', byte_format(4567));
+	}
+
+	public function test_kb_format_medium()
+	{
+		$this->assertEquals('44.6 KB', byte_format(45678));
+	}
+
+	public function test_kb_format_large()
+	{
+		$this->assertEquals('446.1 KB', byte_format(456789));
+	}
+
+	public function test_mb_format()
+	{
+		$this->assertEquals('3.3 MB', byte_format(3456789));
+	}
+
+	public function test_gb_format()
+	{
+		$this->assertEquals('1.8 GB', byte_format(1932735283.2));
+	}
+
+	public function test_tb_format()
+	{
+		$this->assertEquals('112,283.3 TB', byte_format(123456789123456789));
+	}
+
+}
\ No newline at end of file
diff --git a/tests/codeigniter/helpers/path_helper_test.php b/tests/codeigniter/helpers/path_helper_test.php
new file mode 100644
index 0000000..0faf6f3
--- /dev/null
+++ b/tests/codeigniter/helpers/path_helper_test.php
@@ -0,0 +1,31 @@
+<?php
+
+class Path_helper_test extends CI_TestCase {
+
+	public function set_up()
+	{
+		$this->helper('path');
+	}
+
+	public function test_set_realpath()
+	{
+		$this->assertEquals(getcwd().DIRECTORY_SEPARATOR, set_realpath(getcwd()));
+	}
+
+	public function test_set_realpath_nonexistent_directory()
+	{
+		$expected = '/path/to/nowhere';
+		$this->assertEquals($expected, set_realpath('/path/to/nowhere', FALSE));
+	}
+
+	public function test_set_realpath_error_trigger()
+	{
+		$this->setExpectedException(
+				'RuntimeException', 'CI Error: Not a valid path: /path/to/nowhere'
+		);
+
+		set_realpath('/path/to/nowhere', TRUE);
+	}
+}
+
+/* End of file path_helper_test.php */
\ No newline at end of file
diff --git a/tests/codeigniter/helpers/string_helper_test.php b/tests/codeigniter/helpers/string_helper_test.php
new file mode 100644
index 0000000..75701ec
--- /dev/null
+++ b/tests/codeigniter/helpers/string_helper_test.php
@@ -0,0 +1,148 @@
+<?php
+
+class String_helper_test extends CI_TestCase {
+
+	public function set_up()
+	{
+		$this->helper('string');
+	}
+
+	public function test_strip_slashes()
+	{
+		$expected = array(
+			"Is your name O'reilly?",
+			"No, my name is O'connor."
+		);
+
+		$str = array(
+			"Is your name O\'reilly?",
+			"No, my name is O\'connor."
+		);
+
+		$this->assertEquals($expected, strip_slashes($str));
+	}
+
+	public function test_trim_slashes()
+	{
+		$strs = array(
+			'//Slashes//\/'	=> 'Slashes//\\',
+			'/var/www/html/'	=> 'var/www/html'
+		);
+
+		foreach ($strs as $str => $expect)
+		{
+			$this->assertEquals($expect, trim_slashes($str));
+		}
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_strip_quotes()
+	{
+		$strs = array(
+			'"me oh my!"'		=> 'me oh my!',
+			"it's a winner!"	=> 'its a winner!',
+		);
+
+		foreach ($strs as $str => $expect)
+		{
+			$this->assertEquals($expect, strip_quotes($str));
+		}
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_quotes_to_entities()
+	{
+		$strs = array(
+			'"me oh my!"'		=> '&quot;me oh my!&quot;',
+			"it's a winner!"	=> 'it&#39;s a winner!',
+		);
+
+		foreach ($strs as $str => $expect)
+		{
+			$this->assertEquals($expect, quotes_to_entities($str));
+		}
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_reduce_double_slashes()
+	{
+		$strs = array(
+			'http://codeigniter.com'		=> 'http://codeigniter.com',
+			'//var/www/html/example.com/'	=> '/var/www/html/example.com/',
+			'/var/www/html//index.php'		=> '/var/www/html/index.php'
+		);
+
+		foreach ($strs as $str => $expect)
+		{
+			$this->assertEquals($expect, reduce_double_slashes($str));
+		}
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_reduce_multiples()
+	{
+		$strs = array(
+			'Fred, Bill,, Joe, Jimmy'	=> 'Fred, Bill, Joe, Jimmy',
+			'Ringo, John, Paul,,'		=> 'Ringo, John, Paul,'
+		);
+
+		foreach ($strs as $str => $expect)
+		{
+			$this->assertEquals($expect, reduce_multiples($str));
+		}
+
+		$strs = array(
+			'Fred, Bill,, Joe, Jimmy'	=> 'Fred, Bill, Joe, Jimmy',
+			'Ringo, John, Paul,,'		=> 'Ringo, John, Paul'
+		);
+
+		foreach ($strs as $str => $expect)
+		{
+			$this->assertEquals($expect, reduce_multiples($str, ',', TRUE));
+		}
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_repeater()
+	{
+		$strs = array(
+			'a'			=> 'aaaaaaaaaa',
+			'&nbsp;'	=> '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;',
+			'<br>'		=> '<br><br><br><br><br><br><br><br><br><br>'
+
+		);
+
+		foreach ($strs as $str => $expect)
+		{
+			$this->assertEquals($expect, repeater($str, 10));
+		}
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_random_string()
+	{
+		$this->assertEquals(16, strlen(random_string('alnum', 16)));
+		$this->assertEquals(32, strlen(random_string('unique', 16)));
+		$this->assertInternalType('string', random_string('numeric', 16));
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_increment_string()
+	{
+		$this->assertEquals('my-test_1', increment_string('my-test'));
+		$this->assertEquals('my-test-1', increment_string('my-test', '-'));
+		$this->assertEquals('file_5', increment_string('file_4'));
+		$this->assertEquals('file-5', increment_string('file-4', '-'));
+		$this->assertEquals('file-5', increment_string('file-4', '-'));
+		$this->assertEquals('file-1', increment_string('file', '-', '1'));
+		$this->assertEquals(124, increment_string('123', ''));
+	}
+
+}
\ No newline at end of file
diff --git a/tests/codeigniter/helpers/text_helper_test.php b/tests/codeigniter/helpers/text_helper_test.php
new file mode 100644
index 0000000..f131469
--- /dev/null
+++ b/tests/codeigniter/helpers/text_helper_test.php
@@ -0,0 +1,171 @@
+<?php
+
+class Text_helper_test extends CI_TestCase {
+
+	private $_long_string;
+
+	public function set_up()
+	{
+		$this->helper('text');
+
+		$this->_long_string = 'Once upon a time, a framework had no tests.  It sad.  So some nice people began to write tests.  The more time that went on, the happier it became.  Everyone was happy.';
+	}
+
+	// ------------------------------------------------------------------------
+
+	public function test_word_limiter()
+	{
+		$this->assertEquals('Once upon a time,&#8230;', word_limiter($this->_long_string, 4));
+		$this->assertEquals('Once upon a time,&hellip;', word_limiter($this->_long_string, 4, '&hellip;'));
+		$this->assertEquals('', word_limiter('', 4));
+	}
+
+	// ------------------------------------------------------------------------
+
+	public function test_character_limiter()
+	{
+		$this->assertEquals('Once upon a time, a&#8230;', character_limiter($this->_long_string, 20));
+		$this->assertEquals('Once upon a time, a&hellip;', character_limiter($this->_long_string, 20, '&hellip;'));
+		$this->assertEquals('Short', character_limiter('Short', 20));
+		$this->assertEquals('Short', character_limiter('Short', 5));
+	}
+
+	// ------------------------------------------------------------------------
+
+	public function test_ascii_to_entities()
+	{
+		$strs = array(
+			'“‘ “test”'			=> '&#8220;&#8216; &#8220;test&#8221;',
+			'†¥¨ˆøåß∂ƒ©˙∆˚¬'	=> '&#8224;&#165;&#168;&#710;&#248;&#229;&#223;&#8706;&#402;&#169;&#729;&#8710;&#730;&#172;'
+		);
+
+		foreach ($strs as $str => $expect)
+		{
+			$this->assertEquals($expect, ascii_to_entities($str));
+		}
+	}
+
+	// ------------------------------------------------------------------------
+
+	public function test_entities_to_ascii()
+	{
+		$strs = array(
+			'&#8220;&#8216; &#8220;test&#8221;' => '“‘ “test”',
+			'&#8224;&#165;&#168;&#710;&#248;&#229;&#223;&#8706;&#402;&#169;&#729;&#8710;&#730;&#172;' => '†¥¨ˆøåß∂ƒ©˙∆˚¬'
+		);
+
+		foreach ($strs as $str => $expect)
+		{
+			$this->assertEquals($expect, entities_to_ascii($str));
+		}
+	}
+
+	// ------------------------------------------------------------------------
+
+	public function test_convert_accented_characters()
+	{
+		$this->assertEquals('AAAeEEEIIOOEUUUeY', convert_accented_characters('ÀÂÄÈÊËÎÏÔŒÙÛÜŸ'));
+		$this->assertEquals('a e i o u n ue', convert_accented_characters('á é í ó ú ñ ü'));
+	}
+
+	// ------------------------------------------------------------------------
+
+	public function test_censored_words()
+	{
+		$censored = array('boob', 'nerd', 'ass', 'fart');
+
+		$strs = array(
+			'Ted bobbled the ball' 			=> 'Ted bobbled the ball',
+			'Jake is a nerdo'				=> 'Jake is a nerdo',
+			'The borg will assimilate you'	=> 'The borg will assimilate you',
+			'Did Mary Fart?'				=> 'Did Mary $*#?',
+			'Jake is really a boob'			=> 'Jake is really a $*#'
+		);
+
+		foreach ($strs as $str => $expect)
+		{
+			$this->assertEquals($expect, word_censor($str, $censored, '$*#'));
+		}
+
+		// test censored words being sent as a string
+		$this->assertEquals('test', word_censor('test', 'test'));
+	}
+
+	// ------------------------------------------------------------------------
+
+	public function test_highlight_code()
+	{
+		$expect = "<code><span style=\"color: #000000\">\n<span style=\"color: #0000BB\">&lt;?php&nbsp;var_dump</span><span style=\"color: #007700\">(</span><span style=\"color: #0000BB\">\$this</span><span style=\"color: #007700\">);&nbsp;</span><span style=\"color: #0000BB\">?&gt;&nbsp;</span>\n</span>\n</code>";
+
+		$this->assertEquals($expect, highlight_code('<?php var_dump($this); ?>'));
+	}
+
+	// ------------------------------------------------------------------------
+
+	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>',
+			''							=> ''
+		);
+
+		foreach ($strs as $str => $expect)
+		{
+			$this->assertEquals($expect, highlight_phrase($str, 'this is'));
+		}
+	}
+
+	// ------------------------------------------------------------------------
+
+	public function test_ellipsize()
+	{
+		$strs = array(
+			'0'		=> array(
+				'this is my string'				=> '&hellip; my string',
+				"here's another one"			=> '&hellip;nother one',
+				'this one is just a bit longer'	=> '&hellip;bit longer',
+				'short'							=> 'short'
+			),
+			'.5'	=> array(
+				'this is my string'				=> 'this &hellip;tring',
+				"here's another one"			=> "here'&hellip;r one",
+				'this one is just a bit longer'	=> 'this &hellip;onger',
+				'short'							=> 'short'
+			),
+			'1'	=> array(
+				'this is my string'				=> 'this is my&hellip;',
+				"here's another one"			=> "here's ano&hellip;",
+				'this one is just a bit longer'	=> 'this one i&hellip;',
+				'short'							=> 'short'
+			),
+		);
+
+		foreach ($strs as $pos => $s)
+		{
+			foreach ($s as $str => $expect)
+			{
+				$this->assertEquals($expect, ellipsize($str, 10, $pos));
+			}
+		}
+	}
+
+	// ------------------------------------------------------------------------
+
+	public function test_word_wrap()
+	{
+		$string = 'Here is a simple string of text that will help us demonstrate this function.';
+		$this->assertEquals(substr_count(word_wrap($string, 25), "\n"), 4);
+	}
+
+	// ------------------------------------------------------------------------
+
+	public function test_default_word_wrap_charlim()
+	{
+		$string = "Here is a longer string of text that will help us demonstrate the default charlim of this function.";
+		$this->assertEquals(strpos(word_wrap($string), "\n"), 73);
+	}
+
+}
\ No newline at end of file
diff --git a/tests/codeigniter/helpers/url_helper_test.php b/tests/codeigniter/helpers/url_helper_test.php
new file mode 100644
index 0000000..c81c5f1
--- /dev/null
+++ b/tests/codeigniter/helpers/url_helper_test.php
@@ -0,0 +1,76 @@
+<?php
+
+class Url_helper_test extends CI_TestCase {
+
+	public function set_up()
+	{
+		$this->helper('url');
+	}
+
+	public function test_url_title()
+	{
+		$words = array(
+			'foo bar /' 	=> 'foo-bar',
+			'\  testing 12' => 'testing-12'
+		);
+
+		foreach ($words as $in => $out)
+		{
+			$this->assertEquals($out, url_title($in, 'dash', TRUE));
+		}
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_url_title_extra_dashes()
+	{
+		$words = array(
+			'_foo bar_' 	=> 'foo_bar',
+			'_What\'s wrong with CSS?_' => 'Whats_wrong_with_CSS'
+		);
+
+		foreach ($words as $in => $out)
+		{
+			$this->assertEquals($out, url_title($in, 'underscore'));
+		}
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_prep_url()
+	{
+		$this->assertEquals('http://codeigniter.com', prep_url('codeigniter.com'));
+		$this->assertEquals('http://www.codeigniter.com', prep_url('www.codeigniter.com'));
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_auto_link_url()
+	{
+		$strings = array(
+			'www.codeigniter.com test' => '<a href="http://www.codeigniter.com">http://www.codeigniter.com</a> test',
+			'This is my noreply@codeigniter.com test' => 'This is my noreply@codeigniter.com test',
+			'<br />www.google.com' => '<br /><a href="http://www.google.com">http://www.google.com</a>',
+		);
+
+		foreach ($strings as $in => $out)
+		{
+			$this->assertEquals($out, auto_link($in, 'url'));
+		}
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_pull_675()
+	{
+		$strings = array(
+			'<br />www.google.com' => '<br /><a href="http://www.google.com">http://www.google.com</a>',
+		);
+
+		foreach ($strings as $in => $out)
+		{
+			$this->assertEquals($out, auto_link($in, 'url'));
+		}
+	}
+
+}
\ No newline at end of file
diff --git a/tests/codeigniter/helpers/xml_helper_test.php b/tests/codeigniter/helpers/xml_helper_test.php
new file mode 100644
index 0000000..e8cf411
--- /dev/null
+++ b/tests/codeigniter/helpers/xml_helper_test.php
@@ -0,0 +1,15 @@
+<?php
+
+class Xml_helper_test extends CI_TestCase {
+
+	public function set_up()
+	{
+		$this->helper('xml');
+	}
+
+	public function test_xml_convert()
+	{
+		$this->assertEquals('&lt;tag&gt;my &amp; test &#45; &lt;/tag&gt;', xml_convert('<tag>my & test - </tag>'));
+	}
+
+}
\ No newline at end of file
diff --git a/tests/codeigniter/libraries/Encrypt_test.php b/tests/codeigniter/libraries/Encrypt_test.php
new file mode 100644
index 0000000..153a25e
--- /dev/null
+++ b/tests/codeigniter/libraries/Encrypt_test.php
@@ -0,0 +1,72 @@
+<?php
+
+class Encrypt_test extends CI_TestCase {
+
+	public function set_up()
+	{
+		$obj = new stdClass;
+		$obj->encrypt = new Mock_Libraries_Encrypt();
+
+		$this->ci_instance($obj);
+		$this->encrypt = $obj->encrypt;
+
+		$this->ci_set_config('encryption_key', "Encryptin'glike@boss!");
+		$this->msg = 'My secret message';
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_encode()
+	{
+		$this->assertNotEquals($this->msg, $this->encrypt->encode($this->msg));
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_decode()
+	{
+		$encoded_msg = $this->encrypt->encode($this->msg);
+		$this->assertEquals($this->msg, $this->encrypt->decode($encoded_msg));
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_optional_key()
+	{
+		$key = 'Ohai!ù0129°03182%HD1892P0';
+		$encoded_msg = $this->encrypt->encode($this->msg, $key);
+		$this->assertEquals($this->msg, $this->encrypt->decode($encoded_msg, $key));
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_default_cipher()
+	{
+		$this->assertEquals('rijndael-256', $this->encrypt->get_cipher());
+	}
+
+	// --------------------------------------------------------------------
+
+
+	public function test_set_cipher()
+	{
+		$this->encrypt->set_cipher(MCRYPT_BLOWFISH);
+		$this->assertEquals('blowfish', $this->encrypt->get_cipher());
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_default_mode()
+	{
+		$this->assertEquals('cbc', $this->encrypt->get_mode());
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_set_mode()
+	{
+		$this->encrypt->set_mode(MCRYPT_MODE_CFB);
+		$this->assertEquals('cfb', $this->encrypt->get_mode());
+	}
+
+}
\ No newline at end of file
diff --git a/tests/codeigniter/libraries/Parser_test.php b/tests/codeigniter/libraries/Parser_test.php
new file mode 100644
index 0000000..b68f44a
--- /dev/null
+++ b/tests/codeigniter/libraries/Parser_test.php
@@ -0,0 +1,107 @@
+<?php
+
+class Parser_test extends CI_TestCase {
+
+	public function set_up()
+	{
+		$obj = new stdClass;
+		$obj->parser = new Mock_Libraries_Parser();
+
+		$this->ci_instance($obj);
+
+		$this->parser = $obj->parser;
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_set_delimiters()
+	{
+		// Make sure default delimiters are there
+		$this->assertEquals('{', $this->parser->l_delim);
+		$this->assertEquals('}', $this->parser->r_delim);
+
+		// Change them to square brackets
+		$this->parser->set_delimiters('[', ']');
+
+		// Make sure they changed
+		$this->assertEquals('[', $this->parser->l_delim);
+		$this->assertEquals(']', $this->parser->r_delim);
+
+		// Reset them
+		$this->parser->set_delimiters();
+
+		// Make sure default delimiters are there
+		$this->assertEquals('{', $this->parser->l_delim);
+		$this->assertEquals('}', $this->parser->r_delim);
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_parse_simple_string()
+	{
+		$data = array(
+			'title' => 'Page Title',
+			'body' => 'Lorem ipsum dolor sit amet.'
+		);
+
+		$template = "{title}\n{body}";
+
+		$result = implode("\n", $data);
+
+		$this->assertEquals($result, $this->parser->parse_string($template, $data, TRUE));
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_parse()
+	{
+		$this->_parse_no_template();
+		$this->_parse_var_pair();
+		$this->_mismatched_var_pair();
+	}
+
+	// --------------------------------------------------------------------
+
+	private function _parse_no_template()
+	{
+		$this->assertFalse($this->parser->parse_string('', '', TRUE));
+	}
+
+	// --------------------------------------------------------------------
+
+	private function _parse_var_pair()
+	{
+		$data = array(
+			'title'		=> 'Super Heroes',
+			'powers'	=> array(
+					array(
+						'invisibility'	=> 'yes',
+						'flying'		=> 'no'),
+			)
+		);
+
+		$template = "{title}\n{powers}{invisibility}\n{flying}{/powers}";
+
+		$this->assertEquals("Super Heroes\nyes\nno", $this->parser->parse_string($template, $data, TRUE));
+	}
+
+	// --------------------------------------------------------------------
+
+	private function _mismatched_var_pair()
+	{
+		$data = array(
+			'title'		=> 'Super Heroes',
+			'powers'	=> array(
+					array(
+						'invisibility'	=> 'yes',
+						'flying'		=> 'no'),
+			)
+		);
+
+		$template = "{title}\n{powers}{invisibility}\n{flying}";
+		$result = "Super Heroes\n{powers}{invisibility}\n{flying}";
+
+		$this->assertEquals($result, $this->parser->parse_string($template, $data, TRUE));
+	}
+
+}
\ No newline at end of file
diff --git a/tests/codeigniter/libraries/Table_test.php b/tests/codeigniter/libraries/Table_test.php
new file mode 100644
index 0000000..edfc83d
--- /dev/null
+++ b/tests/codeigniter/libraries/Table_test.php
@@ -0,0 +1,297 @@
+<?php
+
+class Table_test extends CI_TestCase {
+
+	public function set_up()
+	{
+		$obj = new stdClass;
+		$obj->table = new Mock_Libraries_Table();
+
+		$this->ci_instance($obj);
+
+		$this->table = $obj->table;
+	}
+
+	// Setter Methods
+	// --------------------------------------------------------------------
+
+	public function test_set_template()
+	{
+		$this->assertFalse($this->table->set_template('not an array'));
+
+		$template = array('a' => 'b');
+
+		$this->table->set_template($template);
+		$this->assertEquals($template, $this->table->template);
+	}
+
+	public function test_set_empty()
+	{
+		$this->table->set_empty('nada');
+		$this->assertEquals('nada', $this->table->empty_cells);
+	}
+
+	public function test_set_caption()
+	{
+		$this->table->set_caption('awesome cap');
+		$this->assertEquals('awesome cap', $this->table->caption);
+	}
+
+	/*
+	 * @depends testPrepArgs
+	 */
+	public function test_set_heading()
+	{
+		// uses _prep_args internally, so we'll just do a quick
+		// check to verify that func_get_args and prep_args are
+		// being called.
+
+		$this->table->set_heading('name', 'color', 'size');
+
+		$this->assertEquals(
+			array(
+				array('data' => 'name'),
+				array('data' => 'color'),
+				array('data' => 'size')
+			),
+			$this->table->heading
+		);
+	}
+
+	/*
+	 * @depends testPrepArgs
+	 */
+	public function test_add_row()
+	{
+		// uses _prep_args internally, so we'll just do a quick
+		// check to verify that func_get_args and prep_args are
+		// being called.
+
+		$this->table->add_row('my', 'pony', 'sings');
+		$this->table->add_row('your', 'pony', 'stinks');
+		$this->table->add_row('my pony', '>', 'your pony');
+
+		$this->assertEquals(count($this->table->rows), 3);
+
+		$this->assertEquals(
+			array(
+				array('data' => 'your'),
+				array('data' => 'pony'),
+				array('data' => 'stinks')
+			),
+			$this->table->rows[1]
+		);
+	}
+
+	// Uility Methods
+	// --------------------------------------------------------------------
+
+	public function test_prep_args()
+	{
+		$expected = array(
+			array('data' => 'name'),
+			array('data' => 'color'),
+			array('data' => 'size')
+		);
+
+		$this->assertEquals(
+			$expected,
+			$this->table->prep_args(array('name', 'color', 'size'))
+		);
+
+		// with cell attributes
+		// need to add that new argument row to our expected outcome
+		$expected[] = array('data' => 'weight', 'class' => 'awesome');
+
+		$this->assertEquals(
+			$expected,
+			$this->table->prep_args(array('name', 'color', 'size', array('data' => 'weight', 'class' => 'awesome')))
+		);
+	}
+
+	public function test_default_template_keys()
+	{
+		$keys = array(
+			'table_open',
+			'thead_open', 'thead_close',
+			'heading_row_start', 'heading_row_end', 'heading_cell_start', 'heading_cell_end',
+			'tbody_open', 'tbody_close',
+			'row_start', 'row_end', 'cell_start', 'cell_end',
+			'row_alt_start', 'row_alt_end', 'cell_alt_start', 'cell_alt_end',
+			'table_close'
+		);
+
+		foreach ($keys as $key)
+		{
+			$this->assertArrayHasKey($key, $this->table->default_template());
+		}
+	}
+
+	public function test_compile_template()
+	{
+		$this->assertFalse($this->table->set_template('invalid_junk'));
+
+		// non default key
+		$this->table->set_template(array('nonsense' => 'foo'));
+		$this->table->compile_template();
+
+		$this->assertArrayHasKey('nonsense', $this->table->template);
+		$this->assertEquals('foo', $this->table->template['nonsense']);
+
+		// override default
+		$this->table->set_template(array('table_close' => '</table junk>'));
+		$this->table->compile_template();
+
+		$this->assertArrayHasKey('table_close', $this->table->template);
+		$this->assertEquals('</table junk>', $this->table->template['table_close']);
+	}
+
+	public function test_make_columns()
+	{
+		// Test bogus parameters
+		$this->assertFalse($this->table->make_columns('invalid_junk'));
+		$this->assertFalse($this->table->make_columns(array()));
+		$this->assertFalse($this->table->make_columns(array('one', 'two'), '2.5'));
+
+		// Now on to the actual column creation
+
+		$five_values = array(
+			'Laura', 'Red', '15',
+			'Katie', 'Blue'
+		);
+
+		// No column count - no changes to the array
+		$this->assertEquals(
+			$five_values,
+			$this->table->make_columns($five_values)
+		);
+
+		// Column count of 3 leaves us with one &nbsp;
+		$this->assertEquals(
+			array(
+				array('Laura', 'Red', '15'),
+				array('Katie', 'Blue', '&nbsp;')
+			),
+			$this->table->make_columns($five_values, 3)
+		);
+	}
+
+	public function test_clear()
+	{
+		$this->table->set_heading('Name', 'Color', 'Size');
+
+		// Make columns changes auto_heading
+		$rows = $this->table->make_columns(array(
+			'Laura', 'Red', '15',
+			'Katie', 'Blue'
+		), 3);
+
+		foreach ($rows as $row)
+		{
+			$this->table->add_row($row);
+		}
+
+		$this->assertFalse($this->table->auto_heading);
+		$this->assertEquals(count($this->table->heading), 3);
+		$this->assertEquals(count($this->table->rows), 2);
+
+		$this->table->clear();
+
+		$this->assertTrue($this->table->auto_heading);
+		$this->assertEmpty($this->table->heading);
+		$this->assertEmpty($this->table->rows);
+	}
+
+	public function test_set_from_array()
+	{
+		$this->assertFalse($this->table->set_from_array('bogus'));
+		$this->assertFalse($this->table->set_from_array(NULL));
+
+		$data = array(
+			array('name', 'color', 'number'),
+			array('Laura', 'Red', '22'),
+			array('Katie', 'Blue')
+		);
+
+		$this->table->set_from_array($data, FALSE);
+		$this->assertEmpty($this->table->heading);
+
+		$this->table->clear();
+
+		$this->table->set_from_array($data);
+		$this->assertEquals(count($this->table->rows), 2);
+
+		$expected = array(
+			array('data' => 'name'),
+			array('data' => 'color'),
+			array('data' => 'number')
+		);
+
+		$this->assertEquals($expected, $this->table->heading);
+
+		$expected = array(
+			array('data' => 'Katie'),
+			array('data' => 'Blue'),
+		);
+
+		$this->assertEquals($expected, $this->table->rows[1]);
+	}
+
+	public function test_set_from_object()
+	{
+		// Make a stub of query instance
+		$query = new CI_TestCase();
+		$query->list_fields = function(){
+			return array('name', 'email');
+		};
+		$query->result_array = function(){
+			return array(
+					array('name' => 'John Doe', 'email' => 'john@doe.com'),
+					array('name' => 'Foo Bar', 'email' => 'foo@bar.com'),
+				);
+		};
+		$query->num_rows = function(){
+			return 2;
+		};
+
+		$this->table->set_from_object($query);
+
+		$expected = array(
+			array('data' => 'name'),
+			array('data' => 'email')
+		);
+
+		$this->assertEquals($expected, $this->table->heading);
+
+		$expected = array(
+			'name' => array('data' => 'Foo Bar'),
+			'email' => array('data' => 'foo@bar.com'),
+		);
+
+		$this->assertEquals($expected, $this->table->rows[1]);
+	}
+
+	public function test_generate()
+	{
+		// Prepare the data
+		$data = array(
+			array('Name', 'Color', 'Size'),
+			array('Fred', 'Blue', 'Small'),
+			array('Mary', 'Red', 'Large'),
+			array('John', 'Green', 'Medium')
+		);
+
+		$table = $this->table->generate($data);
+
+		// Test the table header
+		$this->assertTrue(strpos($table, '<th>Name</th>') !== FALSE);
+		$this->assertTrue(strpos($table, '<th>Color</th>') !== FALSE);
+		$this->assertTrue(strpos($table, '<th>Size</th>') !== FALSE);
+
+		// Test the first entry
+		$this->assertTrue(strpos($table, '<td>Fred</td>') !== FALSE);
+		$this->assertTrue(strpos($table, '<td>Blue</td>') !== FALSE);
+		$this->assertTrue(strpos($table, '<td>Small</td>') !== FALSE);
+	}
+
+}
\ No newline at end of file
diff --git a/tests/codeigniter/libraries/Typography_test.php b/tests/codeigniter/libraries/Typography_test.php
new file mode 100644
index 0000000..eb6dacb
--- /dev/null
+++ b/tests/codeigniter/libraries/Typography_test.php
@@ -0,0 +1,186 @@
+<?php
+
+class Typography_test extends CI_TestCase {
+
+	public function set_up()
+	{
+		$obj = new stdClass;
+		$obj->type = new Mock_Libraries_Typography();
+
+		$this->ci_instance($obj);
+
+		$this->type = $obj->type;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Tests the format_characters() function.
+	 *
+	 * this can and should grow.
+	 */
+	public function test_format_characters()
+	{
+		$strs = array(
+			'"double quotes"' 				=> '&#8220;double quotes&#8221;',
+			'"testing" in "theory" that is' => '&#8220;testing&#8221; in &#8220;theory&#8221; that is',
+			"Here's what I'm" 				=> 'Here&#8217;s what I&#8217;m',
+			'&' 							=> '&amp;',
+			'&amp;' 						=> '&amp;',
+			'&nbsp;'						=> '&nbsp;',
+			'--'							=> '&#8212;',
+			'foo...'						=> 'foo&#8230;',
+			'foo..'							=> 'foo..',
+			'foo...bar.'					=> 'foo&#8230;bar.',
+			'test.  new'					=> 'test.&nbsp; new',
+		);
+
+		foreach ($strs as $str => $expected)
+		{
+			$this->assertEquals($expected, $this->type->format_characters($str));
+		}
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_nl2br_except_pre()
+	{
+		$str = <<<EOH
+Hello, I'm a happy string with some new lines.  
+
+I like to skip.
+
+Jump
+
+and sing.
+
+<pre>
+I am inside a pre tag.  Please don't mess with me.
+
+k?
+</pre>
+
+That's my story and I'm sticking to it.
+
+The End.
+EOH;
+
+		$expected = <<<EOH
+Hello, I'm a happy string with some new lines.  <br />
+<br />
+I like to skip.<br />
+<br />
+Jump<br />
+<br />
+and sing.<br />
+<br />
+<pre>
+I am inside a pre tag.  Please don't mess with me.
+
+k?
+</pre><br />
+<br />
+That's my story and I'm sticking to it.<br />
+<br />
+The End.
+EOH;
+
+		$this->assertEquals($expected, $this->type->nl2br_except_pre($str));
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_auto_typography()
+	{
+		$this->_blank_string();
+		$this->_standardize_new_lines();
+		$this->_reduce_linebreaks();
+		$this->_remove_comments();
+		$this->_protect_pre();
+		$this->_no_opening_block();
+		$this->_protect_braced_quotes();
+	}
+
+	// --------------------------------------------------------------------
+
+	private function _blank_string()
+	{
+		// Test blank string
+		$this->assertEquals('', $this->type->auto_typography(''));
+	}
+
+	// --------------------------------------------------------------------
+
+	private function _standardize_new_lines()
+	{
+		$strs = array(
+			"My string\rhas return characters"	=> "<p>My string<br />\nhas return characters</p>",
+			'This one does not!' 				=> '<p>This one does not!</p>'
+		);
+
+		foreach ($strs as $str => $expect)
+		{
+			$this->assertEquals($expect, $this->type->auto_typography($str));
+		}
+	}
+
+	// --------------------------------------------------------------------
+
+	private function _reduce_linebreaks()
+	{
+		$str = "This has way too many linebreaks.\n\n\n\nSee?";
+		$expect = "<p>This has way too many linebreaks.</p>\n\n<p>See?</p>";
+
+		$this->assertEquals($expect, $this->type->auto_typography($str, TRUE));
+	}
+
+	// --------------------------------------------------------------------
+
+	private function _remove_comments()
+	{
+		$str = '<!-- I can haz comments? -->  But no!';
+		$expect = '<p><!-- I can haz comments? -->&nbsp; But no!</p>';
+
+		$this->assertEquals($expect, $this->type->auto_typography($str));
+	}
+
+	// --------------------------------------------------------------------
+
+	private function _protect_pre()
+	{
+		$str = '<p>My Sentence</p><pre>var_dump($this);</pre>';
+		$expect = '<p>My Sentence</p><pre>var_dump($this);</pre>';
+
+		$this->assertEquals($expect, $this->type->auto_typography($str));
+	}
+
+	// --------------------------------------------------------------------
+
+	private function _no_opening_block()
+	{
+		$str = 'My Sentence<pre>var_dump($this);</pre>';
+		$expect = '<p>My Sentence</p><pre>var_dump($this);</pre>';
+
+		$this->assertEquals($expect, $this->type->auto_typography($str));
+	}
+
+	// --------------------------------------------------------------------
+
+	public function _protect_braced_quotes()
+	{
+		$this->type->protect_braced_quotes = TRUE;
+
+		$str = 'Test {parse="foobar"}';
+		$expect = '<p>Test {parse="foobar"}</p>';
+
+		$this->assertEquals($expect, $this->type->auto_typography($str));
+
+		$this->type->protect_braced_quotes = FALSE;
+
+		$str = 'Test {parse="foobar"}';
+		$expect = '<p>Test {parse=&#8220;foobar&#8221;}</p>';
+
+		$this->assertEquals($expect, $this->type->auto_typography($str));
+	}
+
+}
\ No newline at end of file
diff --git a/tests/codeigniter/libraries/Useragent_test.php b/tests/codeigniter/libraries/Useragent_test.php
new file mode 100644
index 0000000..89383f8
--- /dev/null
+++ b/tests/codeigniter/libraries/Useragent_test.php
@@ -0,0 +1,85 @@
+<?php
+
+class UserAgent_test extends CI_TestCase {
+
+	protected $_user_agent = 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; en-us) AppleWebKit/533.20.25 (KHTML, like Gecko) Version/5.0.4 Safari/533.20.27';
+	protected $_mobile_ua = 'Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_1 like Mac OS X; en-us) AppleWebKit/532.9 (KHTML, like Gecko) Version/4.0.5 Mobile/8B117 Safari/6531.22.7';
+
+	public function set_up()
+	{
+		// set a baseline user agent
+		$_SERVER['HTTP_USER_AGENT'] = $this->_user_agent;
+
+		$obj = new stdClass;
+		$obj->agent = new Mock_Libraries_UserAgent();
+
+		$this->ci_instance($obj);
+
+		$this->agent = $obj->agent;
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_accept_lang()
+	{
+		$_SERVER['HTTP_ACCEPT_LANGUAGE'] = 'en';
+		$this->assertTrue($this->agent->accept_lang());
+		unset($_SERVER['HTTP_ACCEPT_LANGUAGE']);
+		$this->assertTrue($this->agent->accept_lang('en'));
+		$this->assertFalse($this->agent->accept_lang('fr'));
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_mobile()
+	{
+		// Mobile Not Set
+		$_SERVER['HTTP_USER_AGENT'] = $this->_mobile_ua;
+		$this->assertEquals('', $this->agent->mobile());
+		unset($_SERVER['HTTP_USER_AGENT']);
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_util_is_functions()
+	{
+		$this->assertTrue($this->agent->is_browser());
+		$this->assertFalse($this->agent->is_robot());
+		$this->assertFalse($this->agent->is_mobile());
+		$this->assertFalse($this->agent->is_referral());
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_agent_string()
+	{
+		$this->assertEquals($this->_user_agent, $this->agent->agent_string());
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_browser_info()
+	{
+		$this->assertEquals('Mac OS X', $this->agent->platform());
+		$this->assertEquals('Safari', $this->agent->browser());
+		$this->assertEquals('533.20.27', $this->agent->version());
+		$this->assertEquals('', $this->agent->robot());
+		$this->assertEquals('', $this->agent->referrer());
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_charsets()
+	{
+		$_SERVER['HTTP_ACCEPT_CHARSET'] = 'utf8';
+
+		$charsets = $this->agent->charsets();
+
+		$this->assertEquals('utf8', $charsets[0]);
+
+		unset($_SERVER['HTTP_ACCEPT_CHARSET']);
+
+		$this->assertFalse($this->agent->accept_charset());
+	}
+
+}
\ No newline at end of file
diff --git a/tests/mocks/autoloader.php b/tests/mocks/autoloader.php
new file mode 100644
index 0000000..e3ff7a8
--- /dev/null
+++ b/tests/mocks/autoloader.php
@@ -0,0 +1,89 @@
+<?php
+
+// This autoloader provide convinient way to working with mock object
+// make the test looks natural. This autoloader support cascade file loading as well
+// within mocks directory.
+//
+// Prototype :
+//
+// $mock_table = new Mock_Libraries_Table(); 			// Will load ./mocks/libraries/table.php
+// $mock_database_driver = new Mock_Database_Driver();	// Will load ./mocks/database/driver.php
+// and so on...
+function autoload($class)
+{
+	$dir = realpath(dirname(__FILE__)).DIRECTORY_SEPARATOR;
+
+	$ci_core = array(
+		'Benchmark', 'Config', 'Controller',
+		'Exceptions', 'Hooks', 'Input',
+		'Lang', 'Loader', 'Model',
+		'Output', 'Router', 'Security',
+		'URI', 'Utf8',
+	);
+
+	$ci_libraries = array(
+		'Calendar', 'Cart', 'Driver_Library',
+		'Email', 'Encrypt', 'Form_validation',
+		'Ftp', 'Image_lib', 'Javascript',
+		'Log', 'Migration', 'Pagination',
+		'Parser', 'Profiler', 'Session',
+		'Table', 'Trackback', 'Typography',
+		'Unit_test', 'Upload', 'User_agent',
+		'Xmlrpc', 'Zip',
+	);
+
+	if (strpos($class, 'Mock_') === 0)
+	{
+		$class = str_replace(array('Mock_', '_'), array('', DIRECTORY_SEPARATOR), $class);
+		$class = strtolower($class);
+	}
+	elseif (strpos($class, 'CI_') === 0)
+	{
+		$fragments = explode('_', $class, 2);
+		$subclass = next($fragments);
+
+		if (in_array($subclass, $ci_core))
+		{
+			$dir = BASEPATH.'core'.DIRECTORY_SEPARATOR;
+			$class = $subclass;
+		}
+		elseif (in_array($subclass, $ci_libraries))
+		{
+			$dir = BASEPATH.'libraries'.DIRECTORY_SEPARATOR;
+			$class = ($subclass === 'Driver_Library') ? 'Driver' : $subclass;
+		}
+		elseif (preg_match('/^CI_DB_(.+)_(driver|forge|result|utility)$/', $class, $m) && count($m) === 3)
+		{
+			$driver_path = BASEPATH.'database'.DIRECTORY_SEPARATOR.'drivers'.DIRECTORY_SEPARATOR;
+			$dir = $driver_path.$m[1].DIRECTORY_SEPARATOR;
+			$file = $dir.$m[1].'_'.$m[2].'.php';
+		}
+		elseif (strpos($class, 'CI_DB') === 0)
+		{
+			$dir = BASEPATH.'database'.DIRECTORY_SEPARATOR;
+			$file = $dir.str_replace(array('CI_DB','active_record'), array('DB', 'active_rec'), $subclass).'.php';
+		}
+		else
+		{
+			$class = strtolower($class);
+		}
+	}
+
+	$file = isset($file) ? $file : $dir.$class.'.php';
+
+	if ( ! file_exists($file))
+	{
+		$trace = debug_backtrace();
+
+		// If the autoload call came from `class_exists` or `file_exists`,
+		// we skipped and return FALSE
+		if ($trace[2]['function'] === 'class_exists' OR $trace[2]['function'] === 'file_exists')
+		{
+			return FALSE;
+		}
+
+		throw new InvalidArgumentException("Unable to load {$class}.");
+	}
+
+	include_once($file);
+}
\ No newline at end of file
diff --git a/tests/mocks/ci_testcase.php b/tests/mocks/ci_testcase.php
new file mode 100644
index 0000000..eda9e1b
--- /dev/null
+++ b/tests/mocks/ci_testcase.php
@@ -0,0 +1,194 @@
+<?php
+
+class CI_TestCase extends PHPUnit_Framework_TestCase {
+
+	protected $ci_config;
+	protected $ci_instance;
+	protected static $ci_test_instance;
+
+	private $global_map = array(
+		'benchmark'	=> 'bm',
+		'config'	=> 'cfg',
+		'hooks'		=> 'ext',
+		'utf8'		=> 'uni',
+		'router'	=> 'rtr',
+		'output'	=> 'out',
+		'security'	=> 'sec',
+		'input'		=> 'in',
+		'lang'		=> 'lang',
+		'loader'	=> 'load',
+		'model'		=> 'model'
+	);
+
+	// --------------------------------------------------------------------
+
+	public function __construct()
+	{
+		parent::__construct();
+		$this->ci_config = array();
+	}
+
+	// --------------------------------------------------------------------
+
+	public function setUp()
+	{
+		if (method_exists($this, 'set_up'))
+		{
+			$this->set_up();
+		}
+	}
+
+	// --------------------------------------------------------------------
+
+	public function tearDown()
+	{
+		if (method_exists($this, 'tear_down'))
+		{
+			$this->tear_down();
+		}
+	}
+
+	// --------------------------------------------------------------------
+
+	public static function instance()
+	{
+		return self::$ci_test_instance;
+	}
+
+	// --------------------------------------------------------------------
+
+	public function ci_set_config($key, $val = '')
+	{
+		if (is_array($key))
+		{
+			$this->ci_config = $key;
+		}
+		else
+		{
+			$this->ci_config[$key] = $val;
+		}
+	}
+
+	// --------------------------------------------------------------------
+
+	public function ci_get_config()
+	{
+		return $this->ci_config;
+	}
+
+	// --------------------------------------------------------------------
+
+	public function ci_instance($obj = FALSE)
+	{
+		if ( ! is_object($obj))
+		{
+			return $this->ci_instance;
+		}
+
+		$this->ci_instance = $obj;
+	}
+
+	// --------------------------------------------------------------------
+
+	public function ci_instance_var($name, $obj = FALSE)
+	{
+		if ( ! is_object($obj))
+		{
+			return $this->ci_instance->$name;
+		}
+
+		$this->ci_instance->$name =& $obj;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Grab a core class
+	 *
+	 * Loads the correct core class without extensions
+	 * and returns a reference to the class name in the
+	 * globals array with the correct key. This way the
+	 * test can modify the variable it assigns to and
+	 * still maintain the global.
+	 */
+	public function &ci_core_class($name)
+	{
+		$name = strtolower($name);
+
+		if (isset($this->global_map[$name]))
+		{
+			$class_name = ucfirst($name);
+			$global_name = $this->global_map[$name];
+		}
+		elseif (in_array($name, $this->global_map))
+		{
+			$class_name = ucfirst(array_search($name, $this->global_map));
+			$global_name = $name;
+		}
+		else
+		{
+			throw new Exception('Not a valid core class.');
+		}
+
+		if ( ! class_exists('CI_'.$class_name))
+		{
+			require_once BASEPATH.'core/'.$class_name.'.php';
+		}
+
+		$GLOBALS[strtoupper($global_name)] = 'CI_'.$class_name;
+		return $GLOBALS[strtoupper($global_name)];
+	}
+
+	// --------------------------------------------------------------------
+
+	// convenience function for global mocks
+	public function ci_set_core_class($name, $obj)
+	{
+		$orig =& $this->ci_core_class($name);
+		$orig = $obj;
+	}
+
+	// --------------------------------------------------------------------
+	// Internals
+	// --------------------------------------------------------------------
+
+	/**
+	 * Overwrite runBare
+	 *
+	 * PHPUnit instantiates the test classes before
+	 * running them individually. So right before a test
+	 * runs we set our instance. Normally this step would
+	 * happen in setUp, but someone is bound to forget to
+	 * call the parent method and debugging this is no fun.
+	 */
+	public function runBare()
+	{
+		self::$ci_test_instance = $this;
+		parent::runBare();
+	}
+
+	// --------------------------------------------------------------------
+
+	public function helper($name)
+	{
+		require_once(BASEPATH.'helpers/'.$name.'_helper.php');
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * This overload is useful to create a stub, that need to have a specific method.
+	 */
+	public function __call($method, $args)
+	{
+		if ($this->{$method} instanceof Closure)
+		{
+			return call_user_func_array($this->{$method},$args);
+		}
+		else
+		{
+			return parent::__call($method, $args);
+		}
+	}
+
+}
\ No newline at end of file
diff --git a/tests/mocks/core/benchmark.php b/tests/mocks/core/benchmark.php
new file mode 100644
index 0000000..d92be21
--- /dev/null
+++ b/tests/mocks/core/benchmark.php
@@ -0,0 +1,3 @@
+<?php
+
+class Mock_Core_Benchmark extends CI_Benchmark {}
\ No newline at end of file
diff --git a/tests/mocks/core/common.php b/tests/mocks/core/common.php
new file mode 100644
index 0000000..a655ee1
--- /dev/null
+++ b/tests/mocks/core/common.php
@@ -0,0 +1,169 @@
+<?php
+
+// Set up the global CI functions in their most minimal core representation
+
+if ( ! function_exists('get_instance'))
+{
+	function &get_instance()
+	{
+		$test = CI_TestCase::instance();
+		$test = $test->ci_instance();
+		return $test;
+	}
+}
+
+// --------------------------------------------------------------------
+
+if ( ! function_exists('get_config'))
+{
+	function &get_config()
+	{
+		$test = CI_TestCase::instance();
+		$config = $test->ci_get_config();
+		return $config;
+	}
+}
+
+if ( ! function_exists('config_item'))
+{
+	function config_item($item)
+	{
+		$config =& get_config();
+
+		if ( ! isset($config[$item]))
+		{
+			return FALSE;
+		}
+
+		return $config[$item];
+	}
+}
+
+// --------------------------------------------------------------------
+
+if ( ! function_exists('load_class'))
+{
+	function load_class($class, $directory = 'libraries', $prefix = 'CI_')
+	{
+		if ($directory !== 'core' OR $prefix !== 'CI_')
+		{
+			throw new Exception('Not Implemented: Non-core load_class()');
+		}
+
+		$test = CI_TestCase::instance();
+
+		$obj =& $test->ci_core_class($class);
+
+		if (is_string($obj))
+		{
+			throw new Exception('Bad Isolation: Use ci_set_core_class to set '.$class);
+		}
+
+		return $obj;
+	}
+}
+
+// This is sort of meh. Should probably be mocked up with
+// controllable output, so that we can test some of our
+// security code. The function itself will be tested in the
+// bootstrap testsuite.
+// --------------------------------------------------------------------
+
+if ( ! function_exists('remove_invisible_characters'))
+{
+	function remove_invisible_characters($str, $url_encoded = TRUE)
+	{
+		$non_displayables = array();
+
+		// every control character except newline (dec 10)
+		// carriage return (dec 13), and horizontal tab (dec 09)
+
+		if ($url_encoded)
+		{
+			$non_displayables[] = '/%0[0-8bcef]/';	// url encoded 00-08, 11, 12, 14, 15
+			$non_displayables[] = '/%1[0-9a-f]/';	// url encoded 16-31
+		}
+
+		$non_displayables[] = '/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]+/S';	// 00-08, 11, 12, 14-31, 127
+
+		do
+		{
+			$str = preg_replace($non_displayables, '', $str, -1, $count);
+		}
+		while ($count);
+
+		return $str;
+	}
+}
+
+
+// Clean up error messages
+// --------------------------------------------------------------------
+
+if ( ! function_exists('show_error'))
+{
+	function show_error($message, $status_code = 500, $heading = 'An Error Was Encountered')
+	{
+		throw new RuntimeException('CI Error: '.$message);
+	}
+}
+
+if ( ! function_exists('show_404'))
+{
+	function show_404($page = '', $log_error = TRUE)
+	{
+		throw new RuntimeException('CI Error: 404');
+	}
+}
+
+if ( ! function_exists('_exception_handler'))
+{
+	function _exception_handler($severity, $message, $filepath, $line)
+	{
+		throw new RuntimeException('CI Exception: '.$message.' | '.$filepath.' | '.$line);
+	}
+}
+
+
+// We assume a few things about our environment ...
+// --------------------------------------------------------------------
+
+if ( ! function_exists('is_php'))
+{
+	function is_php($version = '5.0.0')
+	{
+		return ! (version_compare(PHP_VERSION, $version) < 0);
+	}
+}
+
+if ( ! function_exists('is_really_writable'))
+{
+	function is_really_writable($file)
+	{
+		return is_writable($file);
+	}
+}
+
+if ( ! function_exists('is_loaded'))
+{
+	function is_loaded()
+	{
+		throw new Exception('Bad Isolation: mock up environment');
+	}
+}
+
+if ( ! function_exists('log_message'))
+{
+	function log_message($level = 'error', $message, $php_error = FALSE)
+	{
+		return TRUE;
+	}
+}
+
+if ( ! function_exists('set_status_header'))
+{
+	function set_status_header($code = 200, $text = '')
+	{
+		return TRUE;
+	}
+}
\ No newline at end of file
diff --git a/tests/mocks/core/input.php b/tests/mocks/core/input.php
new file mode 100644
index 0000000..2a4aa49
--- /dev/null
+++ b/tests/mocks/core/input.php
@@ -0,0 +1,31 @@
+<?php
+
+class Mock_Core_Input extends CI_Input {
+
+	/**
+	 * Since we use GLOBAL to fetch Security and Utf8 classes,
+	 * we need to use inversion of control to mock up
+	 * the same process within CI_Input class constructor.
+	 *
+	 * @covers CI_Input::__construct()
+	 */
+	public function __construct($security, $utf8)
+	{
+		$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);
+
+		// Assign Security and Utf8 classes
+		$this->security = $security;
+		$this->uni = $utf8;
+
+		// Sanitize global arrays
+		$this->_sanitize_globals();
+	}
+
+	public function fetch_from_array($array, $index = '', $xss_clean = FALSE)
+	{
+		return parent::_fetch_from_array($array, $index, $xss_clean);
+	}
+
+}
\ No newline at end of file
diff --git a/tests/mocks/core/loader.php b/tests/mocks/core/loader.php
new file mode 100644
index 0000000..53d88d5
--- /dev/null
+++ b/tests/mocks/core/loader.php
@@ -0,0 +1,31 @@
+<?php
+
+class Mock_Core_Loader extends CI_Loader {
+
+	/**
+	 * Since we use paths to load up models, views, etc, we need the ability to
+	 * mock up the file system so when core tests are run, we aren't mucking
+	 * in the application directory.  this will give finer grained control over
+	 * these tests.  So yeah, while this looks odd, I need to overwrite protected
+	 * class vars in the loader.  So here we go...
+	 *
+	 * @covers CI_Loader::__construct()
+	 */
+	public function __construct()
+	{
+		vfsStreamWrapper::register();
+		vfsStreamWrapper::setRoot(new vfsStreamDirectory('application'));
+
+		$this->models_dir 	= vfsStream::newDirectory('models')->at(vfsStreamWrapper::getRoot());
+		$this->libs_dir 	= vfsStream::newDirectory('libraries')->at(vfsStreamWrapper::getRoot());
+		$this->helpers_dir 	= vfsStream::newDirectory('helpers')->at(vfsStreamWrapper::getRoot());
+		$this->views_dir 	= vfsStream::newDirectory('views')->at(vfsStreamWrapper::getRoot());
+
+		$this->_ci_ob_level  		= ob_get_level();
+		$this->_ci_library_paths	= array(vfsStream::url('application').'/', BASEPATH);
+		$this->_ci_helper_paths 	= array(vfsStream::url('application').'/', BASEPATH);
+		$this->_ci_model_paths 		= array(vfsStream::url('application').'/');
+		$this->_ci_view_paths 		= array(vfsStream::url('application').'/views/' => TRUE);
+	}
+
+}
\ No newline at end of file
diff --git a/tests/mocks/core/security.php b/tests/mocks/core/security.php
new file mode 100644
index 0000000..e19a8b2
--- /dev/null
+++ b/tests/mocks/core/security.php
@@ -0,0 +1,30 @@
+<?php
+
+class Mock_Core_Security extends CI_Security {
+
+	public function csrf_set_cookie()
+	{
+		// We cannot set cookie in CLI mode, so for csrf test, who rely on $_COOKIE,
+		// we superseded set_cookie with directly set the cookie variable,
+		// @see : ./tests/codeigniter/core/Security_test.php, line 8
+		return $this;
+	}
+
+	// Overide inaccesible protected properties
+	public function __get($property)
+	{
+		return isset($this->{'_'.$property}) ? $this->{'_'.$property} : NULL;
+	}
+
+	// Overide inaccesible protected method
+	public function __call($method, $params)
+	{
+		if (is_callable(array($this, '_'.$method)))
+		{
+			return call_user_func_array(array($this, '_'.$method), $params);
+		}
+
+		throw new BadMethodCallException('Method '.$method.' was not found');
+	}
+
+}
\ No newline at end of file
diff --git a/tests/mocks/core/uri.php b/tests/mocks/core/uri.php
new file mode 100644
index 0000000..94f75df
--- /dev/null
+++ b/tests/mocks/core/uri.php
@@ -0,0 +1,26 @@
+<?php
+
+class Mock_Core_URI extends CI_URI {
+
+	public function __construct()
+	{
+		$test = CI_TestCase::instance();
+		$cls =& $test->ci_core_class('cfg');
+
+		// set predictable config values
+		$test->ci_set_config(array(
+			'index_page'		=> 'index.php',
+			'base_url'			=> 'http://example.com/',
+			'subclass_prefix'	=> 'MY_'
+		));
+
+		$this->config = new $cls;
+
+	}
+
+	protected function _is_cli_request()
+	{
+		return FALSE;
+	}
+
+}
\ No newline at end of file
diff --git a/tests/mocks/core/utf8.php b/tests/mocks/core/utf8.php
new file mode 100644
index 0000000..068e74a
--- /dev/null
+++ b/tests/mocks/core/utf8.php
@@ -0,0 +1,26 @@
+<?php
+
+class Mock_Core_Utf8 extends CI_Utf8 {
+
+	/**
+	 * We need to define several constants as
+	 * the same process within CI_Utf8 class constructor.
+	 *
+	 * @covers CI_Utf8::__construct()
+	 */
+	public function __construct()
+	{
+		defined('UTF8_ENABLED') OR define('UTF8_ENABLED', TRUE);
+
+		if (extension_loaded('mbstring'))
+		{
+			defined('MB_ENABLED') OR define('MB_ENABLED', TRUE);
+			mb_internal_encoding('UTF-8');
+		}
+		else
+		{
+			defined('MB_ENABLED') OR define('MB_ENABLED', FALSE);
+		}
+	}
+
+}
\ No newline at end of file
diff --git a/tests/mocks/database/ci_test.sqlite b/tests/mocks/database/ci_test.sqlite
new file mode 100755
index 0000000..44dcef9
--- /dev/null
+++ b/tests/mocks/database/ci_test.sqlite
Binary files differ
diff --git a/tests/mocks/database/config/mysql.php b/tests/mocks/database/config/mysql.php
new file mode 100644
index 0000000..a590b9f
--- /dev/null
+++ b/tests/mocks/database/config/mysql.php
@@ -0,0 +1,34 @@
+<?php
+
+return array(
+
+	// Typical Database configuration
+	'mysql' => array(
+		'dsn' => '',
+		'hostname' => 'localhost',
+		'username' => 'travis',
+		'password' => '',
+		'database' => 'ci_test',
+		'dbdriver' => 'mysql'
+	),
+
+	// Database configuration with failover
+	'mysql_failover' => array(
+		'dsn' => '',
+		'hostname' => 'localhost',
+		'username' => 'not_travis',
+		'password' => 'wrong password',
+		'database' => 'not_ci_test',
+		'dbdriver' => 'mysql',
+		'failover' => array(
+			array(
+				'dsn' => '',
+				'hostname' => 'localhost',
+				'username' => 'travis',
+				'password' => '',
+				'database' => 'ci_test',
+				'dbdriver' => 'mysql',
+			)
+		)
+	)
+);
\ No newline at end of file
diff --git a/tests/mocks/database/config/pdo/mysql.php b/tests/mocks/database/config/pdo/mysql.php
new file mode 100644
index 0000000..fefe0d6
--- /dev/null
+++ b/tests/mocks/database/config/pdo/mysql.php
@@ -0,0 +1,37 @@
+<?php
+
+return array(
+
+	// Typical Database configuration
+	'pdo/mysql' => array(
+		'dsn' => '',
+		'hostname' => 'localhost',
+		'username' => 'travis',
+		'password' => '',
+		'database' => 'ci_test',
+		'dbdriver' => 'pdo',
+		'pdodriver' => 'mysql'
+	),
+
+	// Database configuration with failover
+	'pdo/mysql_failover' => array(
+		'dsn' => '',
+		'hostname' => 'localhost',
+		'username' => 'not_travis',
+		'password' => 'wrong password',
+		'database' => 'not_ci_test',
+		'dbdriver' => 'pdo',
+		'pdodriver' => 'mysql',
+		'failover' => array(
+			array(
+				'dsn' => '',
+				'hostname' => 'localhost',
+				'username' => 'travis',
+				'password' => '',
+				'database' => 'ci_test',
+				'dbdriver' => 'pdo',
+				'pdodriver' => 'mysql'
+			)
+		)
+	)
+);
\ No newline at end of file
diff --git a/tests/mocks/database/config/pdo/pgsql.php b/tests/mocks/database/config/pdo/pgsql.php
new file mode 100644
index 0000000..ddd638c
--- /dev/null
+++ b/tests/mocks/database/config/pdo/pgsql.php
@@ -0,0 +1,37 @@
+<?php
+
+return array(
+
+	// Typical Database configuration
+	'pdo/pgsql' => array(
+		'dsn' => 'pgsql:host=localhost;port=5432;dbname=ci_test;',
+		'hostname' => 'localhost',
+		'username' => 'postgres',
+		'password' => '',
+		'database' => 'ci_test',
+		'dbdriver' => 'pdo',
+		'pdodriver' => 'pgsql'
+	),
+
+	// Database configuration with failover
+	'pdo/pgsql_failover' => array(
+		'dsn' => '',
+		'hostname' => 'localhost',
+		'username' => 'not_travis',
+		'password' => 'wrong password',
+		'database' => 'not_ci_test',
+		'dbdriver' => 'pdo',
+		'pdodriver' => 'pgsql',
+		'failover' => array(
+			array(
+				'dsn' => 'pgsql:host=localhost;port=5432;dbname=ci_test;',
+				'hostname' => 'localhost',
+				'username' => 'postgres',
+				'password' => '',
+				'database' => 'ci_test',
+				'dbdriver' => 'pdo',
+				'pdodriver' => 'pgsql'
+			)
+		)
+	)
+);
\ No newline at end of file
diff --git a/tests/mocks/database/config/pdo/sqlite.php b/tests/mocks/database/config/pdo/sqlite.php
new file mode 100644
index 0000000..3646184
--- /dev/null
+++ b/tests/mocks/database/config/pdo/sqlite.php
@@ -0,0 +1,37 @@
+<?php
+
+return array(
+
+	// Typical Database configuration
+	'pdo/sqlite' => array(
+		'dsn' => 'sqlite:/'.realpath(__DIR__.'/../..').'/ci_test.sqlite',
+		'hostname' => 'localhost',
+		'username' => 'sqlite',
+		'password' => 'sqlite',
+		'database' => 'sqlite',
+		'dbdriver' => 'pdo',
+		'pdodriver' => 'sqlite'
+	),
+
+	// Database configuration with failover
+	'pdo/sqlite_failover' => array(
+		'dsn' => 'sqlite:not_exists.sqlite',
+		'hostname' => 'localhost',
+		'username' => 'sqlite',
+		'password' => 'sqlite',
+		'database' => 'sqlite',
+		'dbdriver' => 'pdo',
+		'pdodriver' => 'sqlite',
+		'failover' => array(
+			array(
+				'dsn' => 'sqlite:/'.realpath(__DIR__.'/../..').'/ci_test.sqlite',
+				'hostname' => 'localhost',
+				'username' => 'sqlite',
+				'password' => 'sqlite',
+				'database' => 'sqlite',
+				'dbdriver' => 'pdo',
+				'pdodriver' => 'sqlite'
+			)
+		)
+	)
+);
\ No newline at end of file
diff --git a/tests/mocks/database/config/pgsql.php b/tests/mocks/database/config/pgsql.php
new file mode 100644
index 0000000..1444b00
--- /dev/null
+++ b/tests/mocks/database/config/pgsql.php
@@ -0,0 +1,34 @@
+<?php
+
+return array(
+
+	// Typical Database configuration
+	'pgsql' => array(
+		'dsn' => '',
+		'hostname' => 'localhost',
+		'username' => 'postgres',
+		'password' => '',
+		'database' => 'ci_test',
+		'dbdriver' => 'postgre'
+	),
+
+	// Database configuration with failover
+	'pgsql_failover' => array(
+		'dsn' => '',
+		'hostname' => 'localhost',
+		'username' => 'not_travis',
+		'password' => 'wrong password',
+		'database' => 'not_ci_test',
+		'dbdriver' => 'postgre',
+		'failover' => array(
+			array(
+				'dsn' => '',
+				'hostname' => 'localhost',
+				'username' => 'postgres',
+				'password' => '',
+				'database' => 'ci_test',
+				'dbdriver' => 'postgre',
+			)
+		)
+	)
+);
\ No newline at end of file
diff --git a/tests/mocks/database/config/sqlite.php b/tests/mocks/database/config/sqlite.php
new file mode 100644
index 0000000..d37ee48
--- /dev/null
+++ b/tests/mocks/database/config/sqlite.php
@@ -0,0 +1,34 @@
+<?php
+
+return array(
+
+	// Typical Database configuration
+	'sqlite' => array(
+		'dsn' => '',
+		'hostname' => 'localhost',
+		'username' => 'sqlite',
+		'password' => 'sqlite',
+		'database' => realpath(__DIR__.'/..').'/ci_test.sqlite',
+		'dbdriver' => 'sqlite3'
+	),
+
+	// Database configuration with failover
+	'sqlite_failover' => array(
+		'dsn' => '',
+		'hostname' => 'localhost',
+		'username' => 'sqlite',
+		'password' => 'sqlite',
+		'database' => '../not_exists.sqlite',
+		'dbdriver' => 'sqlite3',
+		'failover' => array(
+			array(
+				'dsn' => '',
+				'hostname' => 'localhost',
+				'username' => 'sqlite',
+				'password' => 'sqlite',
+				'database' => realpath(__DIR__.'/..').'/ci_test.sqlite',
+				'dbdriver' => 'sqlite3'
+			)
+		)
+	)
+);
\ No newline at end of file
diff --git a/tests/mocks/database/db.php b/tests/mocks/database/db.php
new file mode 100644
index 0000000..30504bb
--- /dev/null
+++ b/tests/mocks/database/db.php
@@ -0,0 +1,100 @@
+<?php
+
+class Mock_Database_DB {
+
+	/**
+	 * @var array DB configuration
+	 */
+	private $config = array();
+
+	/**
+	 * Prepare database configuration skeleton
+	 *
+	 * @param  array 	DB configuration to set
+	 * @return void
+	 */
+	public function __construct($config = array())
+	{
+		$this->config = $config;
+	}
+
+	/**
+	 * Build DSN connection string for DB driver instantiate process
+	 *
+	 * @param 	string 	Group name
+	 * @return 	string 	DSN Connection string
+	 */
+	public function set_dsn($group = 'default')
+	{
+		if ( ! isset($this->config[$group]))
+		{
+			throw new InvalidArgumentException('Group '.$group.' not exists');
+		}
+
+		$params = array(
+			'dbprefix' => '',
+			'pconnect' => FALSE,
+			'db_debug' => FALSE,
+			'cache_on' => FALSE,
+			'cachedir' => '',
+			'char_set' => 'utf8',
+			'dbcollat' => 'utf8_general_ci',
+			'swap_pre' => '',
+			'autoinit' => TRUE,
+			'stricton' => FALSE,
+		);
+
+		$config = array_merge($this->config[$group], $params);
+		$dsnstring = ( ! empty($config['dsn'])) ? $config['dsn'] : FALSE;
+		$pdodriver = ( ! empty($config['pdodriver'])) ? $config['pdodriver'] : FALSE;
+		$failover = ( ! empty($config['failover'])) ? $config['failover'] : FALSE;
+
+		$dsn = $config['dbdriver'].'://'.$config['username'].':'.$config['password']
+			       .'@'.$config['hostname'].'/'.$config['database'];
+
+		// Build the parameter
+		$other_params = array_slice($config, 6);
+		if ($dsnstring) $other_params['dsn'] = $dsnstring;
+		if ($pdodriver) $other_params['pdodriver'] = $pdodriver;
+		if ($failover) $other_params['failover'] = $failover;
+
+		return $dsn.'?'.http_build_query($other_params);
+	}
+
+	/**
+	 * Return a database config array
+	 *
+	 * @see 	./config
+	 * @param	string	Driver based configuration
+	 * @return	array
+	 */
+	public static function config($driver)
+	{
+		$dir = realpath(dirname(__FILE__)).DIRECTORY_SEPARATOR;
+		return include($dir.'config'.DIRECTORY_SEPARATOR.$driver.'.php');
+	}
+
+	/**
+	 * Main DB method wrapper
+	 *
+	 * @param 	string	Group or DSN string
+	 * @param 	bool
+	 * @return 	object
+	 */
+	public static function DB($group, $query_builder = FALSE)
+	{
+		include_once(BASEPATH.'database/DB.php');
+
+		try
+		{
+			$db = DB($group, $query_builder);
+		}
+		catch (Exception $e)
+		{
+			throw new InvalidArgumentException($e->getMessage());
+		}
+
+		return $db;
+	}
+
+}
\ No newline at end of file
diff --git a/tests/mocks/database/db/driver.php b/tests/mocks/database/db/driver.php
new file mode 100644
index 0000000..65ac2c4
--- /dev/null
+++ b/tests/mocks/database/db/driver.php
@@ -0,0 +1,39 @@
+<?php
+
+class Mock_Database_DB_Driver extends CI_DB_driver {
+
+	/**
+	 * @var object The actual Driver
+	 */
+	protected $ci_db_driver;
+
+	/**
+	 * Instantiate the database driver
+	 *
+	 * @param  string 	DB Driver class name
+	 * @param  array 	DB configuration to set
+	 * @return void
+	 */
+	public function __construct($driver_class, $config = array())
+	{
+		if (is_string($driver_class))
+		{
+			$this->ci_db_driver = new $driver_class($config);
+		}
+	}
+
+	/**
+	 * Overloading method, emulate the actual driver method (multiple inheritance workaround)
+	 */
+	public function __call($method, $arguments)
+	{
+		if ( ! is_callable(array($this->ci_db_driver, $method)))
+		{
+			throw new BadMethodCallException($method. ' not exists or not implemented');
+		}
+
+		return call_user_func_array(array($this->ci_db_driver, $method), $arguments);
+	}
+}
+
+class CI_DB extends Mock_Database_DB_QueryBuilder {}
\ No newline at end of file
diff --git a/tests/mocks/database/db/querybuilder.php b/tests/mocks/database/db/querybuilder.php
new file mode 100644
index 0000000..3f22526
--- /dev/null
+++ b/tests/mocks/database/db/querybuilder.php
@@ -0,0 +1,3 @@
+<?php
+
+class Mock_Database_DB_QueryBuilder extends CI_DB_query_builder {}
\ No newline at end of file
diff --git a/tests/mocks/database/drivers/mysql.php b/tests/mocks/database/drivers/mysql.php
new file mode 100644
index 0000000..e0c1fb0
--- /dev/null
+++ b/tests/mocks/database/drivers/mysql.php
@@ -0,0 +1,17 @@
+<?php
+
+class Mock_Database_Drivers_Mysql extends Mock_Database_DB_Driver {
+
+	/**
+	 * Instantiate the database driver
+	 *
+	 * @param	string	DB Driver class name
+	 * @param	array	DB configuration to set
+	 * @return	void
+	 */
+	public function __construct($config = array())
+	{
+		parent::__construct('CI_DB_mysql_driver', $config);
+	}
+
+}
\ No newline at end of file
diff --git a/tests/mocks/database/drivers/pdo.php b/tests/mocks/database/drivers/pdo.php
new file mode 100644
index 0000000..17768ee
--- /dev/null
+++ b/tests/mocks/database/drivers/pdo.php
@@ -0,0 +1,16 @@
+<?php
+
+class Mock_Database_Drivers_PDO extends Mock_Database_DB_Driver {
+
+	/**
+	 * Instantiate the database driver
+	 *
+	 * @param	string	DB Driver class name
+	 * @param	array	DB configuration to set
+	 * @return	void
+	 */
+	public function __construct($config = array())
+	{
+		parent::__construct('CI_DB_pdo_driver', $config);
+	}
+}
\ No newline at end of file
diff --git a/tests/mocks/database/drivers/postgre.php b/tests/mocks/database/drivers/postgre.php
new file mode 100644
index 0000000..5a45115
--- /dev/null
+++ b/tests/mocks/database/drivers/postgre.php
@@ -0,0 +1,17 @@
+<?php
+
+class Mock_Database_Drivers_Postgre extends Mock_Database_DB_Driver {
+
+	/**
+	 * Instantiate the database driver
+	 *
+	 * @param	string	DB Driver class name
+	 * @param	array	DB configuration to set
+	 * @return	void
+	 */
+	public function __construct($config = array())
+	{
+		parent::__construct('CI_DB_postgre_driver', $config);
+	}
+
+}
\ No newline at end of file
diff --git a/tests/mocks/database/drivers/sqlite.php b/tests/mocks/database/drivers/sqlite.php
new file mode 100644
index 0000000..5124675
--- /dev/null
+++ b/tests/mocks/database/drivers/sqlite.php
@@ -0,0 +1,17 @@
+<?php
+
+class Mock_Database_Drivers_Sqlite extends Mock_Database_DB_Driver {
+
+	/**
+	 * Instantiate the database driver
+	 *
+	 * @param	string	DB Driver class name
+	 * @param	array	DB configuration to set
+	 * @return	void
+	 */
+	public function __construct($config = array())
+	{
+		parent::__construct('CI_DB_sqlite3_driver', $config);
+	}
+
+}
\ No newline at end of file
diff --git a/tests/mocks/database/schema/skeleton.php b/tests/mocks/database/schema/skeleton.php
new file mode 100644
index 0000000..18e1ddd
--- /dev/null
+++ b/tests/mocks/database/schema/skeleton.php
@@ -0,0 +1,147 @@
+<?php
+
+class Mock_Database_Schema_Skeleton {
+
+	/**
+	 * @var object Database Holder
+	 */
+	public static $db;
+
+	/**
+	 * @var object Forge Holder
+	 */
+	public static $forge;
+
+	/**
+	 * @var object Driver Holder
+	 */
+	public static $driver;
+
+	/**
+	 * Initialize both database and forge components
+	 */
+	public static function init($driver)
+	{
+		if (empty(static::$db) && empty(static::$forge))
+		{
+			$config = Mock_Database_DB::config($driver);
+			$connection = new Mock_Database_DB($config);
+			$db = Mock_Database_DB::DB($connection->set_dsn($driver), TRUE);
+
+			CI_TestCase::instance()->ci_instance_var('db', $db);
+
+			$loader = new Mock_Core_Loader();
+			$loader->dbforge();
+			$forge = CI_TestCase::instance()->ci_instance_var('dbforge');
+
+			static::$db = $db;
+			static::$forge = $forge;
+			static::$driver = $driver;
+		}
+
+		return static::$db;
+	}
+
+	/**
+	 * Create the dummy tables
+	 *
+	 * @return void
+	 */
+	public static function create_tables()
+	{
+		// User Table
+		static::$forge->add_field(array(
+			'id' => array(
+				'type' => 'INTEGER',
+				'constraint' => 3
+			),
+			'name' => array(
+				'type' => 'VARCHAR',
+				'constraint' => 40
+			),
+			'email' => array(
+				'type' => 'VARCHAR',
+				'constraint' => 100
+			),
+			'country' => array(
+				'type' => 'VARCHAR',
+				'constraint' => 40
+			)
+		));
+		static::$forge->add_key('id', TRUE);
+		static::$forge->create_table('user', (strpos(static::$driver, 'pgsql') === FALSE));
+
+		// Job Table
+		static::$forge->add_field(array(
+			'id' => array(
+				'type' => 'INTEGER',
+				'constraint' => 3
+			),
+			'name' => array(
+				'type' => 'VARCHAR',
+				'constraint' => 40
+			),
+			'description' => array(
+				'type' => 'TEXT'
+			)
+		));
+		static::$forge->add_key('id', TRUE);
+		static::$forge->create_table('job', (strpos(static::$driver, 'pgsql') === FALSE));
+
+		// Misc Table
+		static::$forge->add_field(array(
+			'id' => array(
+				'type' => 'INTEGER',
+				'constraint' => 3
+			),
+			'key' => array(
+				'type' => 'VARCHAR',
+				'constraint' => 40
+			),
+			'value' => array(
+				'type' => 'TEXT'
+			)
+		));
+		static::$forge->add_key('id', TRUE);
+		static::$forge->create_table('misc', (strpos(static::$driver, 'pgsql') === FALSE));
+	}
+
+	/**
+	 * Create the dummy datas
+	 *
+	 * @return void
+	 */
+	public static function create_data()
+	{
+		// Job Data
+		$data = array(
+			'user' => array(
+				array('id' => 1, 'name' => 'Derek Jones', 'email' => 'derek@world.com', 'country' => 'US'),
+				array('id' => 2, 'name' => 'Ahmadinejad', 'email' => 'ahmadinejad@world.com', 'country' => 'Iran'),
+				array('id' => 3, 'name' => 'Richard A Causey', 'email' => 'richard@world.com', 'country' => 'US'),
+				array('id' => 4, 'name' => 'Chris Martin', 'email' => 'chris@world.com', 'country' => 'UK')
+			),
+			'job' => array(
+				array('id' => 1, 'name' => 'Developer', 'description' => 'Awesome job, but sometimes makes you bored'),
+				array('id' => 2, 'name' => 'Politician', 'description' => 'This is not really a job'),
+    				array('id' => 3, 'name' => 'Accountant', 'description' => 'Boring job, but you will get free snack at lunch'),
+				array('id' => 4, 'name' => 'Musician', 'description' => 'Only Coldplay can actually called Musician')
+			),
+			'misc' => array(
+				array('id' => 1, 'key' => '\\xxxfoo456', 'value' => 'Entry with \\xxx'),
+				array('id' => 2, 'key' => '\\%foo456', 'value' => 'Entry with \\%')
+			)
+		);
+
+		foreach ($data as $table => $dummy_data)
+		{
+			static::$db->truncate($table);
+
+			foreach ($dummy_data as $single_dummy_data)
+			{
+				static::$db->insert($table, $single_dummy_data);
+			}
+		}
+	}
+
+}
\ No newline at end of file
diff --git a/tests/mocks/libraries/encrypt.php b/tests/mocks/libraries/encrypt.php
new file mode 100644
index 0000000..f185939
--- /dev/null
+++ b/tests/mocks/libraries/encrypt.php
@@ -0,0 +1,16 @@
+<?php
+
+class Mock_Libraries_Encrypt extends CI_Encrypt {
+
+	// Overide inaccesible protected method
+	public function __call($method, $params)
+	{
+		if (is_callable(array($this, '_'.$method)))
+		{
+			return call_user_func_array(array($this, '_'.$method), $params);
+		}
+
+		throw new BadMethodCallException('Method '.$method.' was not found');
+	}
+
+}
\ No newline at end of file
diff --git a/tests/mocks/libraries/parser.php b/tests/mocks/libraries/parser.php
new file mode 100644
index 0000000..81dcfb3
--- /dev/null
+++ b/tests/mocks/libraries/parser.php
@@ -0,0 +1,3 @@
+<?php
+
+class Mock_Libraries_Parser extends CI_Parser {}
\ No newline at end of file
diff --git a/tests/mocks/libraries/table.php b/tests/mocks/libraries/table.php
new file mode 100644
index 0000000..87c278b
--- /dev/null
+++ b/tests/mocks/libraries/table.php
@@ -0,0 +1,16 @@
+<?php
+
+class Mock_Libraries_Table extends CI_Table {
+
+	// Overide inaccesible protected method
+	public function __call($method, $params)
+	{
+		if (is_callable(array($this, '_'.$method)))
+		{
+			return call_user_func_array(array($this, '_'.$method), $params);
+		}
+
+		throw new BadMethodCallException('Method '.$method.' was not found');
+	}
+
+}
\ No newline at end of file
diff --git a/tests/mocks/libraries/typography.php b/tests/mocks/libraries/typography.php
new file mode 100644
index 0000000..0f76c57
--- /dev/null
+++ b/tests/mocks/libraries/typography.php
@@ -0,0 +1,3 @@
+<?php
+
+class Mock_Libraries_Typography extends CI_Typography {}
\ No newline at end of file
diff --git a/tests/mocks/libraries/useragent.php b/tests/mocks/libraries/useragent.php
new file mode 100644
index 0000000..c957cde
--- /dev/null
+++ b/tests/mocks/libraries/useragent.php
@@ -0,0 +1,3 @@
+<?php
+
+class Mock_Libraries_UserAgent extends CI_User_agent {}
\ No newline at end of file
diff --git a/tests/phpunit.xml b/tests/phpunit.xml
new file mode 100644
index 0000000..56cb884
--- /dev/null
+++ b/tests/phpunit.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<phpunit 
+	bootstrap="./Bootstrap.php"
+	colors="true"
+	convertNoticesToExceptions="true"
+	convertWarningsToExceptions="true"
+	stopOnError="false"
+	stopOnFailure="false"
+	stopOnIncomplete="false"
+	stopOnSkipped="false">
+	<testsuites>
+		<testsuite name="CodeIgniter Core Test Suite">
+			<directory suffix="test.php">./codeigniter/core</directory>
+			<directory suffix="test.php">./codeigniter/helpers</directory>
+			<directory suffix="test.php">./codeigniter/libraries</directory>
+		</testsuite>
+	</testsuites>
+	<filters>
+		<blacklist>
+			<directory suffix=".php">PEAR_INSTALL_DIR</directory>
+			<directory suffix=".php">PHP_LIBDIR</directory>
+		</blacklist>
+	</filters>
+</phpunit>
\ No newline at end of file
diff --git a/tests/travis/mysql.phpunit.xml b/tests/travis/mysql.phpunit.xml
new file mode 100644
index 0000000..38c8eba
--- /dev/null
+++ b/tests/travis/mysql.phpunit.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<phpunit 
+	bootstrap="../Bootstrap.php"
+	colors="true"
+	convertNoticesToExceptions="true"
+	convertWarningsToExceptions="true"
+	stopOnError="false"
+	stopOnFailure="false"
+	stopOnIncomplete="false"
+	stopOnSkipped="false">
+	<php>
+        <const name="DB_DRIVER" value="mysql"/>
+    </php>
+	<testsuites>
+		<testsuite name="CodeIgniter Core Test Suite">
+			<directory suffix="test.php">../codeigniter</directory>
+		</testsuite>
+	</testsuites>
+	<filter>
+        <whitelist addUncoveredFilesFromWhitelist="true">
+            <directory suffix=".php">../../system</directory>
+        </whitelist>
+	</filter>
+</phpunit>
\ No newline at end of file
diff --git a/tests/travis/pdo/mysql.phpunit.xml b/tests/travis/pdo/mysql.phpunit.xml
new file mode 100644
index 0000000..c3113a6
--- /dev/null
+++ b/tests/travis/pdo/mysql.phpunit.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<phpunit 
+	bootstrap="../../Bootstrap.php"
+	colors="true"
+	convertNoticesToExceptions="true"
+	convertWarningsToExceptions="true"
+	stopOnError="false"
+	stopOnFailure="false"
+	stopOnIncomplete="false"
+	stopOnSkipped="false">
+	<php>
+        <const name="DB_DRIVER" value="pdo/mysql"/>
+    </php>
+	<testsuites>
+		<testsuite name="CodeIgniter Core Test Suite">
+			<directory suffix="test.php">../../codeigniter</directory>
+		</testsuite>
+	</testsuites>
+	<filter>
+        <whitelist addUncoveredFilesFromWhitelist="true">
+            <directory suffix=".php">../../../system</directory>
+        </whitelist>
+	</filter>
+</phpunit>
\ No newline at end of file
diff --git a/tests/travis/pdo/pgsql.phpunit.xml b/tests/travis/pdo/pgsql.phpunit.xml
new file mode 100644
index 0000000..2320255
--- /dev/null
+++ b/tests/travis/pdo/pgsql.phpunit.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<phpunit 
+	bootstrap="../../Bootstrap.php"
+	colors="true"
+	convertNoticesToExceptions="true"
+	convertWarningsToExceptions="true"
+	stopOnError="false"
+	stopOnFailure="false"
+	stopOnIncomplete="false"
+	stopOnSkipped="false">
+	<php>
+        <const name="DB_DRIVER" value="pdo/pgsql"/>
+    </php>
+	<testsuites>
+		<testsuite name="CodeIgniter Core Test Suite">
+			<directory suffix="test.php">../../codeigniter</directory>
+		</testsuite>
+	</testsuites>
+	<filter>
+        <whitelist addUncoveredFilesFromWhitelist="true">
+            <directory suffix=".php">../../../system</directory>
+        </whitelist>
+	</filter>
+</phpunit>
\ No newline at end of file
diff --git a/tests/travis/pdo/sqlite.phpunit.xml b/tests/travis/pdo/sqlite.phpunit.xml
new file mode 100644
index 0000000..3d12567
--- /dev/null
+++ b/tests/travis/pdo/sqlite.phpunit.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<phpunit 
+	bootstrap="../../Bootstrap.php"
+	colors="true"
+	convertNoticesToExceptions="true"
+	convertWarningsToExceptions="true"
+	stopOnError="false"
+	stopOnFailure="false"
+	stopOnIncomplete="false"
+	stopOnSkipped="false">
+	<php>
+        <const name="DB_DRIVER" value="pdo/sqlite"/>
+    </php>
+	<testsuites>
+		<testsuite name="CodeIgniter Core Test Suite">
+			<directory suffix="test.php">../../codeigniter</directory>
+		</testsuite>
+	</testsuites>
+	<filter>
+        <whitelist addUncoveredFilesFromWhitelist="true">
+            <directory suffix=".php">../../../system</directory>
+        </whitelist>
+	</filter>
+</phpunit>
\ No newline at end of file
diff --git a/tests/travis/pgsql.phpunit.xml b/tests/travis/pgsql.phpunit.xml
new file mode 100644
index 0000000..51e433d
--- /dev/null
+++ b/tests/travis/pgsql.phpunit.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<phpunit 
+	bootstrap="../Bootstrap.php"
+	colors="true"
+	convertNoticesToExceptions="true"
+	convertWarningsToExceptions="true"
+	stopOnError="false"
+	stopOnFailure="false"
+	stopOnIncomplete="false"
+	stopOnSkipped="false">
+	<php>
+        <const name="DB_DRIVER" value="pgsql"/>
+    </php>
+	<testsuites>
+		<testsuite name="CodeIgniter Core Test Suite">
+			<directory suffix="test.php">../codeigniter</directory>
+		</testsuite>
+	</testsuites>
+	<filter>
+        <whitelist addUncoveredFilesFromWhitelist="true">
+            <directory suffix=".php">../../system</directory>
+        </whitelist>
+	</filter>
+</phpunit>
\ No newline at end of file
diff --git a/tests/travis/sqlite.phpunit.xml b/tests/travis/sqlite.phpunit.xml
new file mode 100644
index 0000000..7011657
--- /dev/null
+++ b/tests/travis/sqlite.phpunit.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<phpunit 
+	bootstrap="../Bootstrap.php"
+	colors="true"
+	convertNoticesToExceptions="true"
+	convertWarningsToExceptions="true"
+	stopOnError="false"
+	stopOnFailure="false"
+	stopOnIncomplete="false"
+	stopOnSkipped="false">
+	<php>
+        <const name="DB_DRIVER" value="sqlite"/>
+    </php>
+	<testsuites>
+		<testsuite name="CodeIgniter Core Test Suite">
+			<directory suffix="test.php">../codeigniter</directory>
+		</testsuite>
+	</testsuites>
+	<filter>
+        <whitelist addUncoveredFilesFromWhitelist="true">
+            <directory suffix=".php">../../system</directory>
+        </whitelist>
+	</filter>
+</phpunit>
\ No newline at end of file
diff --git a/user_guide_src/cilexer/cilexer/cilexer.py b/user_guide_src/cilexer/cilexer/cilexer.py
index 713268e..1c41f2a 100644
--- a/user_guide_src/cilexer/cilexer/cilexer.py
+++ b/user_guide_src/cilexer/cilexer/cilexer.py
@@ -1,7 +1,7 @@
 # CodeIgniter
 # http://codeigniter.com
 # 
-# An open source application development framework for PHP 5.1.6 or newer
+# An open source application development framework for PHP 5.2.4 or newer
 # 
 # NOTICE OF LICENSE
 # 
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 b9e28ae..66768ba 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
@@ -2,7 +2,7 @@
 CodeIgniter
 http://codeigniter.com
 
-An open source application development framework for PHP 5.1.6 or newer
+An open source application development framework for PHP 5.2.4 or newer
 
 NOTICE OF LICENSE
 
diff --git a/user_guide_src/source/changelog.rst b/user_guide_src/source/changelog.rst
index c9354de..f91a1dc 100644
--- a/user_guide_src/source/changelog.rst
+++ b/user_guide_src/source/changelog.rst
@@ -9,8 +9,7 @@
 
 -  License
 
-   -  CodeIgniter has been relicensed with the Open Software License (3.0),
-      eliminating its old proprietary licensing.
+   -  CodeIgniter has been relicensed with the Open Software License (3.0), eliminating its old proprietary licensing.
 
       -  All system files are licensed with OSL 3.0.
       -  Config, error, and sample files shipped in the application folder are
@@ -19,55 +18,143 @@
 
 -  General Changes
 
+   -  PHP 5.1.6 is no longer supported. CodeIgniter now requires PHP 5.2.4.
+   -  ``$_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 to the list of user platforms.
+   -  Added Windows 7, Android, Blackberry and iOS to the list of user platforms.
+   -  Added Fennec (Firefox for mobile) to the list of mobile user agents.
    -  Ability to log certain error types, not all under a threshold.
    -  Added support for pem, p10, p12, p7a, p7c, p7m, p7r, p7s, crt, crl, der, kdb, rsa, cer, sst, csr Certs to mimes.php.
    -  Added support for pgp and gpg to mimes.php.
    -  Added support for 3gp, 3g2, mp4, wmv, f4v, vlc Video files to mimes.php.
    -  Added support for m4a, aac, m4u, xspf, au, ac3, flac, ogg Audio files to mimes.php.
    -  Added support for kmz and kml (Google Earth) files to mimes.php.
-   -  Added application/xml for xml and application/xml, text/xsl for xsl in mimes.php.
+   -  Added support for ics Calendar files to mimes.php
+   -  Updated support for xml ('application/xml') and xsl ('application/xml', 'text/xsl') files in mimes.php.
+   -  Updated support for doc files in mimes.php.
+   -  Added some more doctypes.
+   -  Added Romanian and Greek characters in foreign_characters.php.
    -  Changed logger to only chmod when file is first created.
    -  Removed previously deprecated SHA1 Library.
    -  Removed previously deprecated use of ``$autoload['core']`` in application/config/autoload.php.
       Only entries in ``$autoload['libraries']`` are auto-loaded now.
+   -  Removed previously deprecated EXT constant.
+   -  Updated all classes to be written in PHP 5 style, with visibility declarations and no ``var`` usage for properties.
+   -  Moved error templates to "application/views/errors"
+   -  Global config files are loaded first, then environment ones. Environment config keys overwrite base ones, allowing to only set the keys we want changed per environment.
+   -  Changed detection of ``$view_folder`` so that if it's not found in the current path, it will now also be searched for under the application folder.
+   -  Path constants BASEPATH, APPPATH and VIEWPATH are now (internally) defined as absolute paths.
 
 -  Helpers
 
-   -  url_title() will now trim extra dashes from beginning and end.
+   -  ``create_captcha()`` accepts additional colors parameter, allowing for color customization.
+   -  ``url_title()`` will now trim extra dashes from beginning and end.
    -  Added XHTML Basic 1.1 doctype to :doc:`HTML Helper <helpers/html_helper>`.
-   -  Changed humanize to include a second param for the separator.
+   -  Changed ``humanize()`` to include a second param for the separator.
+   -  Refactored ``plural()`` and ``singular()`` to avoid double pluralization and support more words.
+   -  Added an optional third parameter to ``force_download()`` that enables/disables sending the actual file MIME type in the Content-Type header (disabled by default).
+   -  Added an optional third parameter to ``timespan()`` that constrains the number of time units displayed.
+   -  Added a work-around in ``force_download()`` for a bug Android <= 2.1, where the filename extension needs to be in uppercase.
+   -  ``form_dropdown()`` will now also take an array for unity with other form helpers.
+   -  ``do_hash()`` now uses PHP's native ``hash()`` function (supporting more algorithms) and is deprecated.
+   -  Removed previously deprecated helper function ``js_insert_smiley()`` from smiley helper.
+   -  :doc:`File Helper <helpers/file_helper>` changes include:
+	 - ``set_realpath()`` can now also handle file paths as opposed to just directories.
+	 - Added an optional paramater to ``delete_files()`` to enable it to skip deleting files such as .htaccess and index.html.
+	 - ``read_file()`` is now a deprecated alias of ``file_get_contents()``.
 
 -  Database
 
-   -  Added new :doc:`Active Record <database/active_record>` methods that return
-      the SQL string of queries without executing them: get_compiled_select(),
-      get_compiled_insert(), get_compiled_update(), get_compiled_delete().
-   -  Taking care of LIKE condition when used with MySQL UPDATE statement.
-   -  Adding $escape parameter to the order_by function, this enables ordering by custom fields.
-   -  MySQLi driver now uses mysqli_get_server_info() for server version checking.
-   -  MySQLi driver now supports persistent connections when running on PHP >= 5.3.
+   -  :doc:`Query Builder <database/query_builder>` changes include:
+	 - Renamed the Active Record class to Query Builder to remove confusion with the Active Record design pattern.
+	 - Added the ability to insert objects with insert_batch().
+	 - Added new methods that return the SQL string of queries without executing them: get_compiled_select(), get_compiled_insert(), get_compiled_update(), get_compiled_delete().
+	 - Added an optional order_by() parameter that allows to disable escaping (useful for custom fields).
+	 - Added an optional join() parameter that allows to disable escaping.
+	 - Added support for join() with multiple conditions.
+   -  Improved support for the MySQLi driver, including:
+	 - OOP style of the PHP extension is now used, instead of the procedural aliases.
+	 - Server version checking is now done via ``mysqli::$server_info`` instead of running an SQL query.
+	 - Added persistent connections support for PHP >= 5.3.
+	 - Added support for backup() in :doc:`Database Utilities <database/utilities>`.
+   -  Added 'dsn' configuration setting for drivers that support DSN strings (PDO, PostgreSQL, Oracle, ODBC, CUBRID).
+   -  Improved PDO database support.
+   -  Added Interbase/Firebird database support via the "interbase" driver.
+   -  Added an optional database name parameter to db_select().
+   -  Replaced the _error_message() and _error_number() methods with error(), that returns an array containing the last database error code and message.
+   -  Improved version() implementation so that drivers that have a native function to get the version number don't have to be defined in the core DB_driver class.
+   -  Improved support of the PostgreSQL driver, including:
+	 - pg_version() is now used to get the database version number, when possible.
+	 - Added db_set_charset() support.
+	 - Added support for optimize_table() in :doc:`Database Utilities <database/utilities>` (rebuilds table indexes).
+	 - Added boolean data type support in escape().
+	 - Added update_batch() support.
+	 - Removed limit() and order_by() support for UPDATE and DELETE queries in as PostgreSQL does not support those features.
+   -  Added a constructor to the DB_result class and moved all driver-specific properties and logic out of the base DB_driver class to allow better abstraction.
+   -  Removed protect_identifiers() and renamed internal method _protect_identifiers() to it instead - it was just an alias.
+   -  Renamed internal method _escape_identifiers() to escape_identifiers().
+   -  Updated escape_identifiers() to accept an array of fields as well as strings.
+   -  MySQL and MySQLi drivers now require at least MySQL version 5.1.
+   -  db_set_charset() now only requires one parameter (collation was only needed due to legacy support for MySQL versions prior to 5.1).
+   -  Added support for SQLite3 database driver.
+   -  Improved support of the CUBRID driver, including:
+	 - Added DSN string support.
+	 - Added persistent connections support.
+	 - Improved list_databases() in :doc:`Database Utility <database/utilities>` (until now only the currently used database was returned).
+   -  Improved support of the MSSQL and SQLSRV drivers, including:
+	 - Added random ordering support.
+	 - Added support for optimize_table() in :doc:`Database Utility <database/utilities>`.
+	 - Added escaping with QUOTE_IDENTIFIER setting detection.
+	 - Added port handling support for UNIX-based systems (MSSQL driver).
+	 - Added OFFSET support for SQL Server 2005 and above.
+   -  Improved support of the Oracle (OCI8) driver, including:
+	 - Added DSN string support (Easy Connect and TNS).
+	 - Added support for drop_table() in :doc:`Database Forge <database/forge>`.
+	 - Added support for list_databases() in :doc:`Database Utilities <database/utilities>`.
+	 - Generally improved for speed and cleaned up all of its components.
+	 - *Row* result methods now really only fetch only the needed number of rows, instead of depending entirely on result().
+	 - num_rows() is now only called explicitly by the developer and no longer re-executes statements.
+   -  Improved support of the SQLite driver, including:
+	 - Added support for replace() in :doc:`Query Builder <database/query_builder>`.
+	 - Added support for drop_table() in :doc:`Database Forge <database/forge>`.
+   -  Added ODBC support for create_database(), drop_database() and drop_table() in :doc:`Database Forge <database/forge>`.
+   -  Added PDO support for create_database(), drop_database and drop_table() in :doc:`Database Forge <database/forge>`.
+   -  Added unbuffered_row() method for getting a row without prefetching whole result (consume less memory).
 
 -  Libraries
 
    -  Added max_filename_increment config setting for Upload library.
    -  CI_Loader::_ci_autoloader() is now a protected method.
-   -  Modified valid_ip() to use PHP's filter_var() when possible (>= PHP 5.2) in the :doc:`Form Validation library <libraries/form_validation>`.
-	 -  Added custom filename to Email::attach() as $this->email->attach($filename, $disposition, $newname)
-   -  Cart library 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).
+   -  :doc:`Cart library <libraries/cart>` changes include:
 	 -  It now auto-increments quantity's instead of just resetting it, this is the default behaviour of large e-commerce sites.
-	 -  Product Name strictness can be disabled via the Cart Library by switching "$product_name_safe"
-	 -  Added function remove() to remove a cart item, updating with quantity of 0 seemed like a hack but has remained to retain compatability
-   -  Image manipulation library changes include:
+	 -  Product Name strictness can be disabled via the Cart Library by switching "$product_name_safe".
+	 -  Added function remove() to remove a cart item, updating with quantity of 0 seemed like a hack but has remained to retain compatibility.
+   -  :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.
-	 -  Class properties wm_font_color, wm_shadow_color and wm_use_drop_shadow are now protected, to avoid breaking the text_watermark() method
-	    if they are set manually after initialization.
-   -  Minor speed optimizations and method & property visibility declarations in the Calendar Library.
+	 -  Class properties wm_font_color, wm_shadow_color and wm_use_drop_shadow are now protected, to avoid breaking the text_watermark() method if they are set manually after initialization.
+	 -  If property maintain_ratio is set to TRUE, image_reproportion() now doesn't need both width and height to be specified.
    -  Removed SHA1 function in the :doc:`Encryption Library <libraries/encryption>`.
    -  Added $config['csrf_regeneration'] to the CSRF protection in the :doc:`Security library <libraries/security>`, which makes token regeneration optional.
+   -  :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.
+	 -  Added method reset_validation(), which resets internal validation variables in case of multiple validation routines.
+	 -  Added support for setting error delimiters in the config file via $config['error_prefix'] and $config['error_suffix'].
+	 -  _execute() now considers input data to be invalid if a specified rule is not found.
+	 -  Removed method is_numeric() as it exists as a native PHP function and _execute() will find and use that (the 'is_numeric' rule itself is deprecated since 1.6.1).
+	 -  Native PHP functions used as rules can now accept an additional parameter, other than the data itself.
+   -  Changed the :doc:`Session Library <libraries/sessions>` to select only one row when using database sessions.
+   -  Added all_flashdata() method to session class. Returns an associative array of only flashdata.
+   -  Allowed for setting table class defaults in a config file.
+   -  Added a Wincache driver to the :doc:`Caching Library <libraries/caching>`.
+   -  Added a Redis driver to the :doc:`Caching Library <libraries/caching>`.
+   -  Added dsn (delivery status notification) option to the :doc:`Email Library <libraries/email>`.
+   -  Renamed method _set_header() to set_header() and made it public to enable adding custom headers in the :doc:`Email Library <libraries/email>`.
+   -  Added an "index" parameter to the data() method in the :doc:`Upload library <libraries/file_uploading>`.
 
 -  Core
 
@@ -75,37 +162,139 @@
    -  Removed CI_CORE boolean constant from CodeIgniter.php (no longer Reactor and Core versions).
    -  Added method get_vars() to CI_Loader to retrieve all variables loaded with $this->load->vars().
    -  is_loaded() function from system/core/Commons.php now returns a reference.
+   -  $config['rewrite_short_tags'] now has no effect when using PHP 5.4 as *<?=* will always be available.
+   -  Added method() to CI_Input to retrieve $_SERVER['REQUEST_METHOD'].
+   -  Modified valid_ip() to use PHP's filter_var() in the :doc:`Input Library <libraries/input>`.
+   -  Added support for HTTP-Only cookies with new config option ``cookie_httponly`` (default FALSE).
+   -  Renamed method _call_hook() to call_hook() in the :doc:`Hooks Library <general/hooks>`.
+   -  Added get_content_type() method to the :doc:`Output Library <libraries/output>`.
+   -  Added get_mimes() function to system/core/Commons.php to return the config/mimes.php array.
+   -  Added a second argument to set_content_type() in the :doc:`Output Library <libraries/output>` that allows setting the document charset as well.
 
 Bug fixes for 3.0
 ------------------
 
--  Unlink raised an error if cache file did not exist when you try to delete it.
--  Fixed a bug (#181) where a mis-spelling was in the form validation
-   language file.
--  Fixed a bug (#159, #163) that mishandled Active Record nested transactions because _trans_depth was not getting incremented.
+-  Fixed a bug where ``unlink()`` raised an error if cache file did not exist when you try to delete it.
+-  Fixed a bug (#181) where a mis-spelling was in the form validation language file.
+-  Fixed a bug (#159, #163) that mishandled Query Builder nested transactions because _trans_depth was not getting incremented.
 -  Fixed a bug (#737, #75) where pagination anchor class was not set properly when using initialize method.
 -  Fixed a bug (#419) - auto_link() now recognizes URLs that come after a word boundary.
 -  Fixed a bug (#724) - is_unique in form validation now checks that you are connected to a database.
--  Fixed a bug (#647) - _get_mod_time() in Zip library no longer generates stat failed errors
--  Fixed a bug (#608) - Fixes an issue with the Image_lib class not clearing properties completely
--  Fixed bugs (#157 and #174) - the Image_lib clear() function now resets all variables to their default values.
+-  Fixed a bug (#647) - _get_mod_time() in Zip library no longer generates stat failed errors.
+-  Fixed a bug (#608) - Fixes an issue with the Image_lib class not clearing properties completely.
+-  Fixed a bug (#157, #174) - the Image_lib clear() function now resets all variables to their default values.
 -  Fixed a bug where using $this->dbforge->create_table() with PostgreSQL database could lead to fetching whole table.
 -  Fixed a bug (#795) - Fixed form method and accept-charset when passing an empty array.
--  Fixed a bug (#797) - timespan was using incorrect seconds for year and month.
+-  Fixed a bug (#797) - timespan() was using incorrect seconds for year and month.
 -  Fixed a bug in CI_Cart::contents() where if called without a TRUE (or equal) parameter, it would fail due to a typo.
--  Fixed a bug (#696) - make oci_execute calls inside num_rows non-committing, since they are only there to reset which row is next in line for oci_fetch calls and thus don't need to be committed.
--  Fixed a bug (#406) - sqlsrv DB driver not reuturning resource on <samp>db_pconnect()</samp>.
+-  Fixed a bug (#696) - make oci_execute() calls inside num_rows() non-committing, since they are only there to reset which row is next in line for oci_fetch calls and thus don't need to be committed.
+-  Fixed a bug (#406) - SQLSRV DB driver not returning resource on ``db_pconnect()``.
 -  Fixed a bug in CI_Image_lib::gd_loaded() where it was possible for the script execution to end or a PHP E_WARNING message to be emitted.
--  In Pagination library, when use_page_numbers=TRUE previous link and page 1 link do not have the same url
+-  Fixed a bug in the :doc:`Pagination library <libraries/pagination>` where when use_page_numbers=TRUE previous link and page 1 link did not have the same url.
 -  Fixed a bug (#561) - Errors in :doc:`XML-RPC Library <libraries/xmlrpc>` were not properly escaped.
 -  Fixed a bug (#904) - ``CI_Loader::initialize()`` caused a PHP Fatal error to be triggered if error level E_STRICT is used.
--  Fixed a hosting edge case where an empty $_SERVER['HTTPS'] variable would evaluate to 'on'
+-  Fixed a hosting edge case where an empty $_SERVER['HTTPS'] variable would evaluate to 'on'.
 -  Fixed a bug (#154) - ``CI_Session::sess_update()`` caused the session to be destroyed on pages where multiple AJAX requests were executed at once.
+-  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 (#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.
+-  Fixed a bug (#153) - E_NOTICE being generated by getimagesize() in the :doc:`File Uploading Library <libraries/file_uploading>`.
+-  Fixed a bug (#611) - SQLSRV's error handling methods used to issue warnings when there's no actual error.
+-  Fixed a bug (#1036) - is_write_type() method in the :doc:`Database Library <database/index>` didn't return TRUE for RENAME queries.
+-  Fixed a bug in PDO's _version() method where it used to return the client version as opposed to the server one.
+-  Fixed a bug in PDO's insert_id() method where it could've failed if it's used with Postgre versions prior to 8.1.
+-  Fixed a bug in CUBRID's affected_rows() method where a connection resource was passed to cubrid_affected_rows() instead of a result.
+-  Fixed a bug (#638) - db_set_charset() ignored its arguments and always used the configured charset instead.
+-  Fixed a bug (#413) - Oracle's error handling methods used to only return connection-related errors.
+-  Fixed a bug (#804) - Profiler library was trying to handle objects as strings in some cases, resulting in warnings being issued by htmlspecialchars().
+-  Fixed a bug (#1101) - MySQL/MySQLi result method field_data() was implemented as if it was handling a DESCRIBE result instead of the actual result set.
+-  Fixed a bug in Oracle's :doc:`Database Forge Class <database/forge>` method _create_table() where it failed with AUTO_INCREMENT as it's not supported.
+-  Fixed a bug (#1080) - When using the SMTP protocol, the :doc:`Email Library <libraries/email>` send() method was returning TRUE even if the connection/authentication against the server failed.
+-  Fixed a bug (#499) - a CSRF cookie was created even with CSRF protection being disabled.
+-  Fixed a bug (#306) - ODBC's insert_id() method was calling non-existent function odbc_insert_id(), which resulted in a fatal error.
+-  Fixed a bug in Oracle's DB_result class where the cursor id passed to it was always NULL.
+-  Fixed a bug (#64) - Regular expression in DB_query_builder.php failed to handle queries containing SQL bracket delimiters in the join condition.
+-  Fixed a bug in the :doc:`Session Library <libraries/sessions>` where a PHP E_NOTICE error was triggered by _unserialize() due to results from databases such as MSSQL and Oracle being space-padded on the right.
+-  Fixed a bug (#501) - set_rules() to check if the request method is not 'POST' before aborting, instead of depending on count($_POST) in the :doc:`Form Validation Library <libraries/form_validation>`.
+-  Fixed a bug (#940) - csrf_verify() used to set the CSRF cookie while processing a POST request with no actual POST data, which resulted in validating a request that should be considered invalid.
+-  Fixed a bug (#136) - PostgreSQL, MySQL and MySQLi's escape_str() method didn't properly escape LIKE wild characters.
+-  Fixed a bug in the library loader where some PHP versions wouldn't execute the class constructor.
+-  Fixed a bug (#88) - An unexisting property was used for configuration of the Memcache cache driver.
+-  Fixed a bug (#14) - create_database() method in the :doc:`Database Forge Library <database/forge>` didn't utilize the configured database character set.
+-  Fixed a bug (#23, #1238) - delete_all() in the `Database Caching Library <database/caching>` used to delete .htaccess and index.html files, which is a potential security risk.
+-  Fixed a bug in :doc:`Trackback Library <libraries/trackback>` method validate_url() where it didn't actually do anything, due to input not being passed by reference.
+-  Fixed a bug (#11, #183, #863) - CI_Form_validation::_execute() silently continued to the next rule, if a rule method/function is not found.
+-  Fixed a bug (#122) Where routed uri string was being reported incorrectly in sub-directories.
+-  Fixed a bug (#1242) - read_dir() in the :doc:`Zip Library <libraries/zip>` wasn't compatible with Windows.
+-  Fixed a bug (#306) - ODBC driver didn't have an _insert_batch() method, which resulted in fatal error being triggered when insert_batch() is used with it.
+-  Fixed a bug in MSSQL and SQLSrv's _truncate() where the TABLE keyword was missing.
+-  Fixed a bug in PDO's trans_commit() method where it failed due to an erroneous property name.
+-  Fixed a bug (#798) - update() used to ignore LIKE conditions that were set with like().
+-  Fixed a bug in Oracle's and MSSQL's delete() methods where an erroneous SQL statement was generated when used with limit().
+-  Fixed a bug in SQLSRV's delete() method where like() and limit() conditions were ignored.
+-  Fixed a bug (#1265) - Database connections were always closed, regardless of the 'pconnect' option value.
+-  Fixed a bug (#128) - :doc:`Language Library <libraries/language>` did not correctly keep track of loaded language files.
+-  Fixed a bug (#1242) - Added Windows path compatibility to function read_dir of ZIP library.
+-  Fixed a bug (#1314) - sess_destroy() did not destroy userdata.
+-  Fixed a bug (#1349) - get_extension() in the :doc:`File Uploading Library <libraries/file_uploading>` returned the original filename when it didn't have an actual extension.
+-  Fixed a bug (#1273) - E_NOTICE being generated by :doc:`Query Builder <database/query_builder>`'s set_update_batch() method.
+-  Fixed a bug (#44, #110) - :doc:`Upload library <libraries/file_uploading>`'s clean_file_name() method didn't clear '!' and '#' characters.
+-  Fixed a bug (#121) - ``CI_DB_result::row()`` returned an array when there's no actual result to be returned.
+-  Fixed a bug (#319) - SQLSRV's affected_rows() method failed due to a scrollable cursor being created for write-type queries.
+-  Fixed a bug (#356) - PostgreSQL driver didn't have an _update_batch() method, which resulted in fatal error being triggered when update_batch() is used with it.
+-  Fixed a bug (#784, #862) - :doc:`Database Forge <database/forge>` method ``create_table()`` failed on SQLSRV/MSSQL when used with 'IF NOT EXISTS'.
+-  Fixed a bug (#1419) - libraries/Driver.php had a static variable that was causing an error.
+-  Fixed a bug (#1411) - the :doc:`Email library <libraries/email>` used its own short list of MIMEs instead the one from config/mimes.php.
+-  Fixed a bug where the magic_quotes_runtime setting wasn't turned off for PHP 5.3 (where it is indeed deprecated, but not non-existent).
+-  Fixed a bug (#666) - :doc:`Output library <libraries/output>`'s set_content_type() method didn't set the document charset.
+-  Fixed a bug (#784, #861) - :doc:`Database Forge <database/forge>` method ``create_table()`` used to accept constraints for MSSQL/SQLSRV integer-type columns.
+-  Fixed a bug (#706) - SQLSRV/MSSSQL didn't escape field names.
+-  Fixed a bug (#1452) - protect_identifiers() didn't properly detect identifiers with spaces in their names.
+-  Fixed a bug where protect_identifiers() ignored it's extra arguments when the value passed to it is an array.
+-  Fixed a bug where _has_operator() didn't detect BETWEEN.
+-  Fixed a bug where :doc:`Query Builder <database/query_builder>`'s join() method failed with identifiers containing dashes.
+-  Fixed a bug (#1264) - :doc:`Database Forge <database/forge>` and :doc:`Database Utilities <database/utilities>` didn't update/reset the databases and tables list cache when a table or a database is created, dropped or renamed.
+-  Fixed a bug (#7) - :doc:`Query Builder <database/query_builder>`'s join() method only escaped one set of conditions.
+-  Fixed a bug (#1321) - Core Exceptions class couldn't find the errors/ folder in some cases.
+
+Version 2.1.1
+=============
+
+Release Date: Not Released
+
+-  General Changes
+   -  Fixed support for docx, xlsx files in mimes.php.
+
+-  Libraries
+   -  Further improved MIME type detection in the :doc:`File Uploading Library <libraries/file_uploading>`.
+   -  Added support for IPv6 to the :doc:`Input Library <libraries/input>`.
+   -  Added support for the IP format parameter to the :doc:`Form Validation Library <libraries/form_validation>`.
+
+-  Helpers
+   -  url_title() performance and output improved. You can now use any string as the word delimiter, but 'dash' and 'underscore' are still supported.
+
+Bug fixes for 2.1.1
+-------------------
+
+-  Fixed a bug (#697) - A wrong array key was used in the Upload library to check for mime-types.
+-  Fixed a bug - form_open() compared $action against site_url() instead of base_url().
+-  Fixed a bug - CI_Upload::_file_mime_type() could've failed if mime_content_type() is used for the detection and returns FALSE.
+-  Fixed a bug (#538) - Windows paths were ignored when using the :doc:`Image Manipulation Library <libraries/image_lib>` to create a new file.
+-  Fixed a bug - When database caching was enabled, $this->db->query() checked the cache before binding variables which resulted in cached queries never being found.
+-  Fixed a bug - CSRF cookie value was allowed to be any (non-empty) string before being written to the output, making code injection a risk.
+-  Fixed a bug (#726) - PDO put a 'dbname' argument in it's connection string regardless of the database platform in use, which made it impossible to use SQLite.
+-  Fixed a bug - CI_DB_pdo_driver::num_rows() was not returning properly value with SELECT queries, cause it was relying on PDOStatement::rowCount().
+-  Fixed a bug (#1059) - CI_Image_lib::clear() was not correctly clearing all necessary object properties, namely width and height.
+-  Fixed a bud (#1387) - Active Record's ``from()`` method didn't escape table aliases.
 
 Version 2.1.0
 =============
 
-Release Date: Not Released
+Release Date: November 14, 2011
 
 -  General Changes
 
@@ -163,11 +352,9 @@
       override them.
    -  Removed CI_CORE boolean constant from CodeIgniter.php (no longer Reactor and Core versions).
 
-
 Bug fixes for 2.1.0
 -------------------
 
-
 -  Fixed #378 Robots identified as regular browsers by the User Agent
    class.
 -  If a config class was loaded first then a library with the same name
@@ -1166,7 +1353,7 @@
 
 -  Added a language key for valid_emails in validation_lang.php.
 -  Amended fixes for bug (#3419) with parsing DSN database connections.
--  Moved the _has_operators() function (#4535) into DB_driver from
+-  Moved the _has_operator() function (#4535) into DB_driver from
    DB_active_rec.
 -  Fixed a syntax error in upload_lang.php.
 -  Fixed a bug (#4542) with a regular expression in the Image library.
diff --git a/user_guide_src/source/conf.py b/user_guide_src/source/conf.py
index 593ceaf..e972a38 100644
--- a/user_guide_src/source/conf.py
+++ b/user_guide_src/source/conf.py
@@ -121,7 +121,7 @@
 # Add any paths that contain custom static files (such as style sheets) here,
 # relative to this directory. They are copied after the builtin static files,
 # so a file named "default.css" will overwrite the builtin "default.css".
-html_static_path = ['_static']
+#html_static_path = ['_static']
 
 # If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
 # using the given strftime format.
diff --git a/user_guide_src/source/database/configuration.rst b/user_guide_src/source/database/configuration.rst
index 4f88c25..7a19c84 100644
--- a/user_guide_src/source/database/configuration.rst
+++ b/user_guide_src/source/database/configuration.rst
@@ -28,6 +28,10 @@
 	$db['default']['autoinit'] = TRUE;
 	$db['default']['stricton'] = FALSE;
 
+If you use PDO as your dbdriver, you can specify the full DSN string describe a connection to the database like this::
+
+	$db['default']['dsn'] = 'pgsql:host=localhost;port=5432;dbname=database_name';
+
 You can also specify failovers for the situation when the main connection cannot connect for some reason.
 These failovers can be specified by setting the failover for a connection like this::
 
@@ -102,18 +106,18 @@
 default we've used the word "default" for the primary connection, but it
 too can be renamed to something more relevant to your project.
 
-Active Record
+Query Builder
 -------------
 
-The :doc:`Active Record Class <active_record>` is globally enabled or
-disabled by setting the $active_record variable in the database
+The :doc:`Query Builder Class <query_builder>` is globally enabled or
+disabled by setting the $query_builder variable in the database
 configuration file to TRUE/FALSE (boolean). If you are not using the
-active record class, setting it to FALSE will utilize fewer resources
+query builder class, setting it to FALSE will utilize fewer resources
 when the database classes are initialized.
 
 ::
 
-	$active_record = TRUE;
+	$query_builder = TRUE;
 
 .. note:: that some CodeIgniter classes such as Sessions require Active
 	Records be enabled to access certain functionality.
@@ -128,9 +132,9 @@
 **username**		The username used to connect to the database.
 **password**		The password used to connect to the database.
 **database**		The name of the database you want to connect to.
-**dbdriver**		The database type. ie: mysql, postgres, odbc, etc. Must be specified in lower case.
+**dbdriver**		The database type. ie: mysql, postgre, odbc, etc. Must be specified in lower case.
 **dbprefix**		An optional table prefix which will added to the table name when running :doc:
-			`Active Record <active_record>` queries. This permits multiple CodeIgniter installations
+			`Query Builder <query_builder>` queries. This permits multiple CodeIgniter installations
 			to share one database.
 **pconnect**		TRUE/FALSE (boolean) - Whether to use a persistent connection.
 **db_debug**		TRUE/FALSE (boolean) - Whether database errors should be displayed.
@@ -162,8 +166,8 @@
 				$db['default']['port'] =  5432;
 ======================  ==================================================================================================
 
-.. note:: Depending on what database platform you are using (MySQL,
-	Postgres, etc.) not all values will be needed. For example, when using
-	SQLite you will not need to supply a username or password, and the
-	database name will be the path to your database file. The information
-	above assumes you are using MySQL.
+.. note:: Depending on what database platform you are using (MySQL, PostgreSQL,
+	etc.) not all values will be needed. For example, when using SQLite you
+	will not need to supply a username or password, and the database name
+	will be the path to your database file. The information above assumes
+	you are using MySQL.
diff --git a/user_guide_src/source/database/connecting.rst b/user_guide_src/source/database/connecting.rst
index a834cc0..5822ca6 100644
--- a/user_guide_src/source/database/connecting.rst
+++ b/user_guide_src/source/database/connecting.rst
@@ -36,7 +36,7 @@
    string.
 #. TRUE/FALSE (boolean). Whether to return the connection ID (see
    Connecting to Multiple Databases below).
-#. TRUE/FALSE (boolean). Whether to enable the Active Record class. Set
+#. TRUE/FALSE (boolean). Whether to enable the Query Builder class. Set
    to TRUE by default.
 
 Manually Connecting to a Database
@@ -122,6 +122,12 @@
 	| $DB1->result();
 	| etc...
 
+.. note:: You don't need to create separate database configurations if you
+	only need to use a different database on the same connection. You
+	can switch to a different database when you need to, like this:
+
+	| $this->db->db_select($database2_name);
+
 Reconnecting / Keeping the Connection Alive
 ===========================================
 
diff --git a/user_guide_src/source/database/examples.rst b/user_guide_src/source/database/examples.rst
index d1cd488..8b3cc47 100644
--- a/user_guide_src/source/database/examples.rst
+++ b/user_guide_src/source/database/examples.rst
@@ -104,10 +104,10 @@
 	$this->db->query($sql);
 	echo $this->db->affected_rows();
 
-Active Record Query
+Query Builder Query
 ===================
 
-The :doc:`Active Record Pattern <active_record>` gives you a simplified
+The :doc:`Query Builder Pattern <query_builder>` gives you a simplified
 means of retrieving data::
 
 	$query = $this->db->get('table_name');
@@ -118,10 +118,10 @@
 	}
 
 The above get() function retrieves all the results from the supplied
-table. The :doc:`Active Record <active_record>` class contains a full
+table. The :doc:`Query Builder <query_builder>` class contains a full
 compliment of functions for working with data.
 
-Active Record Insert
+Query Builder Insert
 ====================
 
 ::
diff --git a/user_guide_src/source/database/helpers.rst b/user_guide_src/source/database/helpers.rst
index 7ea19e9..e8a5ac8 100644
--- a/user_guide_src/source/database/helpers.rst
+++ b/user_guide_src/source/database/helpers.rst
@@ -7,9 +7,9 @@
 
 The insert ID number when performing database inserts.
 
-.. note:: If using the PDO driver with PostgreSQL, this function requires
-	a $name parameter, which specifies the appropriate sequence to check
-	for the insert id.
+.. note:: If using the PDO driver with PostgreSQL, or using the Interbase
+	driver, this function requires a $name parameter, which specifies the 
+	appropriate sequence to check for the insert id.
 
 $this->db->affected_rows()
 ===========================
diff --git a/user_guide_src/source/database/index.rst b/user_guide_src/source/database/index.rst
index ab12b7c..7ccb8fb 100644
--- a/user_guide_src/source/database/index.rst
+++ b/user_guide_src/source/database/index.rst
@@ -3,7 +3,7 @@
 ##################
 
 CodeIgniter comes with a full-featured and very fast abstracted database
-class that supports both traditional structures and Active Record
+class that supports both traditional structures and Query Builder
 patterns. The database functions offer clear, simple syntax.
 
 .. toctree::
@@ -15,7 +15,7 @@
 	Running Queries <queries>
 	Generating Query Results <results>
 	Query Helper Functions <helpers>
-	Active Record Class <active_record>
+	Query Builder Class <query_builder>
 	Transactions <transactions>
 	Table MetaData <table_data>
 	Field MetaData <fields>
diff --git a/user_guide_src/source/database/queries.rst b/user_guide_src/source/database/queries.rst
index 971d5d6..d23efec 100644
--- a/user_guide_src/source/database/queries.rst
+++ b/user_guide_src/source/database/queries.rst
@@ -50,7 +50,7 @@
 **********************
 
 In many databases it is advisable to protect table and field names - for
-example with backticks in MySQL. **Active Record queries are
+example with backticks in MySQL. **Query Builder queries are
 automatically protected**, however if you need to manually protect an
 identifier you can use::
 
@@ -112,3 +112,20 @@
 automatically escaped, producing safer queries. You don't have to
 remember to manually escape data; the engine does it automatically for
 you.
+
+***************
+Handling Errors
+***************
+
+$this->db->error();
+===================
+
+If you need to get the last error that has occured, the error() method
+will return an array containing its code and message. Here's a quick
+example::
+
+	if ( ! $this->db->simple_query('SELECT `example_field` FROM `example_table`'))
+	{
+		$error = $this->db->error(); // Has keys 'code' and 'message'
+	}
+
diff --git a/user_guide_src/source/database/active_record.rst b/user_guide_src/source/database/query_builder.rst
similarity index 95%
rename from user_guide_src/source/database/active_record.rst
rename to user_guide_src/source/database/query_builder.rst
index c04e67d..54e8df6 100644
--- a/user_guide_src/source/database/active_record.rst
+++ b/user_guide_src/source/database/query_builder.rst
@@ -1,15 +1,15 @@
 ###################
-Active Record Class
+Query Builder Class
 ###################
 
-CodeIgniter uses a modified version of the Active Record Database
-Pattern. This pattern allows information to be retrieved, inserted, and
-updated in your database with minimal scripting. In some cases only one
-or two lines of code are necessary to perform a database action.
+CodeIgniter gives you access to a Query Builder class. This pattern 
+allows information to be retrieved, inserted, and updated in your 
+database with minimal scripting. In some cases only one or two lines
+of code are necessary to perform a database action.
 CodeIgniter does not require that each database table be its own class
 file. It instead provides a more simplified interface.
 
-Beyond simplicity, a major benefit to using the Active Record features
+Beyond simplicity, a major benefit to using the Query Builder features
 is that it allows you to create database independent applications, since
 the query syntax is generated by each database adapter. It also allows
 for safer queries, since the values are escaped automatically by the
@@ -67,7 +67,7 @@
 
 	// Produces string: SELECT * FROM mytable
 
-The second parameter enables you to set whether or not the active record query
+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()`)::
 
 	echo $this->db->limit(10,20)->get_compiled_select('mytable', FALSE);
@@ -512,7 +512,7 @@
 ==============================
 
 Permits you to determine the number of rows in a particular Active
-Record query. Queries will accept Active Record restrictors such as
+Record query. Queries will accept Query Builder restrictors such as
 where(), or_where(), like(), or_like(), etc. Example::
 
 	echo $this->db->count_all_results('my_table');  // Produces an integer, like 25
@@ -533,7 +533,7 @@
 **************
 
 Query grouping allows you to create groups of WHERE clauses by enclosing them in parentheses. This will allow
-you to create queries with complex WHERE clauses. Nested groups are supported. Example:
+you to create queries with complex WHERE clauses. Nested groups are supported. Example::
 
 	$this->db->select('*')->from('my_table')
 		->group_start()
@@ -636,7 +636,7 @@
 
 	// Produces string: INSERT INTO mytable (title, name, date) VALUES ('My title', 'My name', 'My date')
 
-The second parameter enables you to set whether or not the active record query
+The second parameter enables you to set whether or not the query builder query
 will be reset (by default it will be--just like `$this->db->insert()`_)::
 
 	echo $this->db->set('title', 'My Title')->get_compiled_insert('mytable', FALSE);
@@ -921,19 +921,19 @@
 multiple functions. Consider this example::
 
 	$query = $this->db->select('title')
-				->where('id', $id)
-				->limit(10, 20)
-				->get('mytable');
+			->where('id', $id)
+			->limit(10, 20)
+			->get('mytable');
 
 .. _ar-caching:
 
 *********************
-Active Record Caching
+Query Builder Caching
 *********************
 
-While not "true" caching, Active Record enables you to save (or "cache")
+While not "true" caching, Query Builder enables you to save (or "cache")
 certain parts of your queries for reuse at a later point in your
-script's execution. Normally, when an Active Record call is completed,
+script's execution. Normally, when an Query Builder call is completed,
 all stored information is reset for the next call. With caching, you can
 prevent this reset, and reuse information easily.
 
@@ -944,7 +944,7 @@
 $this->db->start_cache()
 ========================
 
-This function must be called to begin caching. All Active Record queries
+This function must be called to begin caching. All Query Builder queries
 of the correct type (see below for supported queries) are stored for
 later use.
 
@@ -956,7 +956,7 @@
 $this->db->flush_cache()
 ========================
 
-This function deletes all items from the Active Record cache.
+This function deletes all items from the Query Builder cache.
 
 Here's a usage example::
 
@@ -983,12 +983,12 @@
 $this->db->reset_query()
 ========================
 
-Resetting Active Record allows you to start fresh with your query without
+Resetting Query Builder allows you to start fresh with your query without
 executing it first using a method like $this->db->get() or $this->db->insert().
 Just like the methods that execute a query, this will *not* reset items you've
-cached using `Active Record Caching`_.
+cached using `Query Builder Caching`_.
 
-This is useful in situations where you are using Active Record to generate SQL
+This is useful in situations where you are using Query Builder to generate SQL
 (ex. ``$this->db->get_compiled_select()``) but then choose to, for instance,
 run the query::
 
diff --git a/user_guide_src/source/database/results.rst b/user_guide_src/source/database/results.rst
index 4f93c79..ac4fc37 100644
--- a/user_guide_src/source/database/results.rst
+++ b/user_guide_src/source/database/results.rst
@@ -136,6 +136,26 @@
 	| **$row = $query->next_row('array')**
 	| **$row = $query->previous_row('array')**
 
+.. note:: all the functions above will load the whole result into memory (prefetching) use unbuffered_row() for processing large result sets.
+
+unbuffered_row($type)
+=====
+
+This function returns a single result row without prefetching the whole result in memory as row() does.
+If your query has more than one row, it returns the current row and moves the internal data pointer ahead. 
+The result is returned as $type could be 'object' (default) or 'array' that will return an associative array.
+
+
+
+	$query = $this->db->query("YOUR QUERY");
+	
+	while ($row = $query->unbuffered_row())
+	{	
+		echo $row->title;
+		echo $row->name;
+		echo $row->body;
+	}
+
 ***********************
 Result Helper Functions
 ***********************
@@ -150,6 +170,12 @@
 	
 	echo $query->num_rows();
 
+.. note::
+	Not all database drivers have a native way of getting the total
+	number of rows for a result set. When this is the case, all of
+	the data is prefetched and count() is manually called on the
+	resulting array in order to achieve the same functionality.
+	
 $query->num_fields()
 =====================
 
@@ -182,5 +208,4 @@
 
 	$row = $query2->row();
 	echo $row->name;
-	$query2->free_result();// The $query2 result object will no longer be available
-
+	$query2->free_result(); // The $query2 result object will no longer be available
diff --git a/user_guide_src/source/database/utilities.rst b/user_guide_src/source/database/utilities.rst
index b092010..4e83929 100644
--- a/user_guide_src/source/database/utilities.rst
+++ b/user_guide_src/source/database/utilities.rst
@@ -117,7 +117,7 @@
 	echo $this->dbutil->csv_from_result($query);
 
 The second, third, and fourth parameters allow you to set the delimiter
-newline, and enclosure characters respectively. By default tabs are
+newline, and enclosure characters respectively. By default commas are
 used as the delimiter, "\n" is used as a new line, and a double-quote
 is used as the enclosure. Example::
 
@@ -161,7 +161,11 @@
 Permits you to backup your full database or individual tables. The
 backup data can be compressed in either Zip or Gzip format.
 
-.. note:: This features is only available for MySQL databases.
+.. note:: This features is only available for MySQL and Interbase/Firebird databases.
+
+.. note:: For Interbase/Firebird databases, the backup file name is the only parameter.
+	
+		Eg. $this->dbutil->backup('db_backup_filename');
 
 .. note:: Due to the limited execution time and memory available to PHP,
 	backing up very large databases may not be possible. If your database is
diff --git a/user_guide_src/source/general/common_functions.rst b/user_guide_src/source/general/common_functions.rst
index 70563b8..99126f9 100644
--- a/user_guide_src/source/general/common_functions.rst
+++ b/user_guide_src/source/general/common_functions.rst
@@ -79,3 +79,8 @@
 This function provides short cut for htmlspecialchars() function. It
 accepts string and array. To prevent Cross Site Scripting (XSS), it is
 very useful.
+
+get_mimes()
+=============
+
+This function returns the MIMEs array from config/mimes.php.
\ No newline at end of file
diff --git a/user_guide_src/source/general/core_classes.rst b/user_guide_src/source/general/core_classes.rst
index ac41407..4aa6693 100644
--- a/user_guide_src/source/general/core_classes.rst
+++ b/user_guide_src/source/general/core_classes.rst
@@ -31,6 +31,7 @@
 -  Log
 -  Output
 -  Router
+-  Security
 -  URI
 -  Utf8
 
diff --git a/user_guide_src/source/general/creating_libraries.rst b/user_guide_src/source/general/creating_libraries.rst
index bc545b4..673fbd4 100644
--- a/user_guide_src/source/general/creating_libraries.rst
+++ b/user_guide_src/source/general/creating_libraries.rst
@@ -188,17 +188,23 @@
 
 	}
 
-Note: If you need to use a constructor in your class make sure you
+If you need to use a constructor in your class make sure you
 extend the parent constructor::
 
 	class MY_Email extends CI_Email {
 
-	    public function __construct()
-	    {
-	        parent::__construct();
-	    }
+		public function __construct($config = array())
+		{
+			parent::__construct($config);
+		}
+
 	}
 
+.. note::
+	Not all of the libraries have the same (or any) parameters
+	in their constructor. Take a look at the library that you're
+	extending first to see how it should be implemented.
+
 Loading Your Sub-class
 ----------------------
 
diff --git a/user_guide_src/source/general/environments.rst b/user_guide_src/source/general/environments.rst
index 40725fe..fa1b096 100644
--- a/user_guide_src/source/general/environments.rst
+++ b/user_guide_src/source/general/environments.rst
@@ -11,10 +11,16 @@
 The ENVIRONMENT Constant
 ========================
 
-By default, CodeIgniter comes with the environment constant set to
+By default, CodeIgniter comes with the environment constant set to use 
+the value provided in ``$_SERVER['CI_ENV']``, otherwise defaults to 
 'development'. At the top of index.php, you will see::
 
-	 define('ENVIRONMENT', 'development');
+	define('ENVIRONMENT', isset($_SERVER['CI_ENV']) ? $_SERVER['CI_ENV'] : 'development');
+
+This server variable can be set in your .htaccess file, or Apache 
+config using `SetEnv <https://httpd.apache.org/docs/2.2/mod/mod_env.html#setenv>`_. 
+Alternative methods are available for nginx and other servers, or you can 
+remove this logic entirely and set the constant based on the HTTP_HOST or IP.
 
 In addition to affecting some basic framework behavior (see the next
 section), you may use this constant in your own development to
diff --git a/user_guide_src/source/general/models.rst b/user_guide_src/source/general/models.rst
index b816f95..87f63e4 100644
--- a/user_guide_src/source/general/models.rst
+++ b/user_guide_src/source/general/models.rst
@@ -16,7 +16,7 @@
 update, and retrieve your blog data. Here is an example of what such a
 model class might look like::
 
-	class Blogmodel extends CI_Model {
+	class Blog_model extends CI_Model {
 
 	    var $title   = '';
 	    var $content = '';
@@ -55,7 +55,7 @@
 	}
 
 .. note:: The functions in the above example use the :doc:`Active
-	Record <../database/active_record>` database functions.
+	Record <../database/query_builder>` database functions.
 
 .. note:: For the sake of simplicity in this example we're using $_POST
 	directly. This is generally bad practice, and a more common approach
@@ -104,7 +104,7 @@
 :doc:`controller <controllers>` functions. To load a model you will use
 the following function::
 
-	$this->load->model('Model_name');
+	$this->load->model('model_name');
 
 If your model is located in a sub-folder, include the relative path from
 your models folder. For example, if you have a model located at
@@ -115,14 +115,14 @@
 Once loaded, you will access your model functions using an object with
 the same name as your class::
 
-	$this->load->model('Model_name');
+	$this->load->model('model_name');
 
-	$this->Model_name->function();
+	$this->model_name->function();
 
 If you would like your model assigned to a different object name you can
 specify it via the second parameter of the loading function::
 
-	$this->load->model('Model_name', 'fubar');
+	$this->load->model('model_name', 'fubar');
 
 	$this->fubar->function();
 
@@ -133,7 +133,7 @@
 
 	    function blog()
 	    {
-	        $this->load->model('Blog');
+	        $this->load->model('blog');
 
 	        $data['query'] = $this->Blog->get_last_ten_entries();
 
@@ -165,7 +165,7 @@
    defined in your database config file will be used:
    ::
 
-	$this->load->model('Model_name', '', TRUE);
+	$this->load->model('model_name', '', TRUE);
 
 -  You can manually pass database connectivity settings via the third
    parameter::
diff --git a/user_guide_src/source/general/requirements.rst b/user_guide_src/source/general/requirements.rst
index 3862355..d9edfba 100644
--- a/user_guide_src/source/general/requirements.rst
+++ b/user_guide_src/source/general/requirements.rst
@@ -2,7 +2,8 @@
 Server Requirements
 ###################
 
--  `PHP <http://www.php.net/>`_ version 5.1.6 or newer.
+-  `PHP <http://www.php.net/>`_ version 5.2.4 or newer.
 -  A Database is required for most web application programming. Current
-   supported databases are MySQL (4.1+), MySQLi, MS SQL, Postgres, Oracle,
-   SQLite, ODBC and CUBRID.
\ No newline at end of file
+   supported databases are MySQL (5.1+), MySQLi, Oracle, PostgreSQL,
+   MS SQL, SQLSRV (SQL Server 2005+), SQLite, SQLite3, CUBRID, Interbase,
+   ODBC and PDO.
diff --git a/user_guide_src/source/general/styleguide.rst b/user_guide_src/source/general/styleguide.rst
index d8bdd05..925954c 100644
--- a/user_guide_src/source/general/styleguide.rst
+++ b/user_guide_src/source/general/styleguide.rst
@@ -94,7 +94,7 @@
 
 	class Super_class {
 
-		function __construct()
+		public function __construct()
 		{
 
 		}
@@ -149,7 +149,7 @@
 the following are recommended.
 
 `DocBlock <http://manual.phpdoc.org/HTMLSmartyConverter/HandS/phpDocumentor/tutorial_phpDocumentor.howto.pkg.html#basics.docblock>`_
-style comments preceding class and method declarations so they can be
+style comments preceding class, method, and property declarations so they can be
 picked up by IDEs::
 
 	/**
@@ -168,11 +168,21 @@
 	/**
 	 * Encodes string for use in XML
 	 *
-	 * @access	public
 	 * @param	string
 	 * @return	string
 	 */
 	function xml_encode($str)
+	
+::
+
+	/**
+	 * Data for class manipulation
+	 *
+	 * @var	array
+	 */
+	public $data
+	
+	
 
 Use single line comments within code, leaving a blank line between large
 comment blocks and code.
diff --git a/user_guide_src/source/general/views.rst b/user_guide_src/source/general/views.rst
index dc65f6c..9b7c9da 100644
--- a/user_guide_src/source/general/views.rst
+++ b/user_guide_src/source/general/views.rst
@@ -49,7 +49,7 @@
 	<?php
 	class Blog extends CI_Controller {
 
-		function index()
+		public function index()
 		{
 			$this->load->view('blogview');
 		}
@@ -74,14 +74,14 @@
 
 	class Page extends CI_Controller {
 
-	   function index()
-	   {
-	      $data['page_title'] = 'Your title';
-	      $this->load->view('header');
-	      $this->load->view('menu');
-	      $this->load->view('content', $data);
-	      $this->load->view('footer');
-	   }
+		public function index()
+		{
+			$data['page_title'] = 'Your title';
+			$this->load->view('header');
+			$this->load->view('menu');
+			$this->load->view('content', $data);
+			$this->load->view('footer');
+		}
 
 	}
 	?>
@@ -126,7 +126,7 @@
 	<?php
 	class Blog extends CI_Controller {
 
-		function index()
+		public function index()
 		{
 			$data['title'] = "My Real Title";
 			$data['heading'] = "My Real Heading";
@@ -164,7 +164,7 @@
 	<?php
 	class Blog extends CI_Controller {
 
-		function index()
+		public function index()
 		{
 			$data['todo_list'] = array('Clean House', 'Call Mom', 'Run Errands');
 
diff --git a/user_guide_src/source/helpers/date_helper.rst b/user_guide_src/source/helpers/date_helper.rst
index ad06dd6..18216c5 100644
--- a/user_guide_src/source/helpers/date_helper.rst
+++ b/user_guide_src/source/helpers/date_helper.rst
@@ -255,14 +255,16 @@
 
 The first parameter must contain a Unix timestamp. The second parameter
 must contain a timestamp that is greater that the first timestamp. If
-the second parameter empty, the current time will be used. The most
-common purpose for this function is to show how much time has elapsed
-from some point in time in the past to now. 
+the second parameter empty, the current time will be used. The third 
+parameter is optional and limits the number of time units to display. 
+The most common purpose for this function is to show how much time has 
+elapsed from some point in time in the past to now. 
 
-.. php:method:: timespan($seconds = 1, $time = '')
+.. php:method:: timespan($seconds = 1, $time = '', $units = '')
 
 	:param integer 	$seconds: a number of seconds
 	:param string 	$time: Unix timestamp
+	:param integer 	$units: a number of time units to display
 	:returns: string
 
 Example
@@ -271,7 +273,8 @@
 
 	$post_date = '1079621429';
 	$now = time();
-	echo timespan($post_date, $now);
+	$units = 2;
+	echo timespan($post_date, $now, $units);
 
 .. note:: The text generated by this function is found in the following language
 	file: language/<your_lang>/date_lang.php
@@ -327,36 +330,46 @@
 
 	<form action="#">
 		<select name="timezones">
-			<option value='UM12'>(UTC - 12:00) Enitwetok, Kwajalien</option>
-			<option value='UM11'>(UTC - 11:00) Nome, Midway Island, Samoa</option>
-			<option value='UM10'>(UTC - 10:00) Hawaii</option>
-			<option value='UM9'>(UTC - 9:00) Alaska</option>
-			<option value='UM8'>(UTC - 8:00) Pacific Time</option>
-			<option value='UM7'>(UTC - 7:00) Mountain Time</option>
-			<option value='UM6'>(UTC - 6:00) Central Time, Mexico City</option>
-			<option value='UM5'>(UTC - 5:00) Eastern Time, Bogota, Lima, Quito</option>
-			<option value='UM4'>(UTC - 4:00) Atlantic Time, Caracas, La Paz</option>
-			<option value='UM25'>(UTC - 3:30) Newfoundland</option>
-			<option value='UM3'>(UTC - 3:00) Brazil, Buenos Aires, Georgetown, Falkland Is.</option>
-			<option value='UM2'>(UTC - 2:00) Mid-Atlantic, Ascention Is., St Helena</option>
-			<option value='UM1'>(UTC - 1:00) Azores, Cape Verde Islands</option>
-			<option value='UTC' selected='selected'>(UTC) Casablanca, Dublin, Edinburgh, London, Lisbon, Monrovia</option>
-			<option value='UP1'>(UTC + 1:00) Berlin, Brussels, Copenhagen, Madrid, Paris, Rome</option>
-			<option value='UP2'>(UTC + 2:00) Kaliningrad, South Africa, Warsaw</option>
-			<option value='UP3'>(UTC + 3:00) Baghdad, Riyadh, Moscow, Nairobi</option>
-			<option value='UP25'>(UTC + 3:30) Tehran</option>
-			<option value='UP4'>(UTC + 4:00) Adu Dhabi, Baku, Muscat, Tbilisi</option>
-			<option value='UP35'>(UTC + 4:30) Kabul</option>
-			<option value='UP5'>(UTC + 5:00) Islamabad, Karachi, Tashkent</option>
-			<option value='UP45'>(UTC + 5:30) Bombay, Calcutta, Madras, New Delhi</option>
-			<option value='UP6'>(UTC + 6:00) Almaty, Colomba, Dhaka</option>
-			<option value='UP7'>(UTC + 7:00) Bangkok, Hanoi, Jakarta</option>
-			<option value='UP8'>(UTC + 8:00) Beijing, Hong Kong, Perth, Singapore, Taipei</option>
-			<option value='UP9'>(UTC + 9:00) Osaka, Sapporo, Seoul, Tokyo, Yakutsk</option>
-			<option value='UP85'>(UTC + 9:30) Adelaide, Darwin</option>
-			<option value='UP10'>(UTC + 10:00) Melbourne, Papua New Guinea, Sydney, Vladivostok</option>
-			<option value='UP11'>(UTC + 11:00) Magadan, New Caledonia, Solomon Islands</option>
-			<option value='UP12'>(UTC + 12:00) Auckland, Wellington, Fiji, Marshall Island</option>
+			<option value='UM12'>(UTC -12:00) Baker/Howland Island</option>
+			<option value='UM11'>(UTC -11:00) Samoa Time Zone, Niue</option>
+			<option value='UM10'>(UTC -10:00) Hawaii-Aleutian Standard Time, Cook Islands, Tahiti</option>
+			<option value='UM95'>(UTC -9:30) Marquesas Islands</option>
+			<option value='UM9'>(UTC -9:00) Alaska Standard Time, Gambier Islands</option>
+			<option value='UM8'>(UTC -8:00) Pacific Standard Time, Clipperton Island</option>
+			<option value='UM7'>(UTC -7:00) Mountain Standard Time</option>
+			<option value='UM6'>(UTC -6:00) Central Standard Time</option>
+			<option value='UM5'>(UTC -5:00) Eastern Standard Time, Western Caribbean Standard Time</option>
+			<option value='UM45'>(UTC -4:30) Venezuelan Standard Time</option>
+			<option value='UM4'>(UTC -4:00) Atlantic Standard Time, Eastern Caribbean Standard Time</option>
+			<option value='UM35'>(UTC -3:30) Newfoundland Standard Time</option>
+			<option value='UM3'>(UTC -3:00) Argentina, Brazil, French Guiana, Uruguay</option>
+			<option value='UM2'>(UTC -2:00) South Georgia/South Sandwich Islands</option>
+			<option value='UM1'>(UTC -1:00) Azores, Cape Verde Islands</option>
+			<option value='UTC' selected='selected'>(UTC) Greenwich Mean Time, Western European Time</option>
+			<option value='UP1'>(UTC +1:00) Central European Time, West Africa Time</option>
+			<option value='UP2'>(UTC +2:00) Central Africa Time, Eastern European Time, Kaliningrad Time</option>
+			<option value='UP3'>(UTC +3:00) Moscow Time, East Africa Time</option>
+			<option value='UP35'>(UTC +3:30) Iran Standard Time</option>
+			<option value='UP4'>(UTC +4:00) Azerbaijan Standard Time, Samara Time</option>
+			<option value='UP45'>(UTC +4:30) Afghanistan</option>
+			<option value='UP5'>(UTC +5:00) Pakistan Standard Time, Yekaterinburg Time</option>
+			<option value='UP55'>(UTC +5:30) Indian Standard Time, Sri Lanka Time</option>
+			<option value='UP575'>(UTC +5:45) Nepal Time</option>
+			<option value='UP6'>(UTC +6:00) Bangladesh Standard Time, Bhutan Time, Omsk Time</option>
+			<option value='UP65'>(UTC +6:30) Cocos Islands, Myanmar</option>
+			<option value='UP7'>(UTC +7:00) Krasnoyarsk Time, Cambodia, Laos, Thailand, Vietnam</option>
+			<option value='UP8'>(UTC +8:00) Australian Western Standard Time, Beijing Time, Irkutsk Time</option>
+			<option value='UP875'>(UTC +8:45) Australian Central Western Standard Time</option>
+			<option value='UP9'>(UTC +9:00) Japan Standard Time, Korea Standard Time, Yakutsk Time</option>
+			<option value='UP95'>(UTC +9:30) Australian Central Standard Time</option>
+			<option value='UP10'>(UTC +10:00) Australian Eastern Standard Time, Vladivostok Time</option>
+			<option value='UP105'>(UTC +10:30) Lord Howe Island</option>
+			<option value='UP11'>(UTC +11:00) Magadan Time, Solomon Islands, Vanuatu</option>
+			<option value='UP115'>(UTC +11:30) Norfolk Island</option>
+			<option value='UP12'>(UTC +12:00) Fiji, Gilbert Islands, Kamchatka Time, New Zealand Standard Time</option>
+			<option value='UP1275'>(UTC +12:45) Chatham Islands Standard Time</option>
+			<option value='UP13'>(UTC +13:00) Phoenix Islands Time, Tonga</option>
+			<option value='UP14'>(UTC +14:00) Line Islands</option>
 		</select>
 	</form>
 
@@ -393,66 +406,88 @@
 
 The following table indicates each timezone and its location.
 
+Note some of the location lists have been abridged for clarity and formatting.
+
 +------------+----------------------------------------------------------------+
 | Time Zone  | Location                                                       |
 +============+================================================================+
-| UM12       | (UTC - 12:00) Enitwetok, Kwajalien                             |
+| UM12       | (UTC - 12:00) Baker/Howland Island	                          |
 +------------+----------------------------------------------------------------+
-| UM11       | (UTC - 11:00) Nome, Midway Island, Samoa                       |
+| UM11       | (UTC - 11:00) Samoa Time Zone, Niue						      |
 +------------+----------------------------------------------------------------+
-| UM10       | (UTC - 10:00) Hawaii                                           |
+| UM10       | (UTC - 10:00) Hawaii-Aleutian Standard Time, Cook Islands	  |
 +------------+----------------------------------------------------------------+
-| UM9        | (UTC - 9:00) Alaska                                            |
+| UM95       | (UTC - 09:30) Marquesas Islands							      |
 +------------+----------------------------------------------------------------+
-| UM8        | (UTC - 8:00) Pacific Time                                      |
+| UM9        | (UTC - 09:00) Alaska Standard Time, Gambier Islands		      |
 +------------+----------------------------------------------------------------+
-| UM7        | (UTC - 7:00) Mountain Time                                     |
+| UM8        | (UTC - 08:00) Pacific Standard Time, Clipperton Island	      |
 +------------+----------------------------------------------------------------+
-| UM6        | (UTC - 6:00) Central Time, Mexico City                         |
+| UM7        | (UTC - 11:00) Mountain Standard Time						      |
 +------------+----------------------------------------------------------------+
-| UM5        | (UTC - 5:00) Eastern Time, Bogota, Lima, Quito                 |
+| UM6        | (UTC - 06:00) Central Standard Time						      |
 +------------+----------------------------------------------------------------+
-| UM4        | (UTC - 4:00) Atlantic Time, Caracas, La Paz                    |
+| UM5        | (UTC - 05:00) Eastern Standard Time, Western Caribbean		  |
 +------------+----------------------------------------------------------------+
-| UM25       | (UTC - 3:30) Newfoundland                                      |
+| UM45       | (UTC - 04:30) Venezuelan Standard Time					      |
 +------------+----------------------------------------------------------------+
-| UM3        | (UTC - 3:00) Brazil, Buenos Aires, Georgetown, Falkland Is.    |
+| UM4        | (UTC - 04:00) Atlantic Standard Time, Eastern Caribbean		  |
 +------------+----------------------------------------------------------------+
-| UM2        | (UTC - 2:00) Mid-Atlantic, Ascention Is., St Helena            |
+| UM35       | (UTC - 03:30) Newfoundland Standard Time					      |
 +------------+----------------------------------------------------------------+
-| UM1        | (UTC - 1:00) Azores, Cape Verde Islands                        |
+| UM3        | (UTC - 03:00) Argentina, Brazil, French Guiana, Uruguay	      |
 +------------+----------------------------------------------------------------+
-| UTC        | (UTC) Casablanca, Dublin, Edinburgh, London, Lisbon, Monrovia  |
+| UM2        | (UTC - 02:00) South Georgia/South Sandwich Islands		      |
 +------------+----------------------------------------------------------------+
-| UP1        | (UTC + 1:00) Berlin, Brussels, Copenhagen, Madrid, Paris, Rome |
+| UM1        | (UTC -1:00) Azores, Cape Verde Islands						  |
 +------------+----------------------------------------------------------------+
-| UP2        | (UTC + 2:00) Kaliningrad, South Africa, Warsaw                 |
+| UTC        | (UTC) Greenwich Mean Time, Western European Time				  |
 +------------+----------------------------------------------------------------+
-| UP3        | (UTC + 3:00) Baghdad, Riyadh, Moscow, Nairobi                  |
+| UP1        | (UTC +1:00) Central European Time, West Africa Time			  |
 +------------+----------------------------------------------------------------+
-| UP25       | (UTC + 3:30) Tehran                                            |
+| UP2        | (UTC +2:00) Central Africa Time, Eastern European Time		  |
 +------------+----------------------------------------------------------------+
-| UP4        | (UTC + 4:00) Adu Dhabi, Baku, Muscat, Tbilisi                  |
+| UP3        | (UTC +3:00) Moscow Time, East Africa Time			  		  |
 +------------+----------------------------------------------------------------+
-| UP35       | (UTC + 4:30) Kabul                                             |
+| UP35       | (UTC +3:30) Iran Standard Time								  |
 +------------+----------------------------------------------------------------+
-| UP5        | (UTC + 5:00) Islamabad, Karachi, Tashkent                      |
+| UP4        | (UTC +4:00) Azerbaijan Standard Time, Samara Time			  |
 +------------+----------------------------------------------------------------+
-| UP45       | (UTC + 5:30) Bombay, Calcutta, Madras, New Delhi               |
+| UP45       | (UTC +4:30) Afghanistan										  |
 +------------+----------------------------------------------------------------+
-| UP6        | (UTC + 6:00) Almaty, Colomba, Dhaka                            |
+| UP5        | (UTC +5:00) Pakistan Standard Time, Yekaterinburg Time		  |
 +------------+----------------------------------------------------------------+
-| UP7        | (UTC + 7:00) Bangkok, Hanoi, Jakarta                           |
+| UP55       | (UTC +5:30) Indian Standard Time, Sri Lanka Time				  |
 +------------+----------------------------------------------------------------+
-| UP8        | (UTC + 8:00) Beijing, Hong Kong, Perth, Singapore, Taipei      |
+| UP575      | (UTC +5:45) Nepal Time										  |
 +------------+----------------------------------------------------------------+
-| UP9        | (UTC + 9:00) Osaka, Sapporo, Seoul, Tokyo, Yakutsk             |
+| UP6        | (UTC +6:00) Bangladesh Standard Time, Bhutan Time, Omsk Time   |
 +------------+----------------------------------------------------------------+
-| UP85       | (UTC + 9:30) Adelaide, Darwin                                  |
+| UP65       | (UTC +6:30) Cocos Islands, Myanmar							  |
 +------------+----------------------------------------------------------------+
-| UP10       | (UTC + 10:00) Melbourne, Papua New Guinea, Sydney, Vladivostok |
+| UP7        | (UTC +7:00) Krasnoyarsk Time, Cambodia, Laos, Thailand, Vietnam|
 +------------+----------------------------------------------------------------+
-| UP11       | (UTC + 11:00) Magadan, New Caledonia, Solomon Islands          |
+| UP8        | (UTC +8:00) Australian Western Standard Time, Beijing Time	  |
 +------------+----------------------------------------------------------------+
-| UP12       | (UTC + 12:00) Auckland, Wellington, Fiji, Marshall Island      |
+| UP875      | (UTC +8:45) Australian Central Western Standard Time		      |
++------------+----------------------------------------------------------------+
+| UP9        | (UTC +9:00) Japan Standard Time, Korea Standard Time, Yakutsk  |
++------------+----------------------------------------------------------------+
+| UP95       | (UTC +9:30) Australian Central Standard Time					  |
++------------+----------------------------------------------------------------+
+| UP10       | (UTC +10:00) Australian Eastern Standard Time, Vladivostok Time|
++------------+----------------------------------------------------------------+
+| UP105      | (UTC +10:30) Lord Howe Island								  |
++------------+----------------------------------------------------------------+
+| UP11       | (UTC +11:00) Magadan Time, Solomon Islands, Vanuatu            |
++------------+----------------------------------------------------------------+
+| UP115      | (UTC +11:30) Norfolk Island									  |
++------------+----------------------------------------------------------------+
+| UP12       | (UTC +12:00) Fiji, Gilbert Islands, Kamchatka, New Zealand     |
++------------+----------------------------------------------------------------+
+| UP1275     | (UTC +12:45) Chatham Islands Standard Time					  |
++------------+----------------------------------------------------------------+
+| UP13       | (UTC +13:00) Phoenix Islands Time, Tonga						  |
++------------+----------------------------------------------------------------+
+| UP14       | (UTC +14:00) Line Islands									  |
 +------------+----------------------------------------------------------------+
diff --git a/user_guide_src/source/helpers/directory_helper.rst b/user_guide_src/source/helpers/directory_helper.rst
index fd16988..cf88732 100644
--- a/user_guide_src/source/helpers/directory_helper.rst
+++ b/user_guide_src/source/helpers/directory_helper.rst
@@ -59,7 +59,7 @@
 				[1] => config.html        
 				[database] => Array
 					(              
-						[0] => active_record.html              
+						[0] => query_builder.html              
 						[1] => binds.html              
 						[2] => configuration.html
 						[3] => connecting.html              
diff --git a/user_guide_src/source/helpers/file_helper.rst b/user_guide_src/source/helpers/file_helper.rst
index bfc271e..60c5aa9 100644
--- a/user_guide_src/source/helpers/file_helper.rst
+++ b/user_guide_src/source/helpers/file_helper.rst
@@ -32,6 +32,9 @@
 	controller or view files. CodeIgniter uses a front controller so paths
 	are always relative to the main site index.
 
+.. note:: This function is DEPRECATED. Use the native ``file_get_contents()``
+	instead.
+
 If your server is running an `open_basedir` restriction this function might not work if you are trying to access a file above the calling script.
 
 write_file('path', $data)
diff --git a/user_guide_src/source/helpers/form_helper.rst b/user_guide_src/source/helpers/form_helper.rst
index 3794e08..a110f3c 100644
--- a/user_guide_src/source/helpers/form_helper.rst
+++ b/user_guide_src/source/helpers/form_helper.rst
@@ -45,7 +45,7 @@
 
 ::
 
-	$attributes = array('class' => 'email', 'id' => 'myform');  
+	$attributes = array('class' => 'email', 'id' => 'myform');
 	echo form_open('email/send', $attributes);
 
 The above example would create a form similar to this
@@ -61,15 +61,15 @@
 
 ::
 
-	 $hidden = array('username' => 'Joe', 'member_id' => '234');  
+	 $hidden = array('username' => 'Joe', 'member_id' => '234');
 	echo form_open('email/send', '', $hidden);
 
 The above example would create a form similar to this
 
 ::
 
-	<form method="post" accept-charset="utf-8" action="http://example.com/index.php/email/send"> 
-		<input type="hidden" name="username" value="Joe" /> 
+	<form method="post" accept-charset="utf-8" action="http://example.com/index.php/email/send">
+		<input type="hidden" name="username" value="Joe" />
 		<input type="hidden" name="member_id" value="234" />
 
 form_open_multipart()
@@ -87,28 +87,67 @@
 
 ::
 
-	form_hidden('username', 'johndoe');  
+	form_hidden('username', 'johndoe');
 	// Would produce: <input type="hidden" name="username" value="johndoe" />
 
 Or you can submit an associative array to create multiple fields
 
 ::
 
-	$data = array(               
-		'name'  => 'John Doe',               
-		'email' => 'john@example.com',               
-		'url'   => 'http://example.com'             
-	);  
-	
-	echo form_hidden($data);  
-	
+	$data = array(
+		'name'  => 'John Doe',
+		'email' => 'john@example.com',
+		'url'   => 'http://example.com'
+	);
+
+	echo form_hidden($data);
+
 	/*
-		Would produce: 
-		<input type="hidden" name="name" value="John Doe" /> 
-		<input type="hidden" name="email" value="john@example.com" /> 
+		Would produce:
+		<input type="hidden" name="name" value="John Doe" />
+		<input type="hidden" name="email" value="john@example.com" />
 		<input type="hidden" name="url" value="http://example.com" />
 	*/
 
+Or pass an associative array to the value field.
+
+::
+
+	$data = array(
+		'name'  => 'John Doe',
+		'email' => 'john@example.com',
+		'url'   => 'http://example.com'
+	);
+
+	echo form_hidden('my_array', $data);
+
+	/*
+		Would produce:
+		<input type="hidden" name="my_array[name]" value="John Doe" />
+		<input type="hidden" name="my_array[email]" value="john@example.com" />
+		<input type="hidden" name="my_array[url]" value="http://example.com" />
+	*/
+
+If you want to create hidden input fields with extra attributes
+
+::
+
+	$data = array(
+		'type'        => 'hidden',
+		'name'        => 'email',
+		'id'          => 'hiddenemail',
+		'value'       => 'john@example.com',
+		'class'       => 'hiddenemail'
+	);
+
+	echo form_input($data);
+
+	/*
+		Would produce:
+
+		<input type="hidden" name="email" value="john@example.com" id="hiddenemail" class="hiddenemail" />
+	*/
+
 form_input()
 ============
 
@@ -124,21 +163,21 @@
 
 ::
 
-	$data = array(               
-		'name'        => 'username',               
-		'id'          => 'username',               
-		'value'       => 'johndoe',               
-		'maxlength'   => '100',               
-		'size'        => '50',               
-		'style'       => 'width:50%',             
-	);  
-	
+	$data = array(
+		'name'        => 'username',
+		'id'          => 'username',
+		'value'       => 'johndoe',
+		'maxlength'   => '100',
+		'size'        => '50',
+		'style'       => 'width:50%'
+	);
+
 	echo form_input($data);
-	
+
 	/*
 		Would produce:
-		
-		<input type="text" name="username" id="username" value="johndoe" maxlength="100" size="50" style="width:50%" />
+
+		<input type="text" name="username" value="johndoe" id="username" maxlength="100" size="50" style="width:50%"  />
 	*/
 
 If you would like your form to contain some additional data, like
@@ -146,7 +185,7 @@
 
 ::
 
-	$js = 'onClick="some_function()"';  
+	$js = 'onClick="some_function()"';
 	echo form_input('username', 'johndoe', $js);
 
 form_password()
@@ -176,37 +215,37 @@
 
 ::
 
-	$options = array(                   
-		'small'  => 'Small Shirt',                   
-		'med'    => 'Medium Shirt',                   
-		'large'   => 'Large Shirt',                   
-		'xlarge' => 'Extra Large Shirt',                 
-	);  
-	
-	$shirts_on_sale = array('small', 'large');  
-	echo form_dropdown('shirts', $options, 'large');  
-	
+	$options = array(
+		'small'  => 'Small Shirt',
+		'med'    => 'Medium Shirt',
+		'large'   => 'Large Shirt',
+		'xlarge' => 'Extra Large Shirt',
+	);
+
+	$shirts_on_sale = array('small', 'large');
+	echo form_dropdown('shirts', $options, 'large');
+
 	/*
-		Would produce:  
-		
-		<select name="shirts"> 
-			<option value="small">Small Shirt</option> 
-			<option value="med">Medium  Shirt</option> 
-			<option value="large" selected="selected">Large Shirt</option> 
-			<option value="xlarge">Extra Large Shirt</option> 
+		Would produce:
+
+		<select name="shirts">
+			<option value="small">Small Shirt</option>
+			<option value="med">Medium  Shirt</option>
+			<option value="large" selected="selected">Large Shirt</option>
+			<option value="xlarge">Extra Large Shirt</option>
 		</select>
 	*/
-	
+
 	echo form_dropdown('shirts', $options, $shirts_on_sale);
-	
+
 	/*
-		Would produce:  
-	
-		<select name="shirts" multiple="multiple"> 
-			<option value="small" selected="selected">Small Shirt</option> 
-			<option value="med">Medium  Shirt</option> 
-			<option value="large" selected="selected">Large Shirt</option> 	
-			<option value="xlarge">Extra Large Shirt</option> 
+		Would produce:
+
+		<select name="shirts" multiple="multiple">
+			<option value="small" selected="selected">Small Shirt</option>
+			<option value="med">Medium  Shirt</option>
+			<option value="large" selected="selected">Large Shirt</option>
+			<option value="xlarge">Extra Large Shirt</option>
 		</select>
 	*/
 
@@ -216,7 +255,7 @@
 
 ::
 
-	$js = 'id="shirts" onChange="some_function();"';  
+	$js = 'id="shirts" onChange="some_function();"';
 	echo form_dropdown('shirts', $options, 'large', $js);
 
 If the array passed as $options is a multidimensional array,
@@ -240,38 +279,38 @@
 
 ::
 
-	echo form_fieldset('Address Information'); 
-	echo "<p>fieldset content here</p>\n"; 
+	echo form_fieldset('Address Information');
+	echo "<p>fieldset content here</p>\n";
 	echo form_fieldset_close();
-	
+
 	/*
 		Produces:
-			<fieldset>  
-				<legend>Address Information</legend>  
-					<p>form content here</p>  
+			<fieldset>
+				<legend>Address Information</legend>
+					<p>form content here</p>
 			</fieldset>
 	*/
-	
+
 Similar to other functions, you can submit an associative array in the
 second parameter if you prefer to set additional attributes.
 
 ::
 
 	$attributes = array(
-		'id' => 'address_info', 
+		'id' => 'address_info',
 		'class' => 'address_info'
-	);     
-	
-	echo form_fieldset('Address Information', $attributes); 
-	echo "<p>fieldset content here</p>\n"; 
-	echo form_fieldset_close();   
-	
+	);
+
+	echo form_fieldset('Address Information', $attributes);
+	echo "<p>fieldset content here</p>\n";
+	echo form_fieldset_close();
+
 	/*
-		Produces: 
-		
-		<fieldset id="address_info" class="address_info">  
-			<legend>Address Information</legend>  
-			<p>form content here</p>  
+		Produces:
+
+		<fieldset id="address_info" class="address_info">
+			<legend>Address Information</legend>
+			<p>form content here</p>
 		</fieldset>
 	*/
 
@@ -284,9 +323,9 @@
 
 ::
 
-	$string = "</div></div>";  
-	echo form_fieldset_close($string);  
-	// Would produce: </fieldset> </div></div>
+	$string = "</div></div>";
+	echo form_fieldset_close($string);
+	// Would produce: </fieldset></div></div>
 
 form_checkbox()
 ===============
@@ -295,7 +334,7 @@
 
 ::
 
-	echo form_checkbox('newsletter', 'accept', TRUE);  
+	echo form_checkbox('newsletter', 'accept', TRUE);
 	// Would produce:  <input type="checkbox" name="newsletter" value="accept" checked="checked" />
 
 The third parameter contains a boolean TRUE/FALSE to determine whether
@@ -306,15 +345,15 @@
 
 ::
 
-	$data = array(     
-		'name'        => 'newsletter',     
-		'id'          => 'newsletter',     
-		'value'       => 'accept',     
-		'checked'     => TRUE,     
-		'style'       => 'margin:10px',     
-	);  
-	
-	echo form_checkbox($data);  
+	$data = array(
+		'name'        => 'newsletter',
+		'id'          => 'newsletter',
+		'value'       => 'accept',
+		'checked'     => TRUE,
+		'style'       => 'margin:10px',
+	);
+
+	echo form_checkbox($data);
 	// Would produce: <input type="checkbox" name="newsletter" id="newsletter" value="accept" checked="checked" style="margin:10px" />
 
 As with other functions, if you would like the tag to contain additional
@@ -323,7 +362,7 @@
 
 ::
 
-	$js = 'onClick="some_function()"';   
+	$js = 'onClick="some_function()"';
 	echo form_checkbox('newsletter', 'accept', TRUE, $js)
 
 form_radio()
@@ -339,7 +378,7 @@
 
 ::
 
-	echo form_submit('mysubmit', 'Submit Post!');  
+	echo form_submit('mysubmit', 'Submit Post!');
 	// Would produce:  <input type="submit" name="mysubmit" value="Submit Post!" />
 
 Similar to other functions, you can submit an associative array in the
@@ -353,7 +392,7 @@
 
 ::
 
-	echo form_label('What is your Name', 'username');  
+	echo form_label('What is your Name', 'username');
 	// Would produce:  <label for="username">What is your Name</label>
 
 Similar to other functions, you can submit an associative array in the
@@ -361,12 +400,12 @@
 
 ::
 
-	$attributes = array(     
-		'class' => 'mycustomclass',     
+	$attributes = array(
+		'class' => 'mycustomclass',
 		'style' => 'color: #000;'
-	);     
-	
-	echo form_label('What is your Name', 'username', $attributes);          
+	);
+
+	echo form_label('What is your Name', 'username', $attributes);
 	// Would produce:  <label for="username" class="mycustomclass" style="color: #000;">What is your Name</label>
 
 
@@ -384,7 +423,7 @@
 
 ::
 
-	 echo form_button('name','content');  
+	 echo form_button('name','content');
 	// Would produce <button name="name" type="button">Content</button>
 
 Or you can pass an associative array containing any data you wish your
@@ -392,15 +431,15 @@
 
 ::
 
-	$data = array(     
-		'name' 		=> 'button',     
-		'id' 		=> 'button',     
-		'value' 	=> 'true',     
-		'type' 		=> 'reset',     
-		'content' 	=> 'Reset' 
-	);  
-	
-	echo form_button($data);  
+	$data = array(
+		'name' 		=> 'button',
+		'id' 		=> 'button',
+		'value' 	=> 'true',
+		'type' 		=> 'reset',
+		'content' 	=> 'Reset'
+	);
+
+	echo form_button($data);
 	// Would produce: <button name="button" id="button" value="true" type="reset">Reset</button>
 
 If you would like your form to contain some additional data, like
@@ -408,7 +447,7 @@
 
 ::
 
-	 $js = 'onClick="some_function()"'; 
+	 $js = 'onClick="some_function()"';
 	echo form_button('mybutton', 'Click Me', $js);
 
 form_close()
@@ -420,8 +459,8 @@
 
 ::
 
-	$string = "</div></div>";  
-	echo form_close($string);  
+	$string = "</div></div>";
+	echo form_close($string);
 	// Would produce:  </form> </div></div>
 
 form_prep()
@@ -432,7 +471,7 @@
 
 ::
 
-	$string = 'Here is a string containing "quoted" text.';  
+	$string = 'Here is a string containing "quoted" text.';
 	<input type="text" name="myform" value="$string" />
 
 Since the above string contains a set of quotes it will cause the form
@@ -475,9 +514,9 @@
 ::
 
 	<select name="myselect">
-		<option value="one" <?php echo  set_select('myselect', 'one', TRUE); ?> >One</option> 
-		<option value="two" <?php echo  set_select('myselect', 'two'); ?> >Two</option> 
-		<option value="three" <?php echo  set_select('myselect', 'three'); ?> >Three</option> 
+		<option value="one" <?php echo  set_select('myselect', 'one', TRUE); ?> >One</option>
+		<option value="two" <?php echo  set_select('myselect', 'two'); ?> >Two</option>
+		<option value="three" <?php echo  set_select('myselect', 'three'); ?> >Three</option>
 	</select>
 
 set_checkbox()
@@ -490,7 +529,7 @@
 
 ::
 
-	<input type="checkbox" name="mycheck" value="1" <?php echo set_checkbox('mycheck', '1'); ?> /> 
+	<input type="checkbox" name="mycheck" value="1" <?php echo set_checkbox('mycheck', '1'); ?> />
 	<input type="checkbox" name="mycheck" value="2" <?php echo set_checkbox('mycheck', '2'); ?> />
 
 set_radio()
@@ -501,6 +540,6 @@
 
 ::
 
-	<input type="radio" name="myradio" value="1" <?php echo  set_radio('myradio', '1', TRUE); ?> /> 
+	<input type="radio" name="myradio" value="1" <?php echo  set_radio('myradio', '1', TRUE); ?> />
 	<input type="radio" name="myradio" value="2" <?php echo  set_radio('myradio', '2'); ?> />
 
diff --git a/user_guide_src/source/helpers/html_helper.rst b/user_guide_src/source/helpers/html_helper.rst
index 2e21789..17c28cd 100644
--- a/user_guide_src/source/helpers/html_helper.rst
+++ b/user_guide_src/source/helpers/html_helper.rst
@@ -325,24 +325,44 @@
 The following is a list of doctype choices. These are configurable, and
 pulled from application/config/doctypes.php
 
-+------------------------+--------------------------+---------------------------------------------------------------------------------------------------------------------------+
-| Doctype                | Option                   | Result                                                                                                                    |
-+========================+==========================+===========================================================================================================================+
-| XHTML 1.1              | doctype('xhtml11')       | <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">                         |
-+------------------------+--------------------------+---------------------------------------------------------------------------------------------------------------------------+
-| XHTML 1.0 Strict       | doctype('xhtml1-strict') | <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">             |
-+------------------------+--------------------------+---------------------------------------------------------------------------------------------------------------------------+
-| XHTML 1.0 Transitional | doctype('xhtml1-trans')  | <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> |
-+------------------------+--------------------------+---------------------------------------------------------------------------------------------------------------------------+
-| XHTML 1.0 Frameset     | doctype('xhtml1-frame')  | <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">         |
-+------------------------+--------------------------+---------------------------------------------------------------------------------------------------------------------------+
-| XHTML Basic 1.1        | doctype('xhtml-basic11') | <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">             |
-+------------------------+--------------------------+---------------------------------------------------------------------------------------------------------------------------+
-| HTML 5                 | doctype('html5')         | <!DOCTYPE html>                                                                                                           |
-+------------------------+--------------------------+---------------------------------------------------------------------------------------------------------------------------+
-| HTML 4 Strict          | doctype('html4-strict')  | <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">                                |
-+------------------------+--------------------------+---------------------------------------------------------------------------------------------------------------------------+
-| HTML 4 Transitional    | doctype('html4-trans')   | <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">                    |
-+------------------------+--------------------------+---------------------------------------------------------------------------------------------------------------------------+
-| HTML 4 Frameset        | doctype('html4-frame')   | <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">                     |
-+------------------------+--------------------------+---------------------------------------------------------------------------------------------------------------------------+
++-------------------------------+------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------+
+| Doctype                       | Option                       | Result                                                                                                                                           |
++===============================+==============================+==================================================================================================================================================+
+| XHTML 1.1                     | doctype('xhtml11')           | <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">                                                |
++-------------------------------+------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------+
+| XHTML 1.0 Strict              | doctype('xhtml1-strict')     | <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">                                    |
++-------------------------------+------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------+
+| XHTML 1.0 Transitional        | doctype('xhtml1-trans')      | <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">                        |
++-------------------------------+------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------+
+| XHTML 1.0 Frameset            | doctype('xhtml1-frame')      | <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">                                |
++-------------------------------+------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------+
+| XHTML Basic 1.1               | doctype('xhtml-basic11')     | <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">                                    |
++-------------------------------+------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------+
+| HTML 5                        | doctype('html5')             | <!DOCTYPE html>                                                                                                                                  |
++-------------------------------+------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------+
+| HTML 4 Strict                 | doctype('html4-strict')      | <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">                                                       |
++-------------------------------+------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------+
+| HTML 4 Transitional           | doctype('html4-trans')       | <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">                                           |
++-------------------------------+------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------+
+| HTML 4 Frameset               | doctype('html4-frame')       | <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">                                            |
++-------------------------------+------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------+
+| MathML 1.01                   | doctype('mathml1')	       | <!DOCTYPE math SYSTEM "http://www.w3.org/Math/DTD/mathml1/mathml.dtd">                                                                           |
++-------------------------------+------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------+
+| MathML 2.0                    | doctype('mathml2')           | <!DOCTYPE math PUBLIC "-//W3C//DTD MathML 2.0//EN" "http://www.w3.org/Math/DTD/mathml2/mathml2.dtd">                                             |
++-------------------------------+------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------+
+| SVG 1.0                       | doctype('svg10')             | <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">                                       |
++-------------------------------+------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------+
+| SVG 1.1 Full                  | doctype('svg11')             | <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">                                               |
++-------------------------------+------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------+
+| SVG 1.1 Basic                 | doctype('svg11-basic')       | <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1 Basic//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11-basic.dtd">                                   |
++-------------------------------+------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------+
+| SVG 1.1 Tiny                  | doctype('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+MathML+SVG (XHTML host) | doctype('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">    |
++-------------------------------+------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------+
+| XHTML+MathML+SVG (SVG host)   | doctype('xhtml-math-svg-sh') | <!DOCTYPE svg:svg 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"> |
++-------------------------------+------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------+
+| XHTML+RDFa 1.0                | doctype('xhtml-rdfa-1')      | <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML+RDFa 1.0//EN" "http://www.w3.org/MarkUp/DTD/xhtml-rdfa-1.dtd">                                          |
++-------------------------------+------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------+
+| XHTML+RDFa 1.1                | doctype('xhtml-rdfa-2')      | <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML+RDFa 1.1//EN" "http://www.w3.org/MarkUp/DTD/xhtml-rdfa-2.dtd">                                          |
++-------------------------------+------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------+
\ No newline at end of file
diff --git a/user_guide_src/source/helpers/path_helper.rst b/user_guide_src/source/helpers/path_helper.rst
index 1a70af4..847f5a0 100644
--- a/user_guide_src/source/helpers/path_helper.rst
+++ b/user_guide_src/source/helpers/path_helper.rst
@@ -28,10 +28,16 @@
 
 ::
 
-	$directory = '/etc/passwd'; 
-	echo set_realpath($directory); // returns "/etc/passwd"  
-	$non_existent_directory = '/path/to/nowhere'; 
-	echo set_realpath($non_existent_directory, TRUE); // returns an error, as the path could not be resolved  
-	echo set_realpath($non_existent_directory, FALSE); // returns "/path/to/nowhere"   
+	$file = '/etc/php5/apache2/php.ini';
+	echo set_realpath($file); // returns "/etc/php5/apache2/php.ini"
 
+	$non_existent_file = '/path/to/non-exist-file.txt';
+	echo set_realpath($non_existent_file, TRUE);	// shows an error, as the path cannot be resolved
+	echo set_realpath($non_existent_file, FALSE);	// returns "/path/to/non-exist-file.txt"
 
+	$directory = '/etc/php5';
+	echo set_realpath($directory);	// returns "/etc/php5/"
+	
+	$non_existent_directory = '/path/to/nowhere';
+	echo set_realpath($non_existent_directory, TRUE);	// shows an error, as the path cannot be resolved
+	echo set_realpath($non_existent_directory, FALSE);	// returns "/path/to/nowhere"
diff --git a/user_guide_src/source/helpers/security_helper.rst b/user_guide_src/source/helpers/security_helper.rst
index 01018c6..ec0be28 100644
--- a/user_guide_src/source/helpers/security_helper.rst
+++ b/user_guide_src/source/helpers/security_helper.rst
@@ -34,16 +34,19 @@
 do_hash()
 =========
 
-Permits you to create SHA1 or MD5 one way hashes suitable for encrypting
-passwords. Will create SHA1 by default. Examples
+Permits you to create one way hashes suitable for encrypting
+passwords. Will create SHA1 by default. See `hash_algos() <http://php.net/function.hash_algos>`_
+for a full list of supported algorithms.
 
 ::
 
 	$str = do_hash($str); // SHA1
 	$str = do_hash($str, 'md5'); // MD5
 
-.. note:: This function was formerly named dohash(), which has been
-	deprecated in favor of `do_hash()`.
+.. note:: This function was formerly named ``dohash()``, which has been
+	removed in favor of ``do_hash()``.
+
+.. note:: This function is DEPRECATED. Use the native ``hash()`` instead.
 
 strip_image_tags()
 ==================
diff --git a/user_guide_src/source/helpers/string_helper.rst b/user_guide_src/source/helpers/string_helper.rst
index dc70e46..19500aa 100644
--- a/user_guide_src/source/helpers/string_helper.rst
+++ b/user_guide_src/source/helpers/string_helper.rst
@@ -36,8 +36,7 @@
 -  **unique**: Encrypted with MD5 and uniqid(). Note: The length
    parameter is not available for this type. Returns a fixed length 32
    character string.
--  **sha1**: An encrypted random number based on do_hash() from the
-   :doc:`security helper <security_helper>`.
+-  **sha1**: An encrypted random number based on ``sha1()``.
 
 Usage example
 
@@ -108,6 +107,36 @@
 	$string = "http://example.com//index.php";
 	echo reduce_double_slashes($string); // results in "http://example.com/index.php"
 
+strip_slashes()
+===============
+
+Removes any slashes from a string. Example
+
+::
+
+	$str = "Is your name O\'reilly?";
+	echo strip_slashes($str); // results in Is your name O'reilly?
+
+You can also use an array. Example
+
+::
+	
+	$str = array(
+		'question'  => 'Is your name O\'reilly?',
+		'answer' => 'No, my name is O\'connor.'
+	);
+	
+	$str = strip_slashes($str);
+	
+The above will return the following array:
+
+::
+
+	array(
+		'question'  => "Is your name O'reilly?",
+		'answer' => "No, my name is O'connor."
+	);
+
 trim_slashes()
 ==============
 
diff --git a/user_guide_src/source/installation/upgrade_200.rst b/user_guide_src/source/installation/upgrade_200.rst
index 0bcbd5c..29f44bd 100644
--- a/user_guide_src/source/installation/upgrade_200.rst
+++ b/user_guide_src/source/installation/upgrade_200.rst
@@ -87,7 +87,14 @@
 convention. Please update extended libraries to call
 parent::\__construct().
 
-Step 8: Update your user guide
+Step 8: Move any core extensions to application/core
+====================================================
+
+Any extensions to core classes (e.g. MY_Controller.php) in your
+application/libraries folder must be moved to the new 
+application/core folder.
+
+Step 9: Update your user guide
 ==============================
 
 Please replace your local copy of the user guide with the new version,
@@ -102,7 +109,7 @@
 details, but here are some of the larger changes that are more likely to
 impact your code:
 
-- CodeIgniter now requires PHP 5.1.6.
+- CodeIgniter now requires PHP 5.2.4.
 - Scaffolding has been removed.
 - The CAPTCHA plugin in now a :doc:`helper </helpers/captcha_helper>`.
 - The JavaScript calendar plugin was removed.
diff --git a/user_guide_src/source/installation/upgrade_300.rst b/user_guide_src/source/installation/upgrade_300.rst
index 4c594ab..63c4227 100644
--- a/user_guide_src/source/installation/upgrade_300.rst
+++ b/user_guide_src/source/installation/upgrade_300.rst
@@ -31,3 +31,18 @@
 
 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: 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
+need to rename the `$active_record` variable to `$query_builder`.
+
+    $active_group = 'default';
+    // $active_record = TRUE;
+    $query_builder = TRUE;
+    
+Step 5: Move your errors folder
+===============================
+
+In version 3.0.0, the errors folder has been moved from "application/errors" to "application/views/errors".
\ No newline at end of file
diff --git a/user_guide_src/source/installation/upgrading.rst b/user_guide_src/source/installation/upgrading.rst
index 2badffc..255c6a5 100644
--- a/user_guide_src/source/installation/upgrading.rst
+++ b/user_guide_src/source/installation/upgrading.rst
@@ -5,7 +5,8 @@
 Please read the upgrade notes corresponding to the version you are
 upgrading from.
 
--  :doc:`Upgrading from 2.0.3 to 2.1.0 <upgrade_210>`
+-  :doc:`Upgrading from 2.1.1 to 3.0.0 <upgrade_300>`
+-  :doc:`Upgrading from 2.1.0 to 2.1.1 <upgrade_211>`
 -  :doc:`Upgrading from 2.0.2 to 2.0.3 <upgrade_203>`
 -  :doc:`Upgrading from 2.0.1 to 2.0.2 <upgrade_202>`
 -  :doc:`Upgrading from 2.0 to 2.0.1 <upgrade_201>`
diff --git a/user_guide_src/source/libraries/config.rst b/user_guide_src/source/libraries/config.rst
index c81cad7..08d9c29 100644
--- a/user_guide_src/source/libraries/config.rst
+++ b/user_guide_src/source/libraries/config.rst
@@ -149,11 +149,13 @@
 -  Your own custom configuration files
 
 .. note::
-	CodeIgniter always tries to load the configuration files for
-	the current environment first. If the file does not exist, the global
-	config file (i.e., the one in application/config/) is loaded. This means
-	you are not obligated to place **all** of your configuration files in an
-	environment folder − only the files that change per environment.
+	CodeIgniter always loads the global config file first (i.e., the one in application/config/),
+	then tries to load the configuration files for the current environment.
+	This means you are not obligated to place **all** of your configuration files in an
+	environment folder. Only the files that change per environment. Additionally you don't
+	have to copy **all** the config items in the environment config file. Only the config items
+	that you wish to change for your environment. The config items declared in your environment
+	folders always overwrite those in your global config files.
 
 Helper Functions
 ================
diff --git a/user_guide_src/source/libraries/email.rst b/user_guide_src/source/libraries/email.rst
index 27b704d..f99eb91 100644
--- a/user_guide_src/source/libraries/email.rst
+++ b/user_guide_src/source/libraries/email.rst
@@ -104,6 +104,7 @@
 **newline**         \\n                    "\\r\\n" or "\\n" or "\\r"   Newline character. (Use "\\r\\n" to comply with RFC 822).
 **bcc_batch_mode**  FALSE                  TRUE or FALSE (boolean)      Enable BCC Batch Mode.
 **bcc_batch_size**  200                    None                         Number of emails in each BCC batch.
+**dsn**             FALSE                  TRUE or FALSE (boolean)      Enable notify message from server
 =================== ====================== ============================ =======================================================================
 
 Email Function Reference
@@ -181,6 +182,14 @@
 accept HTML email. If you do not set your own message CodeIgniter will
 extract the message from your HTML email and strip the tags.
 
+$this->email->set_header()
+-----------------------
+
+Appends additional headers to the e-mail::
+
+	$this->email->set_header('Header1', 'Value1');
+	$this->email->set_header('Header2', 'Value2');
+
 $this->email->clear()
 ---------------------
 
@@ -228,11 +237,20 @@
 	$this->email->attach('/path/to/photo2.jpg');
 	$this->email->attach('/path/to/photo3.jpg');
 
-If you'd like to change the disposition or add a custom file name, you can use the second and third paramaters. To use the default disposition (attachment), leave the second parameter blank. Here's an example::
-  
-	$this->email->attach('/path/to/photo1.jpg', 'inline');
-	$this->email->attach('/path/to/photo1.jpg', '', 'birthday.jpg');
-	
+To use the default disposition (attachment), leave the second parameter blank,
+otherwise use a custom disposition::
+
+	$this->email->attach('image.jpg', 'inline');
+
+If you'd like to use a custom file name, you can use the third paramater::
+
+	$this->email->attach('filename.pdf', 'attachment', 'report.pdf');
+
+If you need to use a buffer string instead of a real - physical - file you can
+use the first parameter as buffer, the third parameter as file name and the fourth
+parameter as mime-type::
+
+	$this->email->attach($buffer, 'attachment', 'report.pdf', 'application/pdf');
 
 $this->email->print_debugger()
 -------------------------------
diff --git a/user_guide_src/source/libraries/file_uploading.rst b/user_guide_src/source/libraries/file_uploading.rst
index 90efca9..414d84f 100644
--- a/user_guide_src/source/libraries/file_uploading.rst
+++ b/user_guide_src/source/libraries/file_uploading.rst
@@ -90,24 +90,24 @@
 
 	class Upload extends CI_Controller {
 
-		function __construct()
+		public function __construct()
 		{
 			parent::__construct();
 			$this->load->helper(array('form', 'url'));
 		}
 
-		function index()
+		public function index()
 		{
 			$this->load->view('upload_form', array('error' => ' ' ));
 		}
 
-		function do_upload()
+		public function do_upload()
 		{
-			$config['upload_path'] = './uploads/';
-			$config['allowed_types'] = 'gif|jpg|png';
-			$config['max_size']	= '100';
-			$config['max_width']  = '1024';
-			$config['max_height']  = '768';
+			$config['upload_path']		= './uploads/';
+			$config['allowed_types']	= 'gif|jpg|png';
+			$config['max_size']		= 100;
+			$config['max_width']		= 1024;
+			$config['max_height']		= 768;
 
 			$this->load->library('upload', $config);
 
@@ -287,6 +287,10 @@
 	    [image_size_str] => width="800" height="200"
 	)
 
+To return one element from the array::
+
+	$this->upload->data('file_name');	// Returns: mypic.jpg
+
 Explanation
 ***********
 
diff --git a/user_guide_src/source/libraries/form_validation.rst b/user_guide_src/source/libraries/form_validation.rst
index e7875bc..3c0e6ed 100644
--- a/user_guide_src/source/libraries/form_validation.rst
+++ b/user_guide_src/source/libraries/form_validation.rst
@@ -123,7 +123,7 @@
 
 	class Form extends CI_Controller {
 
-		function index()
+		public function index()
 		{
 			$this->load->helper(array('form', 'url'));
 
@@ -219,7 +219,7 @@
 
 	class Form extends CI_Controller {
 
-		function index()
+		public function index()
 		{
 			$this->load->helper(array('form', 'url'));
 
@@ -321,7 +321,7 @@
 function, which removes malicious data.
 
 **Any native PHP function that accepts one parameter can be used as a
-rule, like htmlspecialchars, trim, MD5, etc.**
+rule, like htmlspecialchars, trim, md5, etc.**
 
 .. note:: You will generally want to use the prepping functions
 	**after** the validation rules so if there is an error, the original
@@ -523,7 +523,7 @@
 
 By default, the Form Validation class adds a paragraph tag (<p>) around
 each error message shown. You can either change these delimiters
-globally or individually.
+globally, individually, or change the defaults in a config file.
 
 #. **Changing delimiters Globally**
    To globally change the error delimiters, in your controller function,
@@ -543,6 +543,12 @@
 
       <?php echo validation_errors('<div class="error">', '</div>'); ?>
 
+#. **Set delimiters in a config file**
+   You can add your error delimiters in application/config/form_validation.php as follows::
+   
+      $config['error_prefix'] = '<div class="error_prefix">';
+      $config['error_suffix'] = '</div>';
+
 
 Showing Errors Individually
 ===========================
@@ -579,6 +585,29 @@
 
 For more info please see the :ref:`using-arrays-as-field-names` section below.
 
+Validating an Array (other than $_POST)
+=======================================
+
+Sometimes you may want to validate an array that does not originate from $_POST data.
+
+In this case, you can specify the array to be validated::
+	
+	$data = array(
+			'username' => 'johndoe',
+			'password' => 'mypassword',
+		 	'passconf' => 'mypassword'
+		);
+
+	$this->form_validation->set_data($data);
+
+Creating validation rules, running the validation and retrieving error messages works the same whether you are
+validating $_POST data or an array.
+
+**Important Note:** If you want to validate more than one array during a single execution, then you should	
+call the reset_validation() function before setting up rules and validating the new array.
+
+For more info please see the :ref:`function-reference` section below.
+
 .. _saving-groups:
 
 ************************************************
@@ -823,42 +852,50 @@
 The following is a list of all the native rules that are available to
 use:
 
-======================= ========== ============================================================================================= =======================
-Rule                    Parameter  Description                                                                                   Example
-======================= ========== ============================================================================================= =======================
-**required**            No         Returns FALSE if the form element is empty.                                                                          
-**matches**             Yes        Returns FALSE if the form element does not match the one in the parameter.                    matches[form_item]     
-**is_unique**           Yes        Returns FALSE if the form element is not unique to the                                        is_unique[table.field] 
-                                   table and field name in the parameter. is_unique[table.field]                                                        
-**max_length**          Yes        Returns FALSE if the form element is longer then 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 the parameter value or not numeric.            greater_than[8]        
-**less_than**           Yes        Returns FALSE if the form element is greater than the parameter value or not numeric.         less_than[8]           
-**alpha**               No         Returns FALSE if the form element contains anything other than alphabetical characters.                              
-**alpha_numeric**       No         Returns FALSE if the form element contains anything other than alpha-numeric characters.                             
-**alpha_dash**          No         Returns FALSE if the form element contains anything other than alpha-numeric characters,                             
-                                   underscores or dashes.                                                                                               
-**numeric**             No         Returns FALSE if the form element contains anything other than numeric characters.                                   
-**integer**             No         Returns FALSE if the form element contains anything other than an integer.                                           
-**decimal**             Yes        Returns FALSE if the form element is not exactly the parameter value.                                                
-**is_natural**          No         Returns FALSE if the form element contains anything other than a natural number:
-                                   0, 1, 2, 3, etc.
-**is_natural_no_zero**  No         Returns FALSE if the form element contains anything other than a natural
-                                   number, but not zero: 1, 2, 3, etc.
-**is_unique**           Yes        Returns FALSE if the form element is not unique in a database table.                          is_unique[table.field] 
-**valid_email**         No         Returns FALSE if the form element does not contain a valid email address.
-**valid_emails**        No         Returns FALSE if any value provided in a comma separated list is not a valid email.
-**valid_ip**            No         Returns FALSE if the supplied IP is not valid.
-**valid_base64**        No         Returns FALSE if the supplied string contains anything other than valid Base64 characters.
-======================= ========== ============================================================================================= =======================
+========================= ========== ============================================================================================= =======================
+Rule                      Parameter  Description                                                                                   Example
+========================= ========== ============================================================================================= =======================
+**required**              No         Returns FALSE if the form element is empty.                                                                          
+**matches**               Yes        Returns FALSE if the form element does not match the one in the parameter.                    matches[form_item]     
+**is_unique**             Yes        Returns FALSE if the form element is not unique to the                                        is_unique[table.field] 
+                                     table and field name in the parameter. is_unique[table.field]                                                        
+**max_length**            Yes        Returns FALSE if the form element is longer then 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.
+**greater_than_equal_to** Yes        Returns FALSE if the form element is less than the parameter value,                           greater_than_equal_to[8]
+                                     or not numeric.
+**less_than**             Yes        Returns FALSE if the form element is greater than or equal to the parameter value or          less_than[8]
+                                     not numeric.
+**less_than_equal_to**    Yes        Returns FALSE if the form element is greater than the parameter value,                        less_than_equal_to[8]
+                                     or not numeric.
+**alpha**                 No         Returns FALSE if the form element contains anything other than alphabetical characters.                              
+**alpha_numeric**         No         Returns FALSE if the form element contains anything other than alpha-numeric characters.                             
+**alpha_dash**            No         Returns FALSE if the form element contains anything other than alpha-numeric characters,                             
+                                     underscores or dashes.                                                                                               
+**numeric**               No         Returns FALSE if the form element contains anything other than numeric characters.                                   
+**integer**               No         Returns FALSE if the form element contains anything other than an integer.                                           
+**decimal**               No         Returns FALSE if the form element contains anything other than a decimal number.                                     
+**is_natural**            No         Returns FALSE if the form element contains anything other than a natural number:
+                                     0, 1, 2, 3, etc.
+**is_natural_no_zero**    No         Returns FALSE if the form element contains anything other than a natural
+                                     number, but not zero: 1, 2, 3, etc.
+**is_unique**             Yes        Returns FALSE if the form element is not unique in a database table.                          is_unique[table.field] 
+**valid_email**           No         Returns FALSE if the form element does not contain a valid email address.
+**valid_emails**          No         Returns FALSE if any value provided in a comma separated list is not a valid email.
+**valid_ip**              No         Returns FALSE if the supplied IP is not valid.
+                                     Accepts an optional parameter of 'ipv4' or 'ipv6' to specify an IP format.
+**valid_base64**          No         Returns FALSE if the supplied string contains anything other than valid Base64 characters.
+========================= ========== ============================================================================================= =======================
 
 .. note:: These rules can also be called as discrete functions. For
 	example::
 
 		$this->form_validation->required($string);
 
-.. note:: You can also use any native PHP functions that permit one
-	parameter.
+.. note:: You can also use any native PHP functions that permit up
+	to two parameters, where at least one is required (to pass
+	the field data).
 
 ******************
 Prepping Reference
@@ -930,6 +967,33 @@
 
 		Permits you to set custom error messages. See :ref:`setting-error-messages`
 
+$this->form_validation->set_data();
+========================================
+	
+	.. php:method:: set_data ($data = '')
+
+		:param array $data: The data to validate
+
+		Permits you to set an array for validation, instead of using the default
+		$_POST array.
+
+$this->form_validation->reset_validation();
+===========================================
+
+ .. php:method:: reset_validation ()
+
+    Permits you to reset the validation when you validate more than one array.
+	This function should be called before validating each new array.
+
+$this->form_validation->error_array();
+========================================
+	
+	.. php:method:: error_array ()
+
+		:rtype: Array
+
+		Returns the error messages as an array.
+
 .. _helper-functions:
 
 ****************
@@ -1011,4 +1075,3 @@
 
 	<input type="radio" name="myradio" value="1" <?php echo  set_radio('myradio', '1', TRUE); ?> />
 	<input type="radio" name="myradio" value="2" <?php echo  set_radio('myradio', '2'); ?> />
-
diff --git a/user_guide_src/source/libraries/input.rst b/user_guide_src/source/libraries/input.rst
index bcf1173..7f995f0 100644
--- a/user_guide_src/source/libraries/input.rst
+++ b/user_guide_src/source/libraries/input.rst
@@ -18,7 +18,7 @@
 :doc:`controller <../general/controllers>` is invoked. It does the
 following:
 
--  If $config['allow_get_array'] is FALSE(default is TRUE), destroys
+-  If $config['allow_get_array'] is FALSE (default is TRUE), destroys
    the global GET array.
 -  Destroys all global variables in the event register_globals is
    turned on.
@@ -53,14 +53,7 @@
 having to test whether an item exists first. In other words, normally
 you might do something like this::
 
-	if ( ! isset($_POST['something']))
-	{
-	    $something = FALSE;
-	}
-	else
-	{
-	    $something = $_POST['something'];
-	}
+	$something = isset($_POST['something']) ? $_POST['something'] : NULL;
 
 With CodeIgniter's built in functions you can simply do this::
 
@@ -95,11 +88,11 @@
 To return all POST items and pass them through the XSS filter set the
 first parameter NULL while setting the second parameter to boolean;
 
-The function returns FALSE (boolean) if there are no items in the POST.
+The function returns NULL if there are no items in the POST.
 
 ::
 
-	$this->input->post(NULL, TRUE); // returns all POST items with XSS filter 
+	$this->input->post(NULL, TRUE); // returns all POST items with XSS filter
 	$this->input->post(); // returns all POST items without XSS filter
 
 $this->input->get()
@@ -115,13 +108,13 @@
 To return all GET items and pass them through the XSS filter set the
 first parameter NULL while setting the second parameter to boolean;
 
-The function returns FALSE (boolean) if there are no items in the GET.
+The function returns NULL if there are no items in the GET.
 
 ::
 
-	$this->input->get(NULL, TRUE); // returns all GET items with XSS filter 
+	$this->input->get(NULL, TRUE); // returns all GET items with XSS filter
 	$this->input->get(); // returns all GET items without XSS filtering
-	
+
 
 $this->input->get_post()
 =========================
@@ -210,7 +203,7 @@
 
 	cookie('some_cookie');
 
-The function returns FALSE (boolean) if the item you are attempting to
+The function returns NULL if the item you are attempting to
 retrieve does not exist.
 
 The second optional parameter lets you run the data through the XSS
@@ -249,6 +242,9 @@
 	     echo 'Valid';
 	}
 
+Accepts an optional second string parameter of 'ipv4' or 'ipv6' to specify
+an IP format. The default checks for both formats.
+
 $this->input->user_agent()
 ===========================
 
@@ -298,3 +294,13 @@
 
 	$this->input->is_cli_request()
 
+$this->input->method();
+=====================================
+
+Returns the $_SERVER['REQUEST_METHOD'], optional set uppercase or lowercase (default lowercase).
+
+::
+
+	echo $this->input->method(TRUE); // Outputs: POST
+	echo $this->input->method(FALSE); // Outputs: post
+	echo $this->input->method(); // Outputs: post
diff --git a/user_guide_src/source/libraries/javascript.rst b/user_guide_src/source/libraries/javascript.rst
index 5e80fb9..d5e09c3 100644
--- a/user_guide_src/source/libraries/javascript.rst
+++ b/user_guide_src/source/libraries/javascript.rst
@@ -86,14 +86,14 @@
 To initialize the jQuery class manually in your controller constructor,
 use the $this->load->library function::
 
-	$this->load->library('jquery');
+	$this->load->library('javascript/jquery');
 
 You may send an optional parameter to determine whether or not a script
 tag for the main jQuery file will be automatically included when loading
 the library. It will be created by default. To prevent this, load the
 library as follows::
 
-	$this->load->library('jquery', FALSE);
+	$this->load->library('javascript/jquery', FALSE);
 
 Once loaded, the jQuery library object will be available using:
 $this->jquery
diff --git a/user_guide_src/source/libraries/loader.rst b/user_guide_src/source/libraries/loader.rst
index 2090404..aadf974 100644
--- a/user_guide_src/source/libraries/loader.rst
+++ b/user_guide_src/source/libraries/loader.rst
@@ -116,12 +116,12 @@
 
 	$string = $this->load->view('myfile', '', true);
 
-$this->load->model('Model_name');
+$this->load->model('model_name');
 ==================================
 
 ::
 
-	$this->load->model('Model_name');
+	$this->load->model('model_name');
 
 
 If your model is located in a sub-folder, include the relative path from
@@ -134,7 +134,7 @@
 If you would like your model assigned to a different object name you can
 specify it via the second parameter of the loading function::
 
-	$this->load->model('Model_name', 'fubar');
+	$this->load->model('model_name', 'fubar');
 
 	$this->fubar->function();
 
diff --git a/user_guide_src/source/libraries/output.rst b/user_guide_src/source/libraries/output.rst
index 2cf7c08..0472d14 100644
--- a/user_guide_src/source/libraries/output.rst
+++ b/user_guide_src/source/libraries/output.rst
@@ -49,6 +49,19 @@
 .. important:: Make sure any non-mime string you pass to this method
 	exists in config/mimes.php or it will have no effect.
 
+You can also set the character set of the document, by passing a second argument::
+
+	$this->output->set_content_type('css', 'utf-8');
+
+$this->output->get_content_type();
+==========================================
+
+Returns the Content-Type HTTP header that's currently in use.
+
+	$mime = $this->output->get_content_type();
+
+.. note:: If not set, the default return value is 'text/html'.
+
 $this->output->get_output();
 =============================
 
diff --git a/user_guide_src/source/libraries/sessions.rst b/user_guide_src/source/libraries/sessions.rst
index ef32f5d..5400524 100644
--- a/user_guide_src/source/libraries/sessions.rst
+++ b/user_guide_src/source/libraries/sessions.rst
@@ -209,6 +209,10 @@
 To read a flashdata variable::
 
 	$this->session->flashdata('item');
+	
+An array of all flashdata can be retrieved as follows::
+
+	$this->session->all_flashdata();
 
 
 If you find that you need to preserve a flashdata variable through an
@@ -241,7 +245,7 @@
 
 	CREATE TABLE IF NOT EXISTS  `ci_sessions` (
 		session_id varchar(40) DEFAULT '0' NOT NULL,
-		ip_address varchar(16) DEFAULT '0' NOT NULL,
+		ip_address varchar(45) DEFAULT '0' NOT NULL,
 		user_agent varchar(120) NOT NULL,
 		last_activity int(10) unsigned DEFAULT 0 NOT NULL,
 		user_data text NOT NULL,
diff --git a/user_guide_src/source/libraries/table.rst b/user_guide_src/source/libraries/table.rst
index 9bc3f34..6a808ab 100644
--- a/user_guide_src/source/libraries/table.rst
+++ b/user_guide_src/source/libraries/table.rst
@@ -116,6 +116,8 @@
 	$tmpl = array ( 'table_open'  => '<table border="1" cellpadding="2" cellspacing="1" class="mytable">' );
 
 	$this->table->set_template($tmpl);
+	
+You can also set defaults for these in a config file.
 
 ******************
 Function Reference
diff --git a/user_guide_src/source/libraries/uri.rst b/user_guide_src/source/libraries/uri.rst
index ee60b77..bb959b0 100644
--- a/user_guide_src/source/libraries/uri.rst
+++ b/user_guide_src/source/libraries/uri.rst
@@ -25,7 +25,7 @@
 #. metro
 #. crime_is_up
 
-By default the function returns FALSE (boolean) if the segment does not
+By default the function returns NULL if the segment does not
 exist. There is an optional second parameter that permits you to set
 your own default value if the segment is missing. For example, this
 would tell the function to return the number zero in the event of
@@ -146,7 +146,7 @@
 
 The function would return this::
 
-	/news/local/345
+	news/local/345
 
 $this->uri->ruri_string()
 ==========================
diff --git a/user_guide_src/source/libraries/xmlrpc.rst b/user_guide_src/source/libraries/xmlrpc.rst
index 3b94576..dfb8811 100644
--- a/user_guide_src/source/libraries/xmlrpc.rst
+++ b/user_guide_src/source/libraries/xmlrpc.rst
@@ -184,10 +184,10 @@
 
 	class My_blog extends CI_Controller {
 
-	    function new_post($request)
-	    {
+		public function new_post($request)
+		{
 
-	    }
+		}
 	}
 
 The $request variable is an object compiled by the Server, which
@@ -304,7 +304,7 @@
 
 	class Xmlrpc_client extends CI_Controller {
 
-		function index()
+		public function index()
 		{
 			$this->load->helper('url');
 			$server_url = site_url('xmlrpc_server');
@@ -345,7 +345,7 @@
 
 	class Xmlrpc_server extends CI_Controller {
 
-		function index()
+		public function index()
 		{
 			$this->load->library('xmlrpc');
 			$this->load->library('xmlrpcs');
@@ -357,15 +357,17 @@
 		}
 
 
-		function process($request)
+		public function process($request)
 		{
 			$parameters = $request->output_parameters();
 
 			$response = array(
-								array(
-										'you_said'  => $parameters['0'],
-										'i_respond' => 'Not bad at all.'),
-								'struct');
+						array(
+							'you_said'  => $parameters[0],
+							'i_respond' => 'Not bad at all.'
+						),
+						'struct'
+					);
 
 			return $this->xmlrpc->send_response($response);
 		}
@@ -419,9 +421,9 @@
 ::
 
 	$parameters = $request->output_parameters();
-	$name = $parameters['0']['name'];
-	$size = $parameters['1']['size'];
-	$size = $parameters['1']['shape'];
+	$name = $parameters[0]['name'];
+	$size = $parameters[1]['size'];
+	$size = $parameters[1]['shape'];
 
 **************************
 XML-RPC Function Reference
diff --git a/user_guide_src/source/overview/at_a_glance.rst b/user_guide_src/source/overview/at_a_glance.rst
index 31f0b4d..6dcfdbb 100644
--- a/user_guide_src/source/overview/at_a_glance.rst
+++ b/user_guide_src/source/overview/at_a_glance.rst
@@ -41,7 +41,7 @@
 CodeIgniter uses the Model-View-Controller approach, which allows great
 separation between logic and presentation. This is particularly good for
 projects in which designers are working with your template files, as the
-code these file contain will be minimized. We describe MVC in more
+code these files contain will be minimized. We describe MVC in more
 detail on its own page.
 
 CodeIgniter Generates Clean URLs
diff --git a/user_guide_src/source/overview/features.rst b/user_guide_src/source/overview/features.rst
index 44db08a..8c27b14 100644
--- a/user_guide_src/source/overview/features.rst
+++ b/user_guide_src/source/overview/features.rst
@@ -15,7 +15,7 @@
 -  Model-View-Controller Based System
 -  Extremely Light Weight
 -  Full Featured database classes with support for several platforms.
--  Active Record Database Support
+-  Query Builder Database Support
 -  Form and Data Validation
 -  Security and XSS Filtering
 -  Session Management
diff --git a/user_guide_src/source/tutorial/create_news_items.rst b/user_guide_src/source/tutorial/create_news_items.rst
index 794b67e..bfaf135 100644
--- a/user_guide_src/source/tutorial/create_news_items.rst
+++ b/user_guide_src/source/tutorial/create_news_items.rst
@@ -94,7 +94,7 @@
 -----
 
 The only thing that remains is writing a method that writes the data to
-the database. You'll use the Active Record class to insert the
+the database. You'll use the Query Builder class to insert the
 information and use the input library to get the posted data. Open up
 the model created earlier and add the following:
 
diff --git a/user_guide_src/source/tutorial/index.rst b/user_guide_src/source/tutorial/index.rst
index c959d04..b1ab331 100644
--- a/user_guide_src/source/tutorial/index.rst
+++ b/user_guide_src/source/tutorial/index.rst
@@ -16,7 +16,7 @@
 -  Model-View-Controller basics
 -  Routing basics
 -  Form validation
--  Performing basic database queries using "Active Record"
+-  Performing basic database queries using "Query Builder"
 
 The entire tutorial is split up over several pages, each explaining a
 small part of the functionality of the CodeIgniter framework. You'll go
diff --git a/user_guide_src/source/tutorial/news_section.rst b/user_guide_src/source/tutorial/news_section.rst
index 38e4214..82b3e3b 100644
--- a/user_guide_src/source/tutorial/news_section.rst
+++ b/user_guide_src/source/tutorial/news_section.rst
@@ -54,7 +54,7 @@
 Now that the database and a model have been set up, you'll need a method
 to get all of our posts from our database. To do this, the database
 abstraction layer that is included with CodeIgniter — `Active
-Record <../database/active_record.html>`_ — is used. This makes it
+Record <../database/query_builder.html>`_ — is used. This makes it
 possible to write your 'queries' once and make them work on `all
 supported database systems <../general/requirements.html>`_. Add the
 following code to your model.
@@ -76,7 +76,7 @@
 With this code you can perform two different queries. You can get all
 news records, or get a news item by its `slug <#>`_. You might have
 noticed that the $slug variable wasn't sanitized before running the
-query; Active Record does this for you.
+query; Query Builder does this for you.
 
 Display the news
 ----------------