Initial Import
diff --git a/system/libraries/Benchmark.php b/system/libraries/Benchmark.php
new file mode 100644
index 0000000..9dd9d4a
--- /dev/null
+++ b/system/libraries/Benchmark.php
@@ -0,0 +1,117 @@
+<?php  if (!defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * Code Igniter
+ *
+ * An open source application development framework for PHP 4.3.2 or newer
+ *
+ * @package		CodeIgniter
+ * @author		Rick Ellis
+ * @copyright	Copyright (c) 2006, pMachine, Inc.
+ * @license		http://www.codeignitor.com/user_guide/license.html 
+ * @link		http://www.codeigniter.com
+ * @since		Version 1.0
+ * @filesource
+ */
+ 
+// ------------------------------------------------------------------------
+
+/**
+ * Code Igniter Benchmark Class
+ *
+ * This class enables you to mark points and calculate the time difference
+ * between them.  Memory consumption can also be displayed.
+ *
+ * @package		CodeIgniter
+ * @subpackage	Libraries
+ * @category	Libraries
+ * @author		Rick Ellis
+ * @link		http://www.codeigniter.com/user_guide/libraries/benchmark.html
+ */
+class CI_Benchmark {
+
+	var $marker = array();
+
+	/**
+	 * Constructor
+	 *
+	 * @access	public
+	 */
+    function CI_Benchmark()
+    {
+    }
+    // END CI_Benchmark()
+    
+	// --------------------------------------------------------------------
+
+	/**
+	 * Set a benchmark marker
+	 *
+	 * Multiple calls to this function can be made so that several
+	 * execution points can be timed
+	 *
+	 * @access	public
+	 * @param	string	$name	name of the marker
+	 * @return	void
+	 */
+    function mark($name)
+    {
+        $this->marker[$name] = microtime();
+    }
+  	// END mark()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Calculates the time difference between two marked points.
+	 *
+	 * If the first parameter is empty this function instead returns the 
+	 * {elapsed_time} pseudo-variable. This permits the the full system 
+	 * execution time to be shown in a template. The output class will
+	 * swap the real value for this variable.
+	 *
+	 * @access	public
+	 * @param	string	a paricular marked point
+	 * @param	string	a paricular marked point
+	 * @param	integer	the number of decimal places
+	 * @return	mixed
+	 */
+    function elapsed_time($point1 = '', $point2 = '', $decimals = 4)
+    {
+    	if ($point1 == '')
+    	{
+			return '{elapsed_time}';
+    	}
+    	    
+    	if ( ! isset($this->marker[$point2]))
+        	$this->marker[$point2] = microtime();
+        	    
+        list($sm, $ss) = explode(' ', $this->marker[$point1]);
+        list($em, $es) = explode(' ', $this->marker[$point2]);
+                        
+        return number_format(($em + $es) - ($sm + $ss), $decimals);
+    }
+ 	// END elapsed_time()
+ 	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Memory Usage
+	 *
+	 * This function returns the {memory_usage} pseudo-variable.
+	 * This permits it to be put it anywhere in a template 
+	 * without the memory being calculated until the end. 
+	 * The output class will swap the real value for this variable.
+	 *
+	 * @access	public
+	 * @return	string
+	 */
+	function memory_usage()
+	{
+		return '{memory_usage}';
+	}
+	// END memory_usage()
+
+}
+
+// END CI_Benchmark class
+?>
\ No newline at end of file
diff --git a/system/libraries/Calendar.php b/system/libraries/Calendar.php
new file mode 100644
index 0000000..013f067
--- /dev/null
+++ b/system/libraries/Calendar.php
@@ -0,0 +1,473 @@
+<?php  if (!defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * Code Igniter
+ *
+ * An open source application development framework for PHP 4.3.2 or newer
+ *
+ * @package		CodeIgniter
+ * @author		Rick Ellis
+ * @copyright	Copyright (c) 2006, pMachine, Inc.
+ * @license		http://www.codeignitor.com/user_guide/license.html 
+ * @link		http://www.codeigniter.com
+ * @since		Version 1.0
+ * @filesource
+ */
+ 
+// ------------------------------------------------------------------------
+
+/**
+ * Code Igniter Calendar Class
+ *
+ * This class enables the creation of calendars 
+ *
+ * @package		CodeIgniter
+ * @subpackage	Libraries
+ * @category	Libraries
+ * @author		Rick Ellis
+ * @link		http://www.codeigniter.com/user_guide/libraries/calendar.html
+ */
+class CI_Calendar {
+
+	var $lang;
+	var $obj;
+	var $local_time;
+	var $template		= '';
+	var $start_day		= 'sunday';
+	var $month_type 	= 'long';
+	var $day_type		= 'abr';
+	var $show_next_prev	= FALSE;
+	var $next_prev_url	= '';
+
+	/**
+	 * Constructor
+	 *
+	 * Loads the calendar language file and sets the default time reference
+	 *
+	 * @access	public
+	 */
+	function CI_Calendar()
+	{		
+		$this->obj =& get_instance();
+		if ( ! in_array('calendar_lang'.EXT, $this->obj->lang->is_loaded))
+		{
+			$this->obj->lang->load('calendar');
+		}
+
+		$this->local_time = time();
+		log_message('debug', "Calendar Class Initialized");
+	}
+	// END CI_Calendar()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Initialize the user preferences
+	 *
+	 * Accepts an associative array as input, containing display preferences
+	 *
+	 * @access	public
+	 * @param	array	config preferences
+	 * @return	void
+	 */	
+	function initialize($config = array())
+	{
+		foreach ($config as $key => $val)
+		{
+			if (isset($this->$key))
+			{
+				$this->$key = $val;
+			}
+		}
+	} 
+	// END initialize()
+	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Generate the calendar
+	 *
+	 * @access	public
+	 * @param	integer	the year
+	 * @param	integer	the month
+	 * @param	array	the data to be shown in the calendar cells
+	 * @return	string
+	 */
+    function generate($year = '', $month = '', $data = array())
+    {
+		// Set and validate the supplied month/year
+    	if ($year == '')
+    		$year  = date("Y", $this->local_time);
+    		
+    	if ($month == '')
+			$month = date("m", $this->local_time);
+			
+ 		if (strlen($year) == 1)
+			$year = '200'.$year;
+		
+ 		if (strlen($year) == 2)
+			$year = '20'.$year;
+
+ 		if (strlen($month) == 1)
+			$month = '0'.$month;
+		
+		$adjusted_date = $this->adjust_date($month, $year);
+		
+		$month	= $adjusted_date['month'];
+		$year	= $adjusted_date['year'];  
+		
+		// Determine the total days in the month
+		$total_days = $this->get_total_days($month, $year); 
+						
+		// 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];
+		
+		// Set the starting day number
+		$local_date = mktime(12, 0, 0, $month, 1, $year);
+		$date = getdate($local_date);
+		$day  = $start_day + 1 - $date["wday"];
+		
+		while ($day > 1)
+		{
+			$day -= 7;
+		}
+		
+		// Set the current month/year/day
+		// We use this to determine the "today" date
+		$cur_year	= date("Y", $this->local_time);
+		$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;
+	
+		// Generate the template data array
+		$this->parse_template();
+	
+		// Begin building the calendar output						
+		$out = $this->temp['table_open'];
+		$out .= "\n";	
+
+		$out .= "\n";		
+		$out .= $this->temp['heading_row_start'];
+		$out .= "\n";
+		
+		// "previous" month link
+		if ($this->show_next_prev == TRUE)
+		{
+			$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']);
+			$out .= "\n";
+		}
+
+		// Heading containing the month/year
+		$colspan = ($this->show_next_prev == TRUE) ? 5 : 7;
+		
+		$this->temp['heading_title_cell'] = str_replace('{colspan}', $colspan, $this->temp['heading_title_cell']);
+		$this->temp['heading_title_cell'] = str_replace('{heading}', $this->get_month_name($month)."&nbsp;".$year, $this->temp['heading_title_cell']);
+		
+		$out .= $this->temp['heading_title_cell'];
+		$out .= "\n";
+
+		// "next" month link
+		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']);
+		}
+
+		$out .= "\n";		
+		$out .= $this->temp['heading_row_end'];
+		$out .= "\n";
+
+		// Write the cells containing the days of the week
+		$out .= "\n";	
+		$out .= $this->temp['week_row_start'];
+		$out .= "\n";
+
+		$day_names = $this->get_day_names();
+
+		for ($i = 0; $i < 7; $i ++)
+		{
+			$out .= str_replace('{week_day}', $day_names[($start_day + $i) %7], $this->temp['week_day_cell']);
+		}
+
+		$out .= "\n";
+		$out .= $this->temp['week_row_end'];
+		$out .= "\n";
+
+		// Build the main body of the calendar        
+		while ($day <= $total_days)
+		{
+			$out .= "\n";
+			$out .= $this->temp['cal_row_start'];
+			$out .= "\n";
+
+			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'];
+			
+				if ($day > 0 AND $day <= $total_days)
+				{ 					
+					if (isset($data[$day]))
+					{	
+						// Cells with content
+						$temp = ($is_current_month == TRUE AND $day == $cur_day) ? $this->temp['cal_cell_content_today'] : $this->temp['cal_cell_content'];
+						$out .= str_replace('{day}', $day, str_replace('{content}', $data[$day], $temp));
+					}
+					else
+					{
+						// Cells with no content
+						$temp = ($is_current_month == TRUE AND $day == $cur_day) ? $this->temp['cal_cell_no_content_today'] : $this->temp['cal_cell_no_content'];
+						$out .= str_replace('{day}', $day, $temp);
+					}
+				}
+				else
+				{
+					// Blank cells
+					$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'];				      	        
+        	    $day++;
+			}
+			
+			$out .= "\n";    	    
+			$out .= $this->temp['cal_row_end'];
+			$out .= "\n";    	    
+		}
+
+		$out .= "\n";    	
+		$out .= $this->temp['table_close'];
+
+		return $out;
+    }
+	// END generate()
+	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Get Month Name
+	 *
+	 * Generates a texual month name based on the numeric 
+	 * month provided.
+	 *
+	 * @access	public
+	 * @parm	integer	the month
+	 * @return	string
+	 */
+	function get_month_name($month)
+	{
+		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');
+		}
+		else
+		{
+			$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_novermber', '12' => 'cal_december');
+		}
+		
+		$month = $month_names[$month];
+		
+		if ($this->obj->lang->line($month) === FALSE)
+		{
+			return ucfirst(str_replace('cal_', '', $month));
+		}
+
+		return $this->obj->lang->line($month);
+	}
+	// END get_month_name()
+	
+	// --------------------------------------------------------------------
+ 
+	/**
+	 * Get Day Names
+	 *
+	 * Returns an array of day names (Sunday, Monday, etc.) based
+	 * on the type.  Options: long, short, abrev 
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	array
+	 */
+	function get_day_names($day_type = '')
+	{
+		if ($day_type != '')
+			$this->day_type = $day_type;
+	
+		if ($this->day_type == 'long')
+		{
+			$day_names = array('sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday');
+		}
+		elseif ($this->day_type == 'short')
+		{
+			$day_names = array('sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat');
+		}
+		else
+		{
+			$day_names = array('su', 'mo', 'tu', 'we', 'th', 'fr', 'sa');
+		}
+	
+		$days = array();
+		foreach ($day_names as $val)
+		{			
+			$days[] = ($this->obj->lang->line('cal_'.$val) === FALSE) ? ucfirst($val) : $this->obj->lang->line('cal_'.$val);
+		}
+	
+		return $days;
+	}
+ 	// END get_day_names()
+ 	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Adjust Date
+	 *
+	 * This function makes sure that we have a valid month/year.
+	 * 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
+	 * @return	array
+	 */
+    function adjust_date($month, $year)
+    {
+        $date = array(); 
+                
+        $date['month']	= $month;
+        $date['year']	= $year;
+        
+        while ($date['month'] > 12)
+        {
+            $date['month'] -= 12;
+            $date['year']++;
+        }
+        
+        while ($date['month'] <= 0)
+        {
+            $date['month'] += 12;
+            $date['year']--;
+        }
+        
+        if (strlen($date['month']) == 1)
+        {
+        	$date['month'] = '0'.$date['month'];
+        }
+        
+        return $date;
+    }
+ 	// END adjust_date()
+ 	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Total days in a given month
+	 *
+	 * @access	public
+	 * @param	integer	the month
+	 * @param	integer	the year
+	 * @return	integer
+	 */
+    function get_total_days($month, $year)
+    {
+    	$days_in_month	= array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
+    
+        if ($month < 1 OR $month > 12)
+        {
+            return 0;
+        }
+        
+        if ($month == 2)
+        {        
+			if ($year % 400 == 0 OR ($year % 4 == 0 AND $year % 100 != 0))
+			{
+				return 29;
+			}
+        }
+    
+        return $days_in_month[$month - 1];
+    }
+	// END get_total_days()
+	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Set Default Template Data
+	 *
+	 * This is used in the event that the user has not created their own template
+	 *
+	 * @access	public
+	 * @return array
+	 */
+	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>'
+					);	
+	}
+	// END default_template()
+	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Parse Template
+	 *
+	 * Harvests the data within the template {pseudo-variables}
+	 * used to display the calendar
+	 *
+	 * @access	public
+	 * @return	void
+	 */
+ 	function parse_template()
+ 	{
+		$this->temp = $this->default_template();
+ 	
+ 		if ($this->template == '')
+ 		{
+ 			return;
+ 		}
+ 		
+		$today = array('cal_cell_start_today', 'cal_cell_content_today', 'cal_cell_no_content_today', 'cal_cell_end_today');
+		
+		foreach (array('table_open', 'table_close', 'heading_row_start', 'heading_previous_cell', 'heading_title_cell', 'heading_next_cell', 'heading_row_end', 'week_row_start', 'week_day_cell', 'week_row_end', 'cal_row_start', 'cal_cell_start', 'cal_cell_content', 'cal_cell_no_content',  'cal_cell_blank', 'cal_cell_end', 'cal_row_end', 'cal_cell_start_today', 'cal_cell_content_today', 'cal_cell_no_content_today', 'cal_cell_end_today') as $val)
+		{
+			if (preg_match("/\{".$val."\}(.*?)\{\/".$val."\}/si", $this->template, $match))
+			{
+				$this->temp[$val] = $match['1'];
+			}
+			else
+			{
+				if (in_array($val, $today))
+				{
+					$this->temp[$val] = $this->temp[str_replace('_today', '', $val)];
+				}
+			}
+		} 	
+ 	}
+	// END parse_template()
+
+}
+
+// END CI_Calendar class
+?>
\ No newline at end of file
diff --git a/system/libraries/Config.php b/system/libraries/Config.php
new file mode 100644
index 0000000..85b2957
--- /dev/null
+++ b/system/libraries/Config.php
@@ -0,0 +1,181 @@
+<?php  if (!defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * Code Igniter
+ *
+ * An open source application development framework for PHP 4.3.2 or newer
+ *
+ * @package		CodeIgniter
+ * @author		Rick Ellis
+ * @copyright	Copyright (c) 2006, pMachine, Inc.
+ * @license		http://www.codeignitor.com/user_guide/license.html 
+ * @link		http://www.codeigniter.com
+ * @since		Version 1.0
+ * @filesource
+ */
+ 
+// ------------------------------------------------------------------------
+
+/**
+ * Code Igniter Config Class
+ *
+ * This class contains functions that enable config files to be managed
+ *
+ * @package		CodeIgniter
+ * @subpackage	Libraries
+ * @category	Libraries
+ * @author		Rick Ellis
+ * @link		http://www.codeigniter.com/user_guide/libraries/config.html
+ */
+class CI_Config {
+
+	var $config = array();
+	var $is_loaded = array();
+
+	/**
+	 * Constructor
+	 *
+	 * Sets the $config data from the primary config.php file as a class variable
+	 *
+	 * @access	public
+	 */
+	function CI_Config()
+	{
+		$this->config =& _get_config();
+		log_message('debug', "Config Class Initialized");
+	}
+  	// END CI_Config()
+  	
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Load Config File
+	 *
+	 * @access	public
+	 * @param	string	the config file name
+	 * @return	void
+	 */	
+	function load($file = '')
+	{
+		$file = ($file == '') ? 'config' : str_replace(EXT, '', $file);
+	
+		if (in_array($file, $this->is_loaded))
+		{                
+			return;
+		}
+	
+		include_once(APPPATH.'config/'.$file.EXT);
+
+		if ( ! isset($config) OR ! is_array($config))
+		{
+			show_error('Your '.$file.EXT.' file does not appear to contain a valid configuration array.');
+		}
+		
+		$this->config = array_merge($this->config, $config);
+
+		$this->is_loaded[] = $file;
+		unset($config);
+
+		log_message('debug', 'Config file loaded: config/'.$file.EXT);
+	}
+  	// END load()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Fetch a config file item
+	 *
+	 * The second parameter allows a slash to be added to the end of
+	 * the item, in the case of a path.
+	 *
+	 * @access	public
+	 * @param	string	the config item name
+	 * @param	bool
+	 * @return	string
+	 */		
+	function item($item, $slash = FALSE)
+	{
+		if ( ! isset($this->config[$item])) 
+		{
+			return FALSE;
+		}
+		
+		$pref = $this->config[$item];
+		
+		if ($pref == '')
+		{
+			return $pref;
+		}
+			
+        if ($slash !== FALSE AND ereg("/$", $pref) === FALSE)
+        {
+			$pref .= '/';
+        }
+        
+        return $pref;
+	}
+  	// END item()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Site URL
+	 *
+	 * @access	public
+	 * @param	string	the URI string
+	 * @return	string
+	 */		
+	function site_url($uri = '')
+	{
+		if (is_array($uri))
+		{ 
+			$uri = implode('/', $uri);
+		}
+		
+		if ($uri == '')
+		{
+			return $this->item('base_url', 1).$this->item('index_page');
+		}
+		else
+		{
+			$suffix = ($this->item('url_suffix') == FALSE) ? '' : $this->item('url_suffix');		
+			return $this->item('base_url', 1).$this->item('index_page', 1).preg_replace("|^/*(.+?)/*$|", "\\1", $uri).$suffix;
+		}
+	}
+  	// END site_url()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * System URL
+	 *
+	 * @access	public
+	 * @return	string
+	 */		
+	function system_url()
+	{
+		$x = explode("/", preg_replace("|/*(.+?)/*$|", "\\1", BASEPATH));
+		return $this->item('base_url', 1).end($x).'/';
+	}
+  	// END system_url()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Set a config file item
+	 *
+	 * @access	public
+	 * @param	string	the config item key
+	 * @param	string	the config item value
+	 * @return	void
+	 */		
+	function set_item($item, $value)
+	{
+		$this->config[$item] = $value;
+	}
+	// END set_item()
+
+}
+
+// END CI_Config class
+?>
\ No newline at end of file
diff --git a/system/libraries/Controller.php b/system/libraries/Controller.php
new file mode 100644
index 0000000..ec21f8d
--- /dev/null
+++ b/system/libraries/Controller.php
@@ -0,0 +1,445 @@
+<?php  if (!defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * Code Igniter
+ *
+ * An open source application development framework for PHP 4.3.2 or newer
+ *
+ * @package		CodeIgniter
+ * @author		Rick Ellis
+ * @copyright	Copyright (c) 2006, pMachine, Inc.
+ * @license		http://www.codeignitor.com/user_guide/license.html 
+ * @link		http://www.codeigniter.com
+ * @since		Version 1.0
+ * @filesource
+ */
+ 
+// ------------------------------------------------------------------------
+
+/**
+ * Code Igniter Application Controller Class
+ *
+ * This class object is the the super class the every library in 
+ * Code Igniter will be assigned to.
+ *
+ * @package		CodeIgniter
+ * @subpackage	Libraries
+ * @category	Libraries
+ * @author		Rick Ellis
+ * @link		http://www.codeigniter.com/user_guide/general/controllers.html
+ */
+class Controller extends CI_Base {
+
+	var $ci_is_loaded		= array();
+	var $_ci_models			= array();
+	var $_ci_scaffolding	= FALSE;
+	var $_ci_scaff_table	= FALSE;
+	
+	/**
+	 * Constructor
+	 *
+	 * Loads the base classes needed to run CI, and runs the "autoload"
+	 * routine which loads the systems specified in the "autoload" config file.
+	 */
+	function Controller()
+	{	
+		parent::CI_Base();
+		
+		// Assign all the class objects that were instantiated by the
+		// front controller to local class variables so that CI can be 
+		// run as one big super object.
+		$this->_ci_assign_core();
+		
+		// Load everything specified in the autoload.php file
+		$this->load->_ci_autoloader($this->_ci_autoload());
+
+		// This allows anything loaded using $this->load (viwes, files, etc.)
+		// to become accessible from within the Controller class functions.
+		foreach ($this->ci_is_loaded as $val)
+		{
+			$this->load->$val =& $this->$val;
+		}
+			
+		log_message('debug', "Controller Class Initialized");
+	}
+  	// END Controller()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Initialization Handler
+	 *
+	 * Looks for the existence of a handler method and calls it
+	 *
+	 * @access	private
+	 * @param 	string	the item that is being loaded
+	 * @param	mixed	any additional parameters
+	 * @return 	void
+	 */
+	function _ci_initialize($what, $params = FALSE)
+	{		
+		$method = '_ci_init_'.strtolower(str_replace(EXT, '', $what));
+
+		if ( ! method_exists($this, $method))
+		{
+			$method = substr($method, 4);
+		
+			if ( ! file_exists(APPPATH.'init/'.$method.EXT))
+			{
+				if ( ! file_exists(BASEPATH.'init/'.$method.EXT))
+				{
+					log_message('error', "Unable to load the requested class: ".$what);
+					show_error("Unable to load the class: ".$what);
+				}
+				
+				include(BASEPATH.'init/'.$method.EXT);
+			}
+			else
+			{
+				include(APPPATH.'init/'.$method.EXT);
+			}
+		}
+		else
+		{
+			if ($params === FALSE)
+			{
+				$this->$method();
+			}
+			else
+			{
+				$this->$method($params);
+			}
+		}
+	}
+  	// END _ci_initialize()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Loads and instantiates the requested model class
+	 *
+	 * @access	private
+	 * @param	string
+	 * @return	array
+	 */
+	function _ci_load_model($model, $name = '', $db_conn = FALSE)
+	{
+		if ($name == '')
+		{
+			$name = $model;
+		}
+	
+		if (isset($this->$name))
+		{
+			show_error('The model name you are loading is the name of a resource that is already being used: '.$name);
+		}
+	
+		$model = strtolower($model);
+		
+		if ( ! file_exists(APPPATH.'models/'.$model.EXT))
+		{
+			show_error('Unable to locate the model you have specified: '.$model);
+		}
+		
+		if ($db_conn !== FALSE)
+		{
+			if ($db_conn === TRUE)
+				$db_conn = '';
+		
+			$this->_ci_init_database($db_conn, FALSE, TRUE);
+		}
+	
+		if ( ! class_exists('Model'))
+		{
+			require_once(BASEPATH.'libraries/Model'.EXT);
+		}
+
+		require_once(APPPATH.'models/'.$model.EXT);
+
+		$model = ucfirst($model);
+		$this->$name = new $model();
+		$this->_ci_models[] = $name;
+		$this->_ci_assign_to_models();
+	}
+	// END _ci_load_model()
+  	
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Assign to Models
+	 *
+	 * Makes sure that anything loaded by the loader class (libraries, plugins, etc.)
+	 * will be available to modles, if any exist.
+	 *
+	 * @access	public
+	 * @param	object
+	 * @return	array
+	 */
+	function _ci_assign_to_models()
+	{
+		$obj =& get_instance();
+		if (count($obj->_ci_models) == 0)
+		{
+			return;
+		}
+		foreach ($obj->_ci_models as $model)
+		{			
+			$obj->$model->_assign_libraries();			
+		}		
+	}
+	// END _ci_assign_to_models()
+  	
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Auto-initialize Core Classes
+	 *
+	 * This initializes the core systems that are specified in the 
+	 * libraries/autoload.php file, as well as the systems specified in
+	 * the $autoload class array above.
+	 *
+	 * It returns the "autoload" array so we can pass it to the Loader 
+	 * class since it needs to autoload plugins and helper files
+	 *
+	 * The config/autoload.php file contains an array that permits 
+	 * sub-systems to be loaded automatically.
+	 *
+	 * @access	private
+	 * @return	array
+	 */
+	function _ci_autoload()
+	{
+		include_once(APPPATH.'config/autoload'.EXT);
+		
+		if ( ! isset($autoload))
+		{
+			return FALSE;
+		}
+		
+		if (count($autoload['config']) > 0)
+		{
+			foreach ($autoload['config'] as $key => $val)
+			{
+				$this->config->load($val);
+			}
+		}
+		unset($autoload['config']);
+		
+		if ( ! is_array($autoload['core']))
+		{
+			$autoload['core'] = array($autoload['core']);
+		}
+		
+		foreach ($autoload['core'] as $item)
+		{
+			$this->_ci_initialize($item);
+		}
+		
+		return $autoload;
+	}
+  	// END _ci_autoload()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Assign the core classes to the global $CI object
+	 *
+	 * By assigning all the classes instantiated by the front controller
+	 * local class variables we enable everything to be accessible using
+	 * $this->class->function()
+	 *
+	 * @access	private
+	 * @return	void
+	 */
+	function _ci_assign_core()
+	{
+		foreach (array('Config', 'Input', 'Benchmark', 'URI', 'Output') as $val)
+		{
+			$class = strtolower($val);
+			$this->$class =& _load_class('CI_'.$val);
+			$this->ci_is_loaded[] = $class;
+		}
+		
+		$this->lang	=& _load_class('CI_Language');
+		$this->ci_is_loaded[] = 'lang';
+	
+		// In PHP 4 the Controller class is a child of CI_Loader.
+		// In PHP 5 we run it as its own class.
+		if (floor(phpversion()) >= 5)
+		{
+			$this->load = new CI_Loader();
+		}
+		
+		$this->ci_is_loaded[] = 'load';
+	}
+  	// END _ci_assign_core()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Initialize Scaffolding
+	 *
+	 * This initializing function works a bit different than the
+	 * others. It doesn't load the class.  Instead, it simply
+	 * sets a flag indicating that scaffolding is allowed to be
+	 * used.  The actual scaffolding function below is
+	 * called by the front controller based on whether the
+	 * second segment of the URL matches the "secret" scaffolding
+	 * word stored in the application/config/routes.php
+	 *
+	 * @access	private
+	 * @param	string	the table to scaffold
+	 * @return	void
+	 */
+	function _ci_init_scaffolding($table = FALSE)
+	{
+		if ($table === FALSE)
+		{
+			show_error('You must include the name of the table you would like access when you initialize scaffolding');
+		}
+		
+		$this->_ci_scaffolding = TRUE;
+		$this->_ci_scaff_table = $table;
+	}
+  	// END _ci_init_scaffolding()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Initialize Database
+	 *
+	 * @access	private
+	 * @param	mixed	database connection values
+	 * @param	bool	whether to return the object for multiple connections
+	 * @return	void
+	 */
+	function _ci_init_database($params = '', $return = FALSE, $active_record = FALSE)
+	{
+		if ($this->_ci_is_loaded('db') == TRUE AND $return == FALSE AND $active_record == FALSE)
+		{
+			return;
+		}
+	
+		// Load the DB config file if needed
+		if (is_string($params) AND strpos($params, '://') === FALSE)
+		{
+			include(APPPATH.'config/database'.EXT);
+			
+			$group = ($params == '') ? $active_group : $params;
+			
+			if ( ! isset($db[$group]))
+			{
+				show_error('You have specified an invalid database connection group: '.$group);
+			}
+			
+			$params = $db[$group];
+		}
+		
+		// No DB specified yet?  Beat them senseless...
+		if ( ! isset($params['dbdriver']) OR $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
+		// we need to dynamically create a class that extends proper parent class 
+		// based on whether we're using the active record class or not.
+		// Kudos to Paul for discovering this clever use of eval()
+		
+		if ($active_record == TRUE)
+		{
+			$params['active_r'] = TRUE;
+		}
+		
+		require_once(BASEPATH.'drivers/DB_driver'.EXT);
+
+		if ( ! isset($params['active_r']) OR $params['active_r'] == TRUE) 
+		{
+			require_once(BASEPATH.'drivers/DB_active_record'.EXT);
+			
+			if ( ! class_exists('CI_DB'))
+			{
+				eval('class CI_DB extends CI_DB_active_record { }');
+			}
+		}
+		else
+		{
+			if ( ! class_exists('CI_DB'))
+			{
+				eval('class CI_DB extends CI_DB_driver { }');
+			}
+		}
+		
+		require_once(BASEPATH.'drivers/DB_'.$params['dbdriver'].EXT);
+
+		// Instantiate the DB adapter
+		$driver = 'CI_DB_'. $params['dbdriver'];
+		$DB = new $driver($params);
+		
+		if ($return === TRUE)
+		{
+			return $DB;
+		}
+		
+		$obj =& get_instance();
+		$obj->ci_is_loaded[] = 'db';
+		$obj->db =& $DB;
+	}
+  	// END _ci_init_database()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Returns TRUE if a class is loaded, FALSE if not
+	 *
+	 * @access	public
+	 * @param	string	 the class name
+	 * @return	bool
+	 */
+	function _ci_is_loaded($class)
+	{
+		return ( ! in_array($class, $this->ci_is_loaded)) ? FALSE : TRUE;
+	}
+  	// END _ci_is_loaded()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Scaffolding
+	 *
+	 * Initializes the scaffolding.
+	 *
+	 * @access	private
+	 * @return	void
+	 */
+	function _ci_scaffolding()
+	{
+		if ($this->_ci_scaffolding === FALSE OR $this->_ci_scaff_table === FALSE)
+		{
+			show_404('Scaffolding unavailable');
+		}
+		
+		if (class_exists('Scaffolding')) return;
+			
+		if ( ! in_array($this->uri->segment(3), array('add', 'insert', 'edit', 'update', 'view', 'delete', 'do_delete')))
+		{
+			$method = 'view';
+		}
+		else
+		{
+			$method = $this->uri->segment(3);
+		}
+		
+		$this->_ci_init_database("", FALSE, TRUE);
+		
+		$this->_ci_initialize('pagination');
+		require_once(BASEPATH.'scaffolding/Scaffolding'.EXT);
+		$this->scaff = new Scaffolding($this->_ci_scaff_table);
+		$this->scaff->$method();
+	}
+	// END _ci_scaffolding()
+
+}
+// END _Controller class
+?>
\ No newline at end of file
diff --git a/system/libraries/Email.php b/system/libraries/Email.php
new file mode 100644
index 0000000..96dc001
--- /dev/null
+++ b/system/libraries/Email.php
@@ -0,0 +1,1740 @@
+<?php  if (!defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * Code Igniter
+ *
+ * An open source application development framework for PHP 4.3.2 or newer
+ *
+ * @package		CodeIgniter
+ * @author		Rick Ellis
+ * @copyright	Copyright (c) 2006, pMachine, Inc.
+ * @license		http://www.codeignitor.com/user_guide/license.html 
+ * @link		http://www.codeigniter.com
+ * @since		Version 1.0
+ * @filesource
+ */
+ 
+// ------------------------------------------------------------------------
+
+/**
+ * Code Igniter Email Class
+ *
+ * Permits email to be sent using Mail, Sendmail, or SMTP.
+ *
+ * @package		CodeIgniter
+ * @subpackage	Libraries
+ * @category	Libraries
+ * @author		Rick Ellis
+ * @link		http://www.codeigniter.com/user_guide/libraries/email.html
+ */
+class CI_Email {
+
+	var	$useragent		= "Code Igniter";
+	var	$mailpath		= "/usr/sbin/sendmail";	// Sendmail path
+	var	$protocol		= "mail";	// mail/sendmail/smtp
+	var	$smtp_host		= "";		// SMTP Server.  Example: mail.earthlink.net
+	var	$smtp_user		= "";		// SMTP Username
+	var	$smtp_pass		= "";		// SMTP Password
+	var	$smtp_port		= "25";		// SMTP Port
+	var	$smtp_timeout	= 5;		// SMTP Timeout in seconds
+	var	$wordwrap		= TRUE;		// true/false  Turns word-wrap on/off
+	var	$wrapchars		= "76";		// Number of characters to wrap at.
+	var	$mailtype		= "text";	// text/html  Defines email formatting
+	var	$charset		= "utf-8";	// Default char set: iso-8859-1 or us-ascii
+	var	$multipart		= "mixed";	// "mixed" (in the body) or "related" (separate)
+	var $alt_message	= '';		// Alternative message for HTML emails
+	var	$validate		= FALSE;	// true/false.  Enables email validation
+	var	$priority		= "3";		// Default priority (1 - 5)
+	var	$newline		= "\n";		// Default newline. "\r\n" or "\n" (Use "\r\n" to comply with RFC 822)
+	var	$bcc_batch_mode	= FALSE;	// true/false  Turns on/off Bcc batch feature
+	var	$bcc_batch_size	= 200;		// If bcc_batch_mode = true, sets max number of Bccs in each batch
+	var	$_subject		= "";
+	var	$_body			= "";
+	var	$_finalbody		= "";
+	var	$_alt_boundary	= "";
+	var	$_atc_boundary	= "";
+	var	$_header_str	= "";
+	var	$_smtp_connect	= "";
+	var	$_encoding		= "8bit";
+	var $_safe_mode		= FALSE;
+	var $_IP			= FALSE;
+	var	$_smtp_auth		= FALSE;
+	var $_replyto_flag	= FALSE;
+	var	$_debug_msg		= array();
+	var	$_recipients	= array();
+	var	$_cc_array		= array();
+	var	$_bcc_array		= array();
+	var	$_headers		= array();
+	var	$_attach_name	= array();
+	var	$_attach_type	= array();
+	var	$_attach_disp	= array();
+	var	$_protocols		= array('mail', 'sendmail', 'smtp');
+	var	$_base_charsets	= array('iso-8859-1', 'us-ascii');
+	var	$_bit_depths	= array('7bit', '8bit');
+	var	$_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
+	 */	
+	function CI_Email($config = array())
+	{		
+		if (count($config) > 0)
+		{
+			$this->initialize($config);
+		}	
+
+		log_message('debug', "Email Class Initialized");
+	}
+	// END CI_Email()
+  
+	// --------------------------------------------------------------------
+
+	/**
+	 * Initialize preferences
+	 *
+	 * @access	public
+	 * @param	array
+	 * @return	void
+	 */	
+	function initialize($config = array())
+	{
+		$this->clear();
+		foreach ($config as $key => $val)
+		{
+			if (isset($this->$key))
+			{
+				$method = 'set_'.$key;
+				
+				if (method_exists($this, $method))
+				{
+					$this->$method($val);
+				}
+				else
+				{
+					$this->$key = $val;
+				}			
+			}
+		}
+        $this->_smtp_auth = ($this->smtp_user == '' AND $this->smtp_pass == '') ? FALSE : TRUE;			
+		$this->_safe_mode = (@ini_get("safe_mode") == 0) ? FALSE : TRUE;
+	}
+  	// END initialize()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Initialize the Email Data
+	 *
+	 * @access	public
+	 * @return	void
+	 */	
+	function clear()
+	{
+		$this->_subject		= "";
+		$this->_body		= "";
+		$this->_finalbody	= "";
+		$this->_header_str	= "";
+		$this->_replyto_flag = FALSE;
+		$this->_recipients	= array();
+		$this->_headers		= array();
+		$this->_debug_msg	= array();
+		
+		$this->_set_header('User-Agent', $this->useragent);				
+		$this->_set_header('Date', $this->_set_date());
+	}
+  	// END clear()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Set FROM
+	 *
+	 * @access	public
+	 * @param	string
+	 * @param	string
+	 * @return	void
+	 */	
+	function from($from, $name = '')
+	{
+		if (preg_match( '/\<(.*)\>/', $from, $match))
+			$from = $match['1'];
+
+		if ($this->validate)
+			$this->validate_email($this->_str_to_array($from));
+			
+		if ($name != '' && substr($name, 0, 1) != '"')
+		{
+			$name = '"'.$name.'"';
+		}
+	
+		$this->_set_header('From', $name.' <'.$from.'>');
+		$this->_set_header('Return-Path', '<'.$from.'>');
+	}
+  	// END from()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Set Reply-to
+	 *
+	 * @access	public
+	 * @param	string
+	 * @param	string
+	 * @return	void
+	 */	
+	function reply_to($replyto, $name = '')
+	{
+		if (preg_match( '/\<(.*)\>/', $replyto, $match))
+			$replyto = $match['1'];
+
+		if ($this->validate)
+			$this->validate_email($this->_str_to_array($replyto));	
+
+		if ($name == '')
+		{
+			$name = $replyto;
+		}
+
+		if (substr($name, 0, 1) != '"')
+		{
+			$name = '"'.$name.'"';
+		}
+
+		$this->_set_header('Reply-To', $name.' <'.$replyto.'>');
+		$this->_replyto_flag = TRUE;
+	}
+  	// END reply_to()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Set Recipients
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	void
+	 */	
+	function to($to)
+	{
+		$to = $this->_str_to_array($to);
+		$to = $this->clean_email($to);
+	
+		if ($this->validate)
+			$this->validate_email($to);
+			
+		if ($this->_get_protocol() != 'mail')
+			$this->_set_header('To', implode(", ", $to));
+
+		switch ($this->_get_protocol())
+		{
+			case 'smtp'		: $this->_recipients = $to;
+			break;
+			case 'sendmail'	: $this->_recipients = implode(", ", $to);
+			break;
+			case 'mail'		: $this->_recipients = implode(", ", $to);
+			break;
+		}	
+	}
+  	// END to()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Set CC
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	void
+	 */	
+	function cc($cc)
+	{	
+		$cc = $this->_str_to_array($cc);
+		$cc = $this->clean_email($cc);
+
+		if ($this->validate)
+			$this->validate_email($cc);
+
+		$this->_set_header('Cc', implode(", ", $cc));
+		
+		if ($this->_get_protocol() == "smtp")
+			$this->_cc_array = $cc;
+	}
+  	// END cc()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Set BCC
+	 *
+	 * @access	public
+	 * @param	string
+	 * @param	string
+	 * @return	void
+	 */	
+	function bcc($bcc, $limit = '')
+	{
+		if ($limit != '' && ctype_digit($limit))
+		{
+			$this->bcc_batch_mode = true;
+			$this->bcc_batch_size = $limit;
+		}
+
+		$bcc = $this->_str_to_array($bcc);
+		$bcc = $this->clean_email($bcc);
+		
+		if ($this->validate)
+			$this->validate_email($bcc);
+
+		if (($this->_get_protocol() == "smtp") OR ($this->bcc_batch_mode && count($bcc) > $this->bcc_batch_size))
+			$this->_bcc_array = $bcc;
+		else
+			$this->_set_header('Bcc', implode(", ", $bcc));
+	}
+  	// END bcc()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Set Email Subject
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	void
+	 */	
+	function subject($subject)
+	{
+		$subject = preg_replace("/(\r\n)|(\r)|(\n)/", "", $subject);
+		$subject = preg_replace("/(\t)/", " ", $subject);
+		
+		$this->_set_header('Subject', trim($subject));		
+	}
+  	// END subject()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Set Body
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	void
+	 */	
+	function message($body)
+	{
+		$body = rtrim(str_replace("\r", "", $body));
+	
+		if ($this->wordwrap === TRUE  AND  $this->mailtype != 'html')
+			$this->_body = $this->word_wrap($body);
+		else
+			$this->_body = $body;	
+			
+		$this->_body = stripslashes($this->_body);
+	}	
+ 	// END message()
+ 	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Assign file attachments
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	string
+	 */		
+	function attach($filename, $disposition = 'attachment')
+	{			
+		$this->_attach_name[] = $filename;
+		$this->_attach_type[] = $this->_mime_types(next(explode('.', basename($filename))));
+		$this->_attach_disp[] = $disposition; // Can also be 'inline'  Not sure if it matters 
+	}
+  	// END attach()
+  
+	// --------------------------------------------------------------------
+
+	/**
+	 * Add a Header Item
+	 *
+	 * @access	public
+	 * @param	string
+	 * @param	string
+	 * @return	void
+	 */	
+	function _set_header($header, $value)
+	{
+		$this->_headers[$header] = $value;
+	}
+  	// END _set_header()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Convert a String to an Array
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	array
+	 */	
+	function _str_to_array($email)
+	{
+		if ( ! is_array($email))
+		{	
+			if (ereg(',$', $email))
+				$email = substr($email, 0, -1);
+			
+			if (ereg('^,', $email))
+				$email = substr($email, 1);	
+					
+			if (ereg(',', $email))
+			{					
+				$x = explode(',', $email);
+				$email = array();
+				
+				for ($i = 0; $i < count($x); $i ++)
+					$email[] = trim($x[$i]);
+			}
+			else
+			{				
+				$email = trim($email);
+				settype($email, "array");
+			}
+		}
+		return $email;
+	}
+  	// END _str_to_array()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Set Multipart Value
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	void
+	 */	
+	function set_alt_message($str = '')
+	{
+		$this->alt_message = ($str == '') ? '' : $str;
+	}
+  	// END set_alt_message()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Set Mailtype
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	void
+	 */	
+	function set_mailtype($type = 'text')
+	{
+		$this->mailtype = ($type == 'html') ? 'html' : 'text';
+	}
+  	// END set_mailtype()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Set Wordwrap
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	void
+	 */	
+	function set_wordwrap($wordwrap = TRUE)
+	{
+		$this->wordwrap = ($wordwrap === FALSE) ? FALSE : TRUE;
+	}
+  	// END set_wordwrap()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Set Protocal
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	void
+	 */	
+	function set_protocol($protocol = 'mail')
+	{ 
+		$this->protocol = ( ! in_array($protocol, $this->_protocols)) ? 'mail' : strtolower($protocol);
+	}
+  	// END set_protocol()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Set Priority
+	 *
+	 * @access	public
+	 * @param	integer
+	 * @return	void
+	 */	
+	function set_priority($n = 3)
+	{
+		if ( ! ctype_digit($n))
+		{
+			$this->priority = 3;
+			return;
+		}
+	
+		if ($n < 1 OR $n > 5)
+		{
+			$this->priority = 3;
+			return;
+		}
+	
+		$this->priority = $n;
+	}
+  	// END set_priority()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Set Newline Character
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	void
+	 */	
+	function set_newline($newline = "\n")
+	{
+		if ($newline != "\n" OR $newline != "\r\n" OR $newline != "\r")
+		{
+			$this->newline	= "\n";	
+			return;
+		}
+	
+		$this->newline	= $newline;	
+	}
+  	// END set_newline()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Set Message Boundry
+	 *
+	 * @access	private
+	 * @return	void
+	 */	
+	function _set_boundaries()
+	{
+		$this->_alt_boundary = "B_ALT_".uniqid(''); // mulipart/alternative
+		$this->_atc_boundary = "B_ATC_".uniqid(''); // attachment boundary
+	}
+  	// END _set_boundaries()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Get the Message ID
+	 *
+	 * @access	private
+	 * @return	string
+	 */	
+	function _get_message_id()
+	{
+		$from = $this->_headers['Return-Path'];
+		$from = str_replace(">", "", $from);
+		$from = str_replace("<", "", $from);
+	
+        return  "<".uniqid('').strstr($from, '@').">";	        
+	}
+  	// END _get_message_id()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Get Mail Protocol
+	 *
+	 * @access	private
+	 * @param	bool
+	 * @return	string
+	 */	
+	function _get_protocol($return = true)
+	{
+		$this->protocol = strtolower($this->protocol);
+		$this->protocol = ( ! in_array($this->protocol, $this->_protocols)) ? 'mail' : $this->protocol;
+		
+		if ($return == true) 
+			return $this->protocol;
+	}
+  	// END _get_protocol()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Get Mail Encoding
+	 *
+	 * @access	private
+	 * @param	bool
+	 * @return	string
+	 */	
+	function _get_encoding($return = true)
+	{		
+		$this->_encoding = ( ! in_array($this->_encoding, $this->_bit_depths)) ? '7bit' : $this->_encoding;
+		
+		if ( ! in_array($this->charset, $this->_base_charsets)) 
+			$this->_encoding = "8bit";
+			
+		if ($return == true) 
+			return $this->_encoding;
+	}
+	// END _get_encoding()
+  
+	// --------------------------------------------------------------------
+
+	/**
+	 * Get content type (text/html/attachment)
+	 *
+	 * @access	private
+	 * @return	string
+	 */	
+	function _get_content_type()
+	{	
+			if	($this->mailtype == 'html' &&  count($this->_attach_name) == 0)
+				return 'html';
+	
+		elseif	($this->mailtype == 'html' &&  count($this->_attach_name)  > 0)
+				return 'html-attach';				
+				
+		elseif	($this->mailtype == 'text' &&  count($this->_attach_name)  > 0)
+				return 'plain-attach';
+				
+		  else	return 'plain';
+	}
+  	// END _get_content_type()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Set RFC 822 Date
+	 *
+	 * @access	public
+	 * @return	string
+	 */	
+	function _set_date()
+	{
+		$timezone = date("Z");
+		$operator = (substr($timezone, 0, 1) == '-') ? '-' : '+';
+		$timezone = abs($timezone);
+		$timezone = ($timezone/3600) * 100 + ($timezone % 3600) /60;
+		
+		return sprintf("%s %s%04d", date("D, j M Y H:i:s"), $operator, $timezone);
+	}
+  	// END _set_date()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Mime message
+	 *
+	 * @access	private
+	 * @return	string
+	 */	
+	function _get_mime_message()
+	{
+		return "This is a multi-part message in MIME format.".$this->newline."Your email application may not support this format.";
+	}
+  	// END _get_mime_message()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Validate Email Address
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	bool
+	 */	
+	function validate_email($email)
+	{	
+		if ( ! is_array($email))
+		{
+			$this->_set_error_message('email_must_be_array');		
+			return FALSE;
+		}
+
+		foreach ($email as $val)
+		{
+			if ( ! $this->valid_email($val)) 
+			{
+				$this->_set_error_message('email_invalid_address', $val);				
+				return FALSE;
+			}
+		}
+	}	
+  	// END validate_email()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Email Validation
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	bool
+	 */	
+	function valid_email($address)
+	{
+		if ( ! preg_match("/^([a-z0-9\+_\-]+)(\.[a-z0-9\+_\-]+)*@([a-z0-9\-]+\.)+[a-z]{2,6}$/ix", $address))
+			return FALSE;
+		else 
+			return TRUE;
+	}
+  	// END valid_email()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Clean Extended Email Address: Joe Smith <joe@smith.com>
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	string
+	 */	
+	function clean_email($email)
+	{
+		if ( ! is_array($email))
+		{
+			if (preg_match('/\<(.*)\>/', $email, $match))
+           		return $match['1'];
+           	else
+           		return $email;
+		}
+			
+		$clean_email = array();
+
+		for ($i=0; $i < count($email); $i++) 
+		{
+			if (preg_match( '/\<(.*)\>/', $email[$i], $match))
+           		$clean_email[] = $match['1'];
+           	else
+           		$clean_email[] = $email[$i];
+		}
+		
+		return $clean_email;
+	}
+  	// END clean_email()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Build alternative plain text message
+	 *
+	 * This function provides the raw message for use
+	 * in plain-text headers of HTML-formatted emails.
+	 * If the user hasn't specified his own alternative message  
+	 * it creates one by stripping the HTML
+	 *
+	 * @access	private
+	 * @return	string
+	 */	
+	function _get_alt_message()
+	{
+		if (eregi( '\<body(.*)\</body\>', $this->_body, $match))
+		{
+			$body = $match['1'];
+			$body = substr($body, strpos($body, ">") + 1);
+		}
+		else
+		{
+			$body = $this->_body;
+		}
+		
+		$body = trim(strip_tags($body));
+		$body = preg_replace( '#<!--(.*)--\>#', "", $body);
+		$body = str_replace("\t", "", $body);
+		
+		for ($i = 20; $i >= 3; $i--)
+		{
+			$n = "";
+			
+			for ($x = 1; $x <= $i; $x ++)
+				 $n .= "\n";
+		
+			$body = str_replace($n, "\n\n", $body);	
+		}
+
+		return $this->word_wrap($body, '76');
+	}
+  	// END _get_alt_message()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Word Wrap
+	 *
+	 * @access	public
+	 * @param	string
+	 * @param	integer
+	 * @return	string
+	 */	
+	function word_wrap($str, $chars = '')
+	{	
+		if ($chars == '')
+			$chars = ($this->wrapchars == "") ? "76" : $this->wrapchars;
+		
+		$lines = split("\n", $str);
+		
+		$output = "";
+
+		while (list(, $thisline) = each($lines)) 
+		{
+			if (strlen($thisline) > $chars)
+			{
+				$line = "";
+				
+				$words = split(" ", $thisline);
+				
+				while(list(, $thisword) = each($words)) 
+				{
+					while((strlen($thisword)) > $chars) 
+					{
+						if (stristr($thisword, '{unwrap}') !== FALSE OR stristr($thisword, '{/unwrap}') !== FALSE)
+						{
+							break;
+						}
+					
+						$cur_pos = 0;
+						
+						for($i=0; $i < $chars - 1; $i++)
+						{
+							$output .= $thisword[$i];
+							$cur_pos++;
+						}
+						
+						$output .= "\n";
+						
+						$thisword = substr($thisword, $cur_pos, (strlen($thisword) - $cur_pos));
+					}
+					
+					if ((strlen($line) + strlen($thisword)) > $chars) 
+					{
+						$output .= $line."\n";
+						
+						$line = $thisword." ";
+					} 
+					else 
+					{
+						$line .= $thisword." ";
+					}
+				}
+	
+				$output .= $line."\n";
+			} 
+			else 
+			{
+				$output .= $thisline."\n";
+			}
+		}
+
+		return $output;	
+	}
+  	// END word_wrap()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Build final headers
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	string
+	 */	
+	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');
+	}
+  	// END _build_headers()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Write Headers as a string
+	 *
+	 * @access	public
+	 * @return	void
+	 */		
+	function _write_headers()
+	{
+		if ($this->protocol == 'mail')
+		{		
+			$this->_subject = $this->_headers['Subject'];
+			unset($this->_headers['Subject']);
+		}	
+
+		reset($this->_headers);
+		$this->_header_str = "";
+				
+		foreach($this->_headers as $key => $val) 
+		{
+			$val = trim($val);
+		
+			if ($val != "")
+			{
+				$this->_header_str .= $key.": ".$val.$this->newline;
+			}
+		}
+		
+		if ($this->_get_protocol() == 'mail')
+			$this->_header_str = substr($this->_header_str, 0, -1);				
+	}
+  	// END _write_headers()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Build Final Body and attachments
+	 *
+	 * @access	public
+	 * @return	void
+	 */	
+	function _build_message()
+	{
+		$this->_set_boundaries();
+		$this->_write_headers();
+		
+		$hdr = ($this->_get_protocol() == 'mail') ? $this->newline : '';
+			
+		switch ($this->_get_content_type())
+		{
+			case 'plain' :
+							
+				$hdr .= "Content-Type: text/plain; charset=" . $this->charset . $this->newline;
+				$hdr .= "Content-Transfer-Encoding: " . $this->_get_encoding();
+				
+				if ($this->_get_protocol() == 'mail')
+				{
+					$this->_header_str .= $hdr;
+					$this->_finalbody = $this->_body;
+					
+					return;
+				}
+				
+				$hdr .= $this->newline . $this->newline . $this->_body;
+				
+				$this->_finalbody = $hdr;
+				return;
+			
+			break;
+			case 'html' :
+							
+				$hdr .= "Content-Type: multipart/alternative; boundary=\"" . $this->_alt_boundary . "\"" . $this->newline;
+				$hdr .= $this->_get_mime_message() . $this->newline . $this->newline;
+				$hdr .= "--" . $this->_alt_boundary . $this->newline;
+				
+				$hdr .= "Content-Type: text/plain; charset=" . $this->charset . $this->newline;
+				$hdr .= "Content-Transfer-Encoding: " . $this->_get_encoding() . $this->newline . $this->newline;
+				$hdr .= $this->_get_alt_message() . $this->newline . $this->newline . "--" . $this->_alt_boundary . $this->newline;
+			
+				$hdr .= "Content-Type: text/html; charset=" . $this->charset . $this->newline;
+				$hdr .= "Content-Transfer-Encoding: quoted/printable";
+				
+				if ($this->_get_protocol() == 'mail')
+				{
+					$this->_header_str .= $hdr;
+					$this->_finalbody = $this->_body . $this->newline . $this->newline . "--" . $this->_alt_boundary . "--";
+					
+					return;
+				}
+				
+				$hdr .= $this->newline . $this->newline;
+				$hdr .= $this->_body . $this->newline . $this->newline . "--" . $this->_alt_boundary . "--";
+
+				$this->_finalbody = $hdr;
+				return;
+		
+			break;
+			case 'plain-attach' :
+	
+				$hdr .= "Content-Type: multipart/".$this->multipart."; boundary=\"" . $this->_atc_boundary."\"" . $this->newline;
+				$hdr .= $this->_get_mime_message() . $this->newline . $this->newline;
+				$hdr .= "--" . $this->_atc_boundary . $this->newline;
+	
+				$hdr .= "Content-Type: text/plain; charset=" . $this->charset . $this->newline;
+				$hdr .= "Content-Transfer-Encoding: " . $this->_get_encoding();
+				
+				if ($this->_get_protocol() == 'mail')
+				{
+					$this->_header_str .= $hdr;		
+					
+					$body  = $this->_body . $this->newline . $this->newline;
+				}
+				
+				$hdr .= $this->newline . $this->newline;
+				$hdr .= $this->_body . $this->newline . $this->newline;
+
+			break;
+			case 'html-attach' :
+			
+				$hdr .= "Content-Type: multipart/".$this->multipart."; boundary=\"" . $this->_atc_boundary."\"" . $this->newline;
+				$hdr .= $this->_get_mime_message() . $this->newline . $this->newline;
+				$hdr .= "--" . $this->_atc_boundary . $this->newline;
+	
+				$hdr .= "Content-Type: multipart/alternative; boundary=\"" . $this->_alt_boundary . "\"" . $this->newline .$this->newline;
+				$hdr .= "--" . $this->_alt_boundary . $this->newline;
+				
+				$hdr .= "Content-Type: text/plain; charset=" . $this->charset . $this->newline;
+				$hdr .= "Content-Transfer-Encoding: " . $this->_get_encoding() . $this->newline . $this->newline;
+				$hdr .= $this->_get_alt_message() . $this->newline . $this->newline . "--" . $this->_alt_boundary . $this->newline;
+	
+				$hdr .= "Content-Type: text/html; charset=" . $this->charset . $this->newline;
+				$hdr .= "Content-Transfer-Encoding: quoted/printable";
+				
+				if ($this->_get_protocol() == 'mail')
+				{
+					$this->_header_str .= $hdr;	
+					
+					$body  = $this->_body . $this->newline . $this->newline; 
+					$body .= "--" . $this->_alt_boundary . "--" . $this->newline . $this->newline;				
+				}
+				
+				$hdr .= $this->newline . $this->newline;
+				$hdr .= $this->_body . $this->newline . $this->newline;
+				$hdr .= "--" . $this->_alt_boundary . "--" . $this->newline . $this->newline;
+
+			break;
+		}
+
+		$attachment = array();
+
+		$z = 0;
+		
+		for ($i=0; $i < count($this->_attach_name); $i++)
+		{
+			$filename = $this->_attach_name[$i];
+			$basename = basename($filename);
+			$ctype = $this->_attach_type[$i];
+						
+			if ( ! file_exists($filename))
+			{
+				$this->_set_error_message('email_attachment_missing', $filename); 
+				return FALSE;
+			}			
+
+			$h  = "--".$this->_atc_boundary.$this->newline;
+			$h .= "Content-type: ".$ctype."; ";
+			$h .= "name=\"".$basename."\"".$this->newline;
+			$h .= "Content-Disposition: ".$this->_attach_disp[$i].";".$this->newline;
+			$h .= "Content-Transfer-Encoding: base64".$this->newline;
+
+			$attachment[$z++] = $h;
+			$file = filesize($filename) +1;
+			
+			if ( ! $fp = fopen($filename, 'r'))
+			{
+				$this->_set_error_message('email_attachment_unredable', $filename); 
+				return FALSE;
+			}
+			
+			$attachment[$z++] = chunk_split(base64_encode(fread($fp, $file)));				
+			fclose($fp);
+		}
+
+		if ($this->_get_protocol() == 'mail')
+		{
+			$this->_finalbody = $body . implode($this->newline, $attachment).$this->newline."--".$this->_atc_boundary."--";	
+			
+			return;
+		}
+		
+		$this->_finalbody = $hdr.implode($this->newline, $attachment).$this->newline."--".$this->_atc_boundary."--";	
+		
+		return;	
+	}
+  	// END _build_message()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Send Email
+	 *
+	 * @access	public
+	 * @return	bool
+	 */	
+	function send()
+	{			
+		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'])))
+		{
+			$this->_set_error_message('email_no_recipients');					
+			return FALSE;
+		}
+
+		$this->_build_headers();
+		
+		if ($this->bcc_batch_mode  AND  count($this->_bcc_array) > 0)
+		{		
+			if (count($this->_bcc_array) > $this->bcc_batch_size)
+				return $this->batch_bcc_send();
+		}
+		
+		$this->_build_message();
+						
+		if ( ! $this->_spool_email())
+			return FALSE;
+		else
+			return TRUE;
+	}
+  	// END send()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Batch Bcc Send.  Sends groups of Bccs in batches
+	 *
+	 * @access	public
+	 * @return	bool
+	 */	
+	function batch_bcc_send()
+	{
+		$float = $this->bcc_batch_size -1;
+		
+		$flag = 0;
+		$set = "";
+		
+		$chunk = array();		
+		
+		for ($i = 0; $i < count($this->_bcc_array); $i++)
+		{
+			if (isset($this->_bcc_array[$i]))
+				$set .= ", ".$this->_bcc_array[$i];
+		
+			if ($i == $float)
+			{	
+				$chunk[] = substr($set, 1);
+				$float = $float + $this->bcc_batch_size;
+				$set = "";
+			}
+			
+			if ($i == count($this->_bcc_array)-1)
+					$chunk[] = substr($set, 1);	
+		}
+
+		for ($i = 0; $i < count($chunk); $i++)
+		{
+			unset($this->_headers['Bcc']);
+			unset($bcc);
+
+			$bcc = $this->_str_to_array($chunk[$i]);
+			$bcc = $this->clean_email($bcc);
+	
+			if ($this->protocol != 'smtp')
+				$this->_set_header('Bcc', implode(", ", $bcc));
+			else
+				$this->_bcc_array = $bcc;
+			
+			$this->_build_message();
+			$this->_spool_email();		
+		}
+	}
+  	// END batch_bcc_send()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Unwrap special elements
+	 *
+	 * @access	private
+	 * @return	void
+	 */	
+    function _unwrap_specials()
+    {
+        $this->_finalbody = preg_replace_callback("/\{unwrap\}(.*?)\{\/unwrap\}/si", array($this, '_remove_nl_callback'), $this->_finalbody);
+    }
+  	// END _unwrap_specials()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Strip line-breaks via callback
+	 *
+	 * @access	private
+	 * @return	string
+	 */	
+    function _remove_nl_callback($matches)
+    {
+        return preg_replace("/(\r\n)|(\r)|(\n)/", "", $matches['1']);    
+    }
+  	// END _remove_nl_callback()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Spool mail to the mail server
+	 *
+	 * @access	private
+	 * @return	bol
+	 */	
+	function _spool_email()
+	{
+	    $this->_unwrap_specials();
+
+		switch ($this->_get_protocol())
+		{
+			case 'mail'	:
+			
+					if ( ! $this->_send_with_mail())
+					{
+						$this->_set_error_message('email_send_failure_phpmail');							
+						return FALSE;
+					}
+			break;
+			case 'sendmail'	: 
+								
+					if ( ! $this->_send_with_sendmail())
+					{
+						$this->_set_error_message('email_send_failure_sendmail');							
+						return FALSE;
+					}
+			break;
+			case 'smtp'	: 
+								
+					if ( ! $this->_send_with_smtp())
+					{
+						$this->_set_error_message('email_send_failure_smtp');							
+						return FALSE;
+					}
+			break;
+
+		}
+
+		$this->_set_error_message('email_sent', $this->_get_protocol());
+		return true;
+	}	
+  	// END _spool_email()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Send using mail()
+	 *
+	 * @access	private
+	 * @return	bool
+	 */	
+	function _send_with_mail()
+	{	
+		if ($this->_safe_mode == TRUE)
+		{
+			if ( ! mail($this->_recipients, $this->_subject, $this->_finalbody, $this->_header_str))
+				return FALSE;
+			else
+				return TRUE;		
+		}
+		else
+		{
+			if ( ! mail($this->_recipients, $this->_subject, $this->_finalbody, $this->_header_str, "-f".$this->clean_email($this->_headers['From'])))
+				return FALSE;
+			else
+				return TRUE;
+		}
+	}
+  	// END _send_with_mail()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Send using Sendmail
+	 *
+	 * @access	private
+	 * @return	bool
+	 */	
+	function _send_with_sendmail()
+	{
+		$fp = @popen($this->mailpath . " -oi -f ".$this->clean_email($this->_headers['From'])." -t", 'w');
+		
+		if ( ! is_resource($fp))
+		{								
+			$this->_set_error_message('email_no_socket');				
+			return FALSE;
+		}
+		
+		fputs($fp, $this->_header_str);		
+		fputs($fp, $this->_finalbody);
+		pclose($fp) >> 8 & 0xFF;
+		
+		return TRUE;
+	}
+  	// END _send_with_sendmail()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Send using SMTP
+	 *
+	 * @access	private
+	 * @return	bool
+	 */	
+	function _send_with_smtp()
+	{	
+	    if ($this->smtp_host == '')
+	    {	
+			$this->_set_error_message('email_no_hostname');		
+			return FALSE;
+		}
+
+		$this->_smtp_connect();
+		$this->_smtp_authenticate();
+		
+		$this->_send_command('from', $this->clean_email($this->_headers['From']));
+
+		foreach($this->_recipients as $val)
+			$this->_send_command('to', $val);
+			
+		if (count($this->_cc_array) > 0)
+		{
+			foreach($this->_cc_array as $val)
+			{
+				if ($val != "")
+				$this->_send_command('to', $val);
+			}
+		}
+
+		if (count($this->_bcc_array) > 0)
+		{
+			foreach($this->_bcc_array as $val)
+			{
+				if ($val != "")
+				$this->_send_command('to', $val);
+			}
+		}
+		
+		$this->_send_command('data');
+
+		$this->_send_data($this->_header_str . $this->_finalbody);
+		
+		$this->_send_data('.');
+
+		$reply = $this->_get_smtp_data();
+		
+		$this->_set_error_message($reply);			
+
+		if (substr($reply, 0, 3) != '250')
+		{
+			$this->_set_error_message('email_smtp_error', $reply);			
+			return FALSE;
+		}
+
+		$this->_send_command('quit');
+		return true;
+	}	
+  	// END _send_with_smtp()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * SMTP Connect
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	string
+	 */	
+	function _smtp_connect()
+	{
+	
+		$this->_smtp_connect = fsockopen($this->smtp_host, 
+										$this->smtp_port,
+										$errno, 
+										$errstr, 
+										$this->smtp_timeout);
+
+		if( ! is_resource($this->_smtp_connect))
+		{								
+			$this->_set_error_message('email_smtp_error', $errno." ".$errstr);				
+			return FALSE;
+		}
+
+		$this->_set_error_message($this->_get_smtp_data());
+		return $this->_send_command('hello');
+	}
+  	// END _smtp_connect()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Send SMTP command
+	 *
+	 * @access	private
+	 * @param	string
+	 * @param	string
+	 * @return	string
+	 */	
+	function _send_command($cmd, $data = '')
+	{
+		switch ($cmd)
+		{
+			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());
+						
+						$resp = 250;
+			break;
+			case 'from' :
+			
+						$this->_send_data('MAIL FROM:<'.$data.'>');
+
+						$resp = 250;
+			break;
+			case 'to'	:
+			
+						$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>";
+
+		if (substr($reply, 0, 3) != $resp)
+		{
+			$this->_set_error_message('email_smtp_error', $reply);				
+			return FALSE;
+		}
+			
+		if ($cmd == 'quit')
+			fclose($this->_smtp_connect);
+	
+		return true;
+	}
+  	// END _send_command()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 *  SMTP Authenticate
+	 *
+	 * @access	private
+	 * @return	bool
+	 */	
+	function _smtp_authenticate()
+	{	
+		if ( ! $this->_smtp_auth)
+			return true;
+			
+		if ($this->smtp_user == ""  AND  $this->smtp_pass == "")
+		{
+			$this->_set_error_message('email_no_smtp_unpw');
+			return FALSE;
+		}
+
+		$this->_send_data('AUTH LOGIN');
+
+		$reply = $this->_get_smtp_data();			
+
+		if (substr($reply, 0, 3) != '334')
+		{
+			$this->_set_error_message('email_filed_smtp_login', $reply);			
+			return FALSE;
+		}
+
+		$this->_send_data(base64_encode($this->smtp_user));
+
+		$reply = $this->_get_smtp_data();			
+
+		if (substr($reply, 0, 3) != '334')
+		{
+			$this->_set_error_message('email_smtp_auth_un', $reply);			
+			return FALSE;
+		}
+
+		$this->_send_data(base64_encode($this->smtp_pass));
+
+		$reply = $this->_get_smtp_data();			
+
+		if (substr($reply, 0, 3) != '235')
+		{
+			$this->_set_error_message('email_smtp_auth_pw', $reply);			
+			return FALSE;
+		}
+	
+		return true;
+	}
+  	// END _smtp_authenticate()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Send SMTP data
+	 *
+	 * @access	private
+	 * @return	bool
+	 */	
+	function _send_data($data)
+	{
+		if ( ! fwrite($this->_smtp_connect, $data . $this->newline))
+		{
+			$this->_set_error_message('email_smtp_data_failure', $data);			
+			return FALSE;
+		}
+		else
+			return true;
+	}
+  	// END _send_data()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Get SMTP data
+	 *
+	 * @access	private
+	 * @return	string
+	 */	
+	function _get_smtp_data()
+	{
+        $data = "";
+    
+		while ($str = fgets($this->_smtp_connect, 512)) 
+		{            
+			$data .= $str;
+			
+			if (substr($str, 3, 1) == " ")
+				break; 	
+    	}
+    	
+    	return $data;
+	}
+  	// END _get_smtp_data()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Get Hostname
+	 *
+	 * @access	private
+	 * @return	string
+	 */		
+	function _get_hostname()
+	{	
+		return ($this->smtp_host != '') ? $this->smtp_host : $this->_get_ip();		
+	}
+  	// END _get_hostname()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Get IP
+	 *
+	 * @access	private
+	 * @return	string
+	 */		
+	function _get_ip()
+	{
+		if ($this->_IP !== FALSE)
+		{
+			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;
+		$fip = (isset($_SERVER['HTTP_X_FORWARDED_FOR']) AND $_SERVER['HTTP_X_FORWARDED_FOR'] != "") ? $_SERVER['HTTP_X_FORWARDED_FOR'] : FALSE;
+					
+		if ($cip && $rip) 	$this->_IP = $cip;	
+		elseif ($rip)		$this->_IP = $rip;
+		elseif ($cip)		$this->_IP = $cip;
+		elseif ($fip)		$this->_IP = $fip;
+		
+		if (strstr($this->_IP, ','))
+		{
+			$x = explode(',', $this->_IP);
+			$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))
+			$this->_IP = '0.0.0.0';
+		
+		unset($cip);
+		unset($rip);
+		unset($fip);
+		
+		return $this->_IP;
+	}
+  	// END _get_ip()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Get Debugg Message
+	 *
+	 * @access	public
+	 * @return	string
+	 */	
+	function print_debugger()
+	{		
+		$msg = '';
+		
+		if (count($this->_debug_msg) > 0)
+		{
+			foreach ($this->_debug_msg as $val)
+			{
+				$msg .= $val;
+			}
+		}
+		
+		$msg .= "<pre>".$this->_header_str."\n".$this->_subject."\n".$this->_finalbody.'</pre>';	
+		return $msg;
+	}	
+  	// print_debugger()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Set Message
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	string
+	 */	
+	function _set_error_message($msg, $val = '')
+	{
+		$obj =& get_instance();
+		$obj->lang->load('email');
+	
+		if (FALSE === ($line = $obj->lang->line($msg)))
+		{	
+			$this->_debug_msg[] = str_replace('%s', $val, $msg)."<br />";
+		}	
+		else
+		{
+			$this->_debug_msg[] = str_replace('%s', $val, $line)."<br />";
+		}	
+	}
+  	// END _set_error_message()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Mime Types
+	 *
+	 * @access	private
+	 * @param	string
+	 * @return	string
+	 */		
+	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'
+					);
+
+		return ( ! isset($mimes[strtolower($ext)])) ? "application/x-unknown-content-type" : $mimes[strtolower($ext)];
+	}
+	// END _mime_types()
+
+}
+// END CI_Email class
+?>
\ No newline at end of file
diff --git a/system/libraries/Encrypt.php b/system/libraries/Encrypt.php
new file mode 100644
index 0000000..532bfe1
--- /dev/null
+++ b/system/libraries/Encrypt.php
@@ -0,0 +1,378 @@
+<?php  if (!defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * Code Igniter
+ *
+ * An open source application development framework for PHP 4.3.2 or newer
+ *
+ * @package		CodeIgniter
+ * @author		Rick Ellis
+ * @copyright	Copyright (c) 2006, pMachine, Inc.
+ * @license		http://www.codeignitor.com/user_guide/license.html 
+ * @link		http://www.codeigniter.com
+ * @since		Version 1.0
+ * @filesource
+ */
+ 
+// ------------------------------------------------------------------------
+
+/**
+ * Code Igniter Encryption Class
+ *
+ * Provides two-way keyed encoding using XOR Hashing and Mcrypt
+ *
+ * @package		CodeIgniter
+ * @subpackage	Libraries
+ * @category	Libraries
+ * @author		Rick Ellis
+ * @link		http://www.codeigniter.com/user_guide/libraries/encryption.html
+ */
+class CI_Encrypt {
+	var $_hash_type	= 'sha1';
+	var $_mcrypt_exists = FALSE;
+	var $_mcrypt_cipher;
+	var $_mcrypt_mode;
+	
+	/**
+	 * Constructor
+	 *
+	 * Simply determines whether the mcrypt library exists.
+	 *
+	 */
+	function CI_Encrypt()
+	{
+		$this->_mcrypt_exists = ( ! function_exists('mcrypt_encrypt')) ? FALSE : TRUE;
+		log_message('debug', "Encrypt Class Initialized");
+	}
+  	// END CI_Encrypt()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Fetch the encryption key
+	 *
+	 * Returns it as MD5 in order to have an exact-length 128 bit key.
+	 * Mcrypt is sensitive to keys that are not the correct length
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	string
+	 */
+	function get_key($key = '')
+	{
+		if ($key == '')
+		{	
+			$obj =& get_instance();
+			$key = $obj->config->item('encryption_key');
+
+			if ($key === FALSE)
+			{
+				show_error('In order to use the encryption class requires that you set an encryption key in your config file.');
+			}
+		}
+		
+		return md5($key);
+	}
+  	// END get_key()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Encode
+	 *
+	 * Encodes the message string using bitwise XOR encoding.  
+	 * The key is combined with a random hash, and then it 
+	 * too gets converted using XOR. The whole thing is then run 
+	 * through mcrypt (if supported) using the randomized key.  
+	 * The end result is a double-encrypted message string 
+	 * that is randomized with each call to this function, 
+	 * even if the supplied message and key are the same.
+	 *
+	 * @access	public
+	 * @param	string	the string to encode
+	 * @param	string	the key
+	 * @return	string
+	 */
+	function encode($string, $key = '')
+	{
+		$key = $this->get_key($key);
+		$enc = $this->_xor_encode($string, $key);
+		
+		if ($this->_mcrypt_exists === TRUE)
+		{
+			$enc = $this->mcrypt_encode($enc, $key);
+		}
+		return base64_encode($enc);		
+	}
+  	// END encode()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Decode
+	 *
+	 * Reverses the above process
+	 *
+	 * @access	public
+	 * @param	string
+	 * @param	string
+	 * @return	string
+	 */
+	function decode($string, $key = '')
+	{
+		$key = $this->get_key($key);
+		$dec = base64_decode($string);
+		
+		 if ($dec === FALSE)
+		 {
+		 	return FALSE;
+		 }
+		
+		if ($this->_mcrypt_exists === TRUE)
+		{
+			$dec = $this->mcrypt_decode($dec, $key);
+		}
+		
+		return $this->_xor_decode($dec, $key);
+	}
+  	// END decode()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * XOR Encode
+	 *
+	 * Takes a plain-text string and key as input and generates an
+	 * encoded bit-string using XOR
+	 *
+	 * @access	private
+	 * @param	string
+	 * @param	string
+	 * @return	string
+	 */	
+	function _xor_encode($string, $key)
+	{
+		$rand = '';
+		while (strlen($rand) < 32) 
+		{    
+			$rand .= mt_rand(0, mt_getrandmax());
+		}
+	
+		$rand = $this->hash($rand);
+		
+		$enc = '';
+		for ($i = 0; $i < strlen($string); $i++)
+		{			
+			$enc .= substr($rand, ($i % strlen($rand)), 1).(substr($rand, ($i % strlen($rand)), 1) ^ substr($string, $i, 1));
+		}
+				
+		return $this->_xor_merge($enc, $key);
+	}
+  	// END _xor_encode()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * XOR Decode
+	 *
+	 * Takes an encoded string and key as input and generates the 
+	 * plain-text original message
+	 *
+	 * @access	private
+	 * @param	string
+	 * @param	string
+	 * @return	string
+	 */	
+	function _xor_decode($string, $key)
+	{
+		$string = $this->_xor_merge($string, $key);
+		
+		$dec = '';
+		for ($i = 0; $i < strlen($string); $i++)
+		{
+			$dec .= (substr($string, $i++, 1) ^ substr($string, $i, 1));
+		}
+	
+		return $dec;
+	}
+  	// END _xor_decode()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * XOR key + string Combiner
+	 *
+	 * Takes a string and key as input and computes the difference using XOR
+	 *
+	 * @access	private
+	 * @param	string
+	 * @param	string
+	 * @return	string
+	 */	
+	function _xor_merge($string, $key)
+	{
+		$hash = $this->hash($key);
+		$str = '';
+		for ($i = 0; $i < strlen($string); $i++)
+		{
+			$str .= substr($string, $i, 1) ^ substr($hash, ($i % strlen($hash)), 1);
+		}
+		
+		return $str;
+	}
+  	// END _xor_merge()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Encrypt using Mcrypt
+	 *
+	 * @access	public
+	 * @param	string
+	 * @param	string
+	 * @return	string
+	 */
+	function mcrypt_encode($data, $key) 
+	{	
+		$this->_get_mcrypt();
+		$init_size = mcrypt_get_iv_size($this->_mcrypt_cipher, $this->_mcrypt_mode);
+		$init_vect = mcrypt_create_iv($init_size, MCRYPT_RAND);
+		return mcrypt_encrypt($this->_mcrypt_cipher, $key, $data, $this->_mcrypt_mode, $init_vect);
+	}
+  	// END mcrypt_encode()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Decrypt using Mcrypt
+	 *
+	 * @access	public
+	 * @param	string
+	 * @param	string
+	 * @return	string
+	 */	
+	function mcrypt_decode($data, $key) 
+	{
+		$this->_get_mcrypt();
+		$init_size = mcrypt_get_iv_size($this->_mcrypt_cipher, $this->_mcrypt_mode);
+		$init_vect = mcrypt_create_iv($init_size, MCRYPT_RAND);
+		return rtrim(mcrypt_decrypt($this->_mcrypt_cipher, $key, $data, $this->_mcrypt_mode, $init_vect), "\0");
+	}
+  	// END mcrypt_decode()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Set the Mcrypt Cypher
+	 *
+	 * @access	public
+	 * @param	constant
+	 * @return	string
+	 */
+	function set_cypher($cypher)
+	{
+		$this->_mcrypt_cipher = $cypher;
+	}
+  	// END set_cypher()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Set the Mcrypt Mode
+	 *
+	 * @access	public
+	 * @param	constant
+	 * @return	string
+	 */
+	function set_mode($mode)
+	{
+		$this->_mcrypt_mode = $mode;
+	}
+  	// END set_mode()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Get Mcrypt value
+	 *
+	 * @access	private
+	 * @param	string
+	 * @return	string
+	 */	
+	function _get_mcrypt()
+	{
+		if ($this->_mcrypt_cipher == '') 
+		{
+			$this->_mcrypt_cipher = MCRYPT_RIJNDAEL_256;
+		}
+		if ($this->_mcrypt_mode == '') 
+		{
+			$this->_mcrypt_mode = MCRYPT_MODE_ECB;
+		}
+	}
+  	// END _get_mcrypt()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Set the Hash type
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	string
+	 */		
+	function set_hash($type = 'sha1')
+	{
+		$this->_hash_type = ($type != 'sha1' OR $type != 'md5') ? 'sha1' : $type;
+	}
+  	// END set_hash()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Hash encode a string
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	string
+	 */		
+	function hash($str)
+	{
+		return ($this->_hash_type == 'sha1') ? $this->sha1($str) : md5($str);
+	}
+  	// END hash()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Generate an SHA1 Hash
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	string
+	 */	
+	function sha1($str)
+	{
+		if ( ! function_exists('sha1'))
+		{
+			if ( ! function_exists('mhash'))
+			{	
+				require_once(BASEPATH.'libraries/Sha1'.EXT);
+				$SH = new CI_SHA;
+				return $SH->generate($str);            
+			}
+			else
+			{
+				return bin2hex(mhash(MHASH_SHA1, $str));
+			}
+		}
+		else
+		{
+			return sha1($str);
+		}	
+	}  
+	// END sha1()
+	
+}
+
+// END CI_Encrypt class
+?>
\ No newline at end of file
diff --git a/system/libraries/Exceptions.php b/system/libraries/Exceptions.php
new file mode 100644
index 0000000..a72dbf8
--- /dev/null
+++ b/system/libraries/Exceptions.php
@@ -0,0 +1,165 @@
+<?php  if (!defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * Code Igniter
+ *
+ * An open source application development framework for PHP 4.3.2 or newer
+ *
+ * @package		CodeIgniter
+ * @author		Rick Ellis
+ * @copyright	Copyright (c) 2006, pMachine, Inc.
+ * @license		http://www.codeignitor.com/user_guide/license.html 
+ * @link		http://www.codeigniter.com
+ * @since		Version 1.0
+ * @filesource
+ */
+ 
+// ------------------------------------------------------------------------
+
+/**
+ * Exceptions Class
+ * 
+ * @package		CodeIgniter
+ * @subpackage	Libraries
+ * @category	Exceptions
+ * @author		Rick Ellis
+ * @link		http://www.codeigniter.com/user_guide/libraries/exceptions.html
+ */
+class CI_Exceptions {
+	var $action;
+	var $severity;
+	var $message;
+	var $filename;
+	var $line;
+
+	var $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'
+					);
+
+
+	/**
+	 * Constructor 
+	 *
+	 */	
+	function CI_Exceptions()
+	{
+		log_message('debug', "Output Class Initialized");
+	}
+  	// END CI_Exceptions()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Exception Logger
+	 *
+	 * This function logs PHP generated error messages
+	 *
+	 * @access	private
+	 * @param	string	the error severity
+	 * @param	string	the error string
+	 * @param	string	the error filepath
+	 * @param	string	the error line number
+	 * @return	string
+	 */
+	function log_exception($severity, $message, $filepath, $line)
+	{	
+		$severity = ( ! isset($this->levels[$severity])) ? $severity : $this->levels[$severity];
+		
+		log_message('error', 'Severity: '.$severity.' '.$severity.' --> '.$message. ' '.$filepath.' '.$line, TRUE);
+	}
+	// END log_exception()
+  
+	// --------------------------------------------------------------------
+
+	/**
+	 * 404 Page Not Found Handler
+	 *
+	 * @access	private
+	 * @param	string
+	 * @return	string
+	 */
+	function show_404($page = '')
+	{	
+		$heading = "404 Page Not Found";
+		$message = "The page you requested was not found."; 
+
+		log_message('error', '404 Page Not Found --> '.$page);
+		echo $this->show_error($heading, $message, 'error_404');
+		exit;
+	}
+  	// END show_404()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * General Error Page
+	 *
+	 * This function takes an error message as input
+	 * (either as a string or an array) and displayes
+	 * it using the specified template.
+	 *
+	 * @access	private
+	 * @param	string	the heading
+	 * @param	string	the message
+	 * @param	string	the template name
+	 * @return	string
+	 */
+	function show_error($heading, $message, $template = 'error_general')
+	{
+		$message = '<p>'.implode('</p><p>', ( ! is_array($message)) ? array($message) : $message).'</p>';
+				
+		ob_start();
+		include_once(APPPATH.'errors/'.$template.EXT);
+		$buffer = ob_get_contents();
+		ob_end_clean();
+		return $buffer;
+	}
+	// END show_error()
+
+  
+	// --------------------------------------------------------------------
+
+	/**
+	 * Native PHP error handler
+	 *
+	 * @access	private
+	 * @param	string	the error severity
+	 * @param	string	the error string
+	 * @param	string	the error filepath
+	 * @param	string	the error line number
+	 * @return	string
+	 */
+	function show_php_error($severity, $message, $filepath, $line)
+	{	
+		$severity = ( ! isset($this->levels[$severity])) ? $severity : $this->levels[$severity];
+	
+		$filepath = str_replace("\\", "/", $filepath);
+		
+		// For safety reasons we do not show the full file path
+		if (FALSE !== strpos($filepath, '/'))
+		{
+			$x = explode('/', $filepath);
+			$filepath = $x[count($x)-2].'/'.end($x);
+		}
+	
+		ob_start();
+		include_once(APPPATH.'errors/error_php'.EXT);
+		$buffer = ob_get_contents();
+		ob_end_clean();
+		echo $buffer;
+	}
+  	// END show_php_error()
+
+// END Exceptions Class
+}
+?>
\ No newline at end of file
diff --git a/system/libraries/Hooks.php b/system/libraries/Hooks.php
new file mode 100644
index 0000000..389e7ac
--- /dev/null
+++ b/system/libraries/Hooks.php
@@ -0,0 +1,237 @@
+<?php  if (!defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * Code Igniter
+ *
+ * An open source application development framework for PHP 4.3.2 or newer
+ *
+ * @package		CodeIgniter
+ * @author		Rick Ellis
+ * @copyright	Copyright (c) 2006, pMachine, Inc.
+ * @license		http://www.codeignitor.com/user_guide/license.html 
+ * @link		http://www.codeigniter.com
+ * @since		Version 1.0
+ * @filesource
+ */
+ 
+// ------------------------------------------------------------------------
+
+/**
+ * Code Igniter Hooks Class
+ *
+ * Provides a mechanism to extend the base system without hacking.  Most of
+ * this class is borrowed from Paul's Extension class in ExpressionEngine.
+ *
+ * @package		CodeIgniter
+ * @subpackage	Libraries
+ * @category	Libraries
+ * @author		Rick Ellis
+ * @link		http://www.codeigniter.com/user_guide/libraries/encryption.html
+ */
+class CI_Hooks {
+	
+	var $enabled 		= FALSE;
+	var $hooks   		= array();
+	var $in_progress	= FALSE;
+	
+	/**
+	 * Constructor
+	 *
+	 */
+	function CI_Hooks()
+	{
+		log_message('debug', "Hooks Class Initialized");
+	
+		$CFG =& _load_class('CI_Config');
+		
+		// If hooks are not enabled in the config file
+		// there is nothing else to do
+		
+		if ($CFG->item('enable_hooks') == FALSE)
+		{
+			return;
+		}
+		
+		// Grab the "hooks" definition file.
+		// If there are no hooks, we're done.
+		
+		@include(APPPATH.'config/hooks'.EXT);
+		
+		if ( ! isset($hook) OR ! is_array($hook))
+		{
+			return;
+		}
+
+		$this->hooks =& $hook;
+		$this->enabled = TRUE;
+	}
+  	// END CI_Hooks()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Does a given hook exist?
+	 *
+	 * Returns TRUE/FALSE based on whether a given hook exists
+	 *
+	 * @access	private
+	 * @param	string
+	 * @return	bool
+	 */
+	function _hook_exists($which = '')
+	{
+		if ( ! $this->enabled)
+		{
+			return FALSE;
+		}
+
+		if ( ! isset($this->hooks[$which]))
+		{
+			return FALSE;
+		}
+
+		return TRUE;
+	}
+  	// END hook_exists()
+  	
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Call Hook
+	 *
+	 * Calls a particular hook
+	 *
+	 * @access	private
+	 * @param	string	the hook name
+	 * @return	mixed
+	 */
+	function _call_hook($which = '')
+	{
+		if (isset($this->hooks[$which][0]) AND is_array($this->hooks[$which][0]))
+		{
+			foreach ($this->hooks[$which] as $val)
+			{
+				$this->_run_hook($val);
+			}
+		}
+		else
+		{
+			$this->_run_hook($this->hooks[$which]);
+		}
+	}
+  	// END hook_exists()
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Run Hook
+	 *
+	 * Runs a particular hook
+	 *
+	 * @access	private
+	 * @param	array	the hook details
+	 * @return	bool
+	 */
+	function _run_hook($data)
+	{
+		if ( ! is_array($data))
+		{
+			return FALSE;
+		}
+		
+		// -----------------------------------
+		// Safety - Prevents run-away loops
+		// -----------------------------------
+	
+		// If the script being called happens to have the same 
+		// extension call within it a loop can happen
+		
+		if ($this->in_progress == TRUE)
+		{
+			return;
+		}
+
+		// -----------------------------------
+		// Set file path
+		// -----------------------------------
+		
+		if ( ! isset($data['filepath']) OR ! isset($data['filename']))
+		{
+			return FALSE;
+		}
+		
+		$filepath = APPPATH.$data['filepath'].'/'.$data['filename'];
+	
+		if ( ! file_exists($filepath))
+		{
+			return FALSE;
+		}
+		
+		// -----------------------------------
+		// Set class/function name
+		// -----------------------------------
+		
+		$class		= FALSE;
+		$function	= FALSE;
+		$params		= '';
+		
+		if (isset($data['class']) AND $data['class'] != '') 
+		{
+			$class = $data['class'];
+		}
+
+		if (isset($data['function'])) 
+		{
+			$function = $data['function'];
+		}
+
+		if (isset($data['params'])) 
+		{
+			$params = $data['params'];
+		}
+		
+		if ($class === FALSE AND $function === FALSE)
+		{
+			return FALSE;
+		}
+		
+		// -----------------------------------
+		// Set the in_progress flag
+		// -----------------------------------
+
+		$this->in_progress = TRUE;
+		
+		// -----------------------------------
+		// Call the requested class and/or function
+		// -----------------------------------
+		
+		if ($class !== FALSE)
+		{
+			if ( ! class_exists($class))
+			{
+				require($filepath);
+			}
+		
+			$HOOK = new $class;
+			$HOOK->$function($params);
+		}
+		else
+		{
+			if ( ! function_exists($function))
+			{
+				require($filepath);
+			}
+		
+			$function($params);
+		}
+	
+		$this->in_progress = FALSE;
+		return TRUE;
+	}
+  	// END _run_hook()
+
+
+}
+
+// END CI_Hooks class
+?>
\ No newline at end of file
diff --git a/system/libraries/Image_lib.php b/system/libraries/Image_lib.php
new file mode 100644
index 0000000..854f048
--- /dev/null
+++ b/system/libraries/Image_lib.php
@@ -0,0 +1,1550 @@
+<?php  if (!defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * Code Igniter
+ *
+ * An open source application development framework for PHP 4.3.2 or newer
+ *
+ * @package		CodeIgniter
+ * @author		Rick Ellis
+ * @copyright	Copyright (c) 2006, pMachine, Inc.
+ * @license		http://www.codeignitor.com/user_guide/license.html 
+ * @link		http://www.codeigniter.com
+ * @since		Version 1.0
+ * @filesource
+ */
+ 
+// ------------------------------------------------------------------------
+
+/**
+ * Image Manipulation class
+ * 
+ * @package		CodeIgniter
+ * @subpackage	Libraries
+ * @category	Image_lib
+ * @author		Rick Ellis
+ * @link		http://www.codeigniter.com/user_guide/libraries/image_lib.html
+ */
+class CI_Image_lib {
+	
+	var $image_library		= 'gd2';  	// Can be:  imagemagick, netpbm, gd, gd2
+	var $library_path		= '';
+	var $dynamic_output		= FALSE;	// Whether to send to browser or write to disk
+	var $source_image		= '';	
+	var $new_image			= '';
+	var $width				= '';
+	var $height				= '';
+	var $quality			= '90';
+	var $create_thumb		= FALSE;
+	var $thumb_marker		= '_thumb';
+	var $maintain_ratio		= TRUE;  	// Whether to maintain aspect ratio when resizing or use hard values
+	var $master_dim			= 'auto';	// auto, height, or width.  Determines what to use as the master dimension
+	var $rotation_angle		= '';
+	var $x_axis				= '';
+	var	$y_axis				= '';
+	
+	// Watermark Vars
+	var $wm_text			= '';			// Watermark text if graphic is not used
+	var $wm_type			= 'text';		// Type of watermarking.  Options:  text/overlay
+	var $wm_x_transp		= 4;
+	var $wm_y_transp		= 4;
+	var $wm_overlay_path	= '';			// Watermark image path
+	var $wm_font_path		= '';			// TT font
+	var $wm_font_size		= 17;			// Font size (different versions of GD will either use points or pixels)
+	var $wm_vrt_alignment	= 'B';			// Vertical alignment:   T M B
+	var $wm_hor_alignment	= 'C';			// Horizontal alignment: L R C
+	var $wm_padding			= 0;			// Padding around text
+	var $wm_hor_offset		= 0;			// Lets you push text to the right
+	var $wm_vrt_offset		= 0;			 // Lets you push  text down
+	var $wm_font_color		= '#ffffff';	// Text color
+	var $wm_shadow_color	= '';			// Dropshadow color
+	var $wm_shadow_distance	= 2;			// Dropshadow distance
+	var $wm_opacity			= 50; 			// Image opacity: 1 - 100  Only works with image
+	
+	// Private Vars
+	var $source_folder		= '';
+	var $dest_folder		= '';
+	var $mime_type			= '';
+	var $orig_width			= '';
+	var $orig_height		= '';
+	var $image_type			= '';
+	var $size_str			= '';
+	var $full_src_path		= '';
+	var $full_dst_path		= '';
+	var $create_fnc			= 'imagecreatetruecolor';
+	var $copy_fnc			= 'imagecopyresampled';
+	var $error_msg			= array();
+	var $wm_use_drop_shadow	= FALSE;
+	var $wm_use_truetype	= FALSE;		
+	
+	/**
+	 * Constructor 
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	void
+	 */	
+	function CI_Image_lib($props = array())
+	{
+		if (count($props) > 0)
+		{
+			$this->initialize($props);
+		}
+		
+		log_message('debug', "Image Lib Class Initialized");
+	}
+	// END CI_Image_lib()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Initialize image properties
+	 *
+	 * Resets values in case this class is used in a loop
+	 *
+	 * @access	public
+	 * @return	void
+	 */	
+	function clear()
+	{
+		$props = array('source_folder', 'dest_folder', 'source_image', 'full_src_path', 'full_dst_path', 'new_image', 'image_type', 'size_str', 'quality', 'orig_width', 'orig_height', 'rotation_angle', 'x_axis', 'y_axis', 'create_fnc', 'copy_fnc', 'wm_overlay_path', 'wm_use_truetype', 'dynamic_output', 'wm_font_size', 'wm_text', 'wm_vrt_alignment', 'wm_hor_alignment', 'wm_padding', 'wm_hor_offset', 'wm_vrt_offset', 'wm_font_color', 'wm_use_drop_shadow', 'wm_shadow_color', 'wm_shadow_distance', 'wm_opacity');
+	
+		foreach ($props as $val)
+		{
+			$this->$val = '';
+		}  		
+	}
+	// END clear()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * initialize image preferences
+	 *
+	 * @access	public
+	 * @param	array
+	 * @return	void
+	 */	
+	function initialize($props = array())
+	{  
+		/*
+		 * Convert array elements into class variables
+		 */
+		if (count($props) > 0)
+		{
+			foreach ($props as $key => $val)
+			{
+				$this->$key = $val;
+			}
+		}
+
+		/*
+		 * 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?
+		 *
+		 * We use it to determine the image properties (width/height).
+		 * Note:  We need to figure out how to determine image
+		 * properties using ImageMagick and NetPBM
+		 *
+		 */		
+		if ( ! function_exists('getimagesize')) 
+		{
+			$this->set_error('imglib_gd_required_for_props');
+			return FALSE;		
+		}
+		
+		$this->image_library = strtolower($this->image_library);
+		
+		/*
+		 * 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)
+		{
+			$full_source_path = str_replace("\\", "/", realpath($this->source_image)); 
+		}
+		else
+		{
+			$full_source_path = $this->source_image;
+		}
+		
+		$x = explode('/', $full_source_path);
+		$this->source_image = end($x);
+		$this->source_folder = str_replace($this->source_image, '', $full_source_path);
+								
+		// Set the Image Propterties
+		if ( ! $this->get_image_properties($this->source_folder.$this->source_image))
+		{
+			return FALSE;       	
+		}				
+
+		/*
+		 * Assign the "new" image name/path
+		 *
+		 * 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
+		 * set the destination filename and path accordingly.
+		 *
+		 */			
+		if ($this->new_image == '')
+		{
+			$this->dest_image = $this->source_image;
+			$this->dest_folder = $this->source_folder;
+		}
+		else
+		{
+			if (strpos($this->new_image, '/') === FALSE)
+			{
+				$this->dest_folder = $this->source_folder;
+				$this->dest_image = $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; 
+				}
+				
+				// 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
+		 *
+		 * 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 == '')
+		{
+			$this->thumb_marker = '';
+		}
+
+		$xp	= $this->explode_name($this->dest_image);
+	
+		$filename = $xp['name'];
+		$file_ext = $xp['ext'];
+				
+		$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?
+		 *
+		 * 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.
+		 *
+		 */	
+		if ($this->maintain_ratio === TRUE && ($this->width != '' AND $this->height != ''))
+		{
+			$this->image_reproportion();
+		}
+
+		/*
+		 * Was a width and height specified?
+		 *
+		 * 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 ! ctype_digit($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_font_color != '')
+		{
+			if (strlen($this->wm_font_color) == 6)
+			{
+				$this->wm_font_color = '#'.$this->wm_font_color;
+			}
+		}
+		
+		if ($this->wm_shadow_color != '')
+		{
+			if (strlen($this->wm_shadow_color) == 6)
+			{
+				$this->wm_shadow_color = '#'.$this->wm_shadow_color;
+			}
+		}
+	
+		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;
+		}
+
+		if ($this->wm_font_path != '')
+		{
+			$this->wm_use_truetype = TRUE;
+		}
+
+		return TRUE;
+	} 
+	// END initialize()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Image Resize
+	 *
+	 * This is a wrapper function that chooses the proper
+	 * resize function based on the protocol specified
+	 *
+	 * @access	public
+	 * @return	bool
+	 */	
+	function resize()
+	{
+		$protocol = 'image_process_'.$this->image_library;
+		
+		if (eregi("gd2$", $protocol))
+		{
+			$protocol = 'image_process_gd';
+		}
+		
+		return $this->$protocol('resize');
+	}
+	// END resize()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Image Crop
+	 *
+	 * This is a wrapper function that chooses the proper
+	 * cropping function based on the protocol specified
+	 *
+	 * @access	public
+	 * @return	bool
+	 */	
+	function crop()
+	{
+		$protocol = 'image_process_'.$this->image_library;
+		
+		if (eregi("gd2$", $protocol))
+		{
+			$protocol = 'image_process_gd';
+		}
+		
+		return $this->$protocol('crop');
+	}
+	// END crop()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Image Rotate
+	 *
+	 * This is a wrapper function that chooses the proper
+	 * rotation function based on the protocol specified
+	 *
+	 * @access	public
+	 * @return	bool
+	 */	
+	function rotate()
+	{
+		// Allowed rotation values		
+		$degs = array(90, 180, 270, 'vrt', 'hor');	
+	
+		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)
+		{
+			$this->width	= $this->orig_height;
+			$this->height	= $this->orig_width;
+		}
+		else
+		{
+			$this->width	= $this->orig_width;
+			$this->height	= $this->orig_height;
+		}
+	
+
+		// Choose resizing function
+		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();
+		}
+	}
+	// END rotate()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Image Process Using GD/GD2
+	 *
+	 * This function will resize or crop
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	bool
+	 */		
+	function image_process_gd($action = 'resize')
+	{	
+		$v2_override = FALSE;
+			
+		if ($action == 'crop')
+		{
+			// If the target width/height match the source then it's pointless to crop, right?
+			if ($this->width >= $this->orig_width AND $this->height >= $this->orig_width)
+			{
+				// We'll return true so the user thinks the process succeeded.
+				// It'll be our little secret...
+	
+				return TRUE; 
+			}
+			
+			//  Reassign the source width/height if cropping
+			$this->orig_width  = $this->width;
+			$this->orig_height = $this->height;	
+				
+			// GD 2.0 has a cropping bug so we'll test for it
+			if ($this->gd_version() !== FALSE)
+			{
+				$gd_version = str_replace('0', '', $this->gd_version());			
+				$v2_override = ($gd_version == 2) ? TRUE : FALSE;
+			}
+		}
+		else
+		{
+			// 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		
+			if (($this->orig_width == $this->width AND $this->orig_height == $this->height) AND ($this->source_image != $this->dest_image))
+			{
+				if ( ! @copy($this->full_src_path, $this->full_dst_path))
+				{
+					$this->set_error('imglib_copy_failed');
+					return FALSE; 
+				}
+			
+				@chmod($this->full_dst_path, 0777);
+				return TRUE;
+			}
+			
+			// If resizing the x/y axis must be zero
+			$this->x_axis = 0;
+			$this->y_axis = 0;
+		}
+		
+		//  Create the image handle
+		if ( ! ($src_img = $this->image_create_gd()))
+		{		
+			return FALSE;
+		}
+
+		//  Create The Image
+		if ($this->image_library == 'gd2' AND function_exists('imagecreatetruecolor') AND $v2_override == FALSE)
+		{
+			$create	= 'imagecreatetruecolor';
+			$copy	= 'imagecopyresampled';
+		}
+		else
+		{
+			$create	= 'imagecreate';	
+			$copy	= 'imagecopyresized';
+		}
+			
+		$dst_img = $create($this->width, $this->height); 
+		$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)
+		{ 
+			$this->image_display_gd($dst_img);
+		}
+		else
+		{
+			// Or save it
+			if ( ! $this->image_save_gd($dst_img))
+			{
+				return FALSE;
+			}
+		}
+
+		//  Kill the file handles
+		imagedestroy($dst_img); 
+		imagedestroy($src_img);
+		
+		// Set the file to 777
+		@chmod($this->full_dst_path, 0777);            
+		
+		return TRUE;
+	}
+	// END image_process_gd()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Image Process Using ImageMagick
+	 *
+	 * This function will resize, crop or rotate
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	bool
+	 */		
+	function image_process_imagemagick($action = 'resize')
+	{
+		//  Do we have a vaild library path?
+		if ($this->library_path == '')
+		{
+			$this->set_error('imglib_libpath_invalid');
+			return FALSE;
+		}
+				
+		if ( ! eregi("convert$", $this->library_path)) 
+		{
+			if ( ! eregi("/$", $this->library_path)) $this->library_path .= "/";
+		
+			$this->library_path .= 'convert';
+		}
+		
+		// Execute the command
+		$cmd = $this->library_path." -quality ".$this->quality;
+	
+		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";
+		}
+		elseif ($action == 'rotate')
+		{
+			switch ($this->rotation_angle)
+			{
+				case 'hor' 	: $angle = '-flop';
+					break;
+				case 'vrt' 	: $angle = '-flip';
+					break;
+				default		: $angle = '-rotate '.$this->rotation_angle;
+					break;
+			}			
+		
+			$cmd .= " ".$angle." \"$this->full_src_path\" \"$this->full_dst_path\" 2>&1";
+		}
+		else  // Resize
+		{
+			$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?	
+		if ($retval > 0) 
+		{
+			$this->set_error('imglib_image_process_failed');
+			return FALSE;
+		}
+		
+		// Set the file to 777
+		@chmod($this->full_dst_path, 0777);            
+		
+		return TRUE;
+	}
+	// END image_process_imagemagick()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Image Process Using NetPBM
+	 *
+	 * This function will resize, crop or rotate
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	bool
+	 */		
+	function image_process_netpbm($action = 'resize')
+	{
+		if ($this->library_path == '')
+		{
+			$this->set_error('imglib_libpath_invalid');
+			return FALSE;
+		}
+			
+		//  Build the resizing command
+		switch ($this->image_type)
+		{
+			case 1 :
+						$cmd_in		= 'giftopnm';
+						$cmd_out	= 'ppmtogif';
+				break;
+			case 2 :
+						$cmd_in		= 'jpegtopnm';
+						$cmd_out	= 'ppmtojpeg';			
+				break;
+			case 3 :
+						$cmd_in		= 'pngtopnm';
+						$cmd_out	= 'ppmtopng';
+				break;
+		}
+		
+		if ($action == 'crop')
+		{
+			$cmd_inner = 'pnmcut -left '.$this->x_axis.' -top '.$this->y_axis.' -width '.$this->width.' -height '.$this->height;
+		}
+		elseif ($action == 'rotate')
+		{
+			switch ($this->rotation_angle)
+			{
+				case 90		:	$angle = 'r270';
+					break;
+				case 180	:	$angle = 'r180';
+					break;
+				case 270 	:	$angle = 'r90';
+					break;
+				case 'vrt'	:	$angle = 'tb';
+					break;
+				case 'hor'	:	$angle = 'lr';
+					break;
+			}
+		
+			$cmd_inner = 'pnmflip -'.$angle.' ';
+		}
+		else // Resize
+		{
+			$cmd_inner = 'pnmscale -xysize '.$this->width.' '.$this->height;
+		}
+						
+		$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?
+		if ($retval > 0) 
+		{
+			$this->set_error('imglib_image_process_failed');
+			return FALSE;
+		}
+		
+		// With NetPBM we have to create a temporary image.
+		// 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');
+		@chmod($dst_image, 0777);            
+		
+		return TRUE;
+	}
+	// END image_process_netpbm()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Image Rotate Using GD
+	 *
+	 * @access	public
+	 * @return	bool
+	 */		
+	function image_rotate_gd()
+	{	
+		// Is Image Rotation Supported?
+		// this function is only supported as of PHP 4.3
+		if ( ! function_exists('imagerotate'))
+		{ 
+			$this->set_error('imglib_rotate_unsupported');
+			return FALSE;
+		}
+		
+		//  Create the image handle
+		if ( ! ($src_img = $this->image_create_gd()))
+		{		
+			return FALSE;
+		}
+
+		// Set the background color		
+		// This won't work with transparent PNG files so we are
+		// going to have to figure out how to determine the color
+		// of the alpha channel in a future release.
+	
+		$white	= imagecolorallocate($src_img, 255, 255, 255);
+
+		//  Rotate it!
+		$dst_img = imagerotate($src_img, $this->rotation_angle, $white);
+	
+		//  Save the Image
+		if ($this->dynamic_output == TRUE)
+		{ 
+			$this->image_display_gd($dst_img);
+		}
+		else
+		{
+			// Or save it
+			if ( ! $this->image_save_gd($dst_img))
+			{
+				return FALSE;
+			}
+		}
+
+		//  Kill the file handles
+		imagedestroy($dst_img); 
+		imagedestroy($src_img);
+		
+		// Set the file to 777
+		
+		@chmod($this->full_dst_path, 0777);            
+		
+		return true;
+	}
+	// END image_rotate_gd()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Create Mirror Image using GD
+	 *
+	 * This function will flip horizontal or vertical
+	 *
+	 * @access	public
+	 * @return	bool
+	 */			
+	function image_mirror_gd()
+	{		
+		if ( ! $src_img = $this->image_create_gd())
+		{
+			return FALSE;
+		}
+		
+		$width  = $this->orig_width;
+		$height = $this->orig_height;
+	
+		if ($this->rotation_angle == 'hor')
+		{
+			for ($i = 0; $i < $height; $i++)
+			{         
+				$left  = 0; 
+				$right = $width-1; 
+	
+				while ($left < $right)
+				{ 
+					$cl = imagecolorat($src_img, $left, $i); 
+					$cr = imagecolorat($src_img, $right, $i);
+					
+					imagesetpixel($src_img, $left, $i, $cr); 
+					imagesetpixel($src_img, $right, $i, $cl); 
+					
+					$left++; 
+					$right--; 
+				} 
+			}
+		}
+		else
+		{
+			for ($i = 0; $i < $width; $i++)
+			{         
+				$top = 0; 
+				$bot = $height-1; 
+	
+				while ($top < $bot)
+				{ 
+					$ct = imagecolorat($src_img, $i, $top);
+					$cb = imagecolorat($src_img, $i, $bot);
+					
+					imagesetpixel($src_img, $i, $top, $cb); 
+					imagesetpixel($src_img, $i, $bot, $ct); 
+					
+					$top++; 
+					$bot--; 
+				} 
+			}		
+		}		
+
+		//  Show the image
+		if ($this->dynamic_output == TRUE)
+		{ 
+			$this->image_display_gd($src_img);
+		}
+		else
+		{
+			// Or save it
+			if ( ! $this->image_save_gd($src_img))
+			{
+				return FALSE;
+			}
+		}
+		
+		//  Kill the file handles
+		imagedestroy($src_img);
+		
+		// Set the file to 777
+		@chmod($this->full_dst_path, 0777);            
+		
+		return TRUE;
+	}
+	// END image_mirror_gd()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Image Watermark
+	 *
+	 * This is a wrapper function that chooses the type
+	 * of watermarking based on the specified preference.
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	bool
+	 */	
+	function watermark()
+	{
+		if ($this->wm_type == 'overlay')
+		{
+			return $this->overlay_watermark();
+		}
+		else
+		{
+			return $this->text_watermark();
+		}
+	}
+	// END image_mirror_gd()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Watermark - Graphic Version
+	 *
+	 * @access	public
+	 * @return	bool
+	 */			
+	function overlay_watermark()
+	{
+		if ( ! function_exists('imagecolortransparent'))
+		{
+			$this->set_error('imglib_gd_required');
+			return FALSE;		
+		}
+	
+		//  Fetch source image properties
+		$this->get_image_properties();
+
+		//  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'];
+	
+		//  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
+		// 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));
+	
+		if ($this->wm_vrt_alignment == 'B')
+			$this->wm_vrt_offset = $this->wm_vrt_offset * -1;
+	
+		if ($this->wm_hor_alignment == 'R')
+			$this->wm_hor_offset = $this->wm_hor_offset * -1;
+
+		//  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)
+		{
+			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;
+		}
+
+		//  Set the horizontal position
+		switch ($this->wm_hor_alignment)
+		{
+			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;
+		}
+	
+		//  Build the finalized image			
+		if ($wm_img_type == 3 AND function_exists('imagealphablending')) 
+		{ 
+			@imagealphablending($src_img, TRUE);
+		} 		
+
+		// Set RGB values for text and shadow		
+		imagecolortransparent($wm_img, imagecolorat($wm_img, $this->wm_x_transp, $this->wm_y_transp));
+		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)
+		{ 
+			$this->image_display_gd($src_img);
+		}
+		else
+		{
+			if ( ! $this->image_save_gd($src_img))
+			{
+				return FALSE;
+			}
+		}
+		
+		imagedestroy($src_img);
+		imagedestroy($wm_img);
+				
+		return TRUE;
+	}
+	// END overlay_watermark()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Watermark - Text Version
+	 *
+	 * @access	public
+	 * @return	bool
+	 */			
+	function text_watermark() 
+	{
+		if ( ! ($src_img = $this->image_create_gd()))
+		{		
+			return FALSE;
+		}
+				
+		if ($this->wm_use_truetype == TRUE AND ! file_exists($this->wm_font_path))
+		{
+			$this->set_error('imglib_missing_font');
+			return FALSE;
+		}
+		
+		//  Fetch source image properties		
+		$this->get_image_properties();				
+		
+		// Set RGB values for text and shadow		
+		$this->wm_font_color	= str_replace('#', '', $this->wm_font_color);
+		$this->wm_shadow_color	= str_replace('#', '', $this->wm_shadow_color);
+		
+		$R1 = hexdec(substr($this->wm_font_color, 0, 2));
+		$G1 = hexdec(substr($this->wm_font_color, 2, 2));
+		$B1 = hexdec(substr($this->wm_font_color, 4, 2));
+	
+		$R2 = hexdec(substr($this->wm_shadow_color, 0, 2));
+		$G2 = hexdec(substr($this->wm_shadow_color, 2, 2));
+		$B2 = hexdec(substr($this->wm_shadow_color, 4, 2));
+		
+		$txt_color	= imagecolorclosest($src_img, $R1, $G1, $B1);
+		$drp_color	= imagecolorclosest($src_img, $R2, $G2, $B2);
+
+		// 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
+		// offset flips itself automatically
+	
+		if ($this->wm_vrt_alignment == 'B')
+			$this->wm_vrt_offset = $this->wm_vrt_offset * -1;
+			
+		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_font_size == '')
+				$this->wm_font_size = '17';
+		
+			$fontwidth  = $this->wm_font_size-($this->wm_font_size/4);
+			$fontheight = $this->wm_font_size;
+			$this->wm_vrt_offset += $this->wm_font_size;
+		}
+		else
+		{
+			$fontwidth  = imagefontwidth($this->wm_font_size);
+			$fontheight = imagefontheight($this->wm_font_size);
+		}
+
+		// Set 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 verticle alignment
+		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) 
+		{
+			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;
+		}
+	
+		$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;
+		}
+		
+		//  Add the text to the source image
+		if ($this->wm_use_truetype)
+		{	
+			if ($this->wm_use_drop_shadow)
+				imagettftext($src_img, $this->wm_font_size, 0, $x_shad, $y_shad, $drp_color, $this->wm_font_path, $this->wm_text);
+				imagettftext($src_img, $this->wm_font_size, 0, $x_axis, $y_axis, $txt_color, $this->wm_font_path, $this->wm_text);
+		}
+		else
+		{
+			if ($this->wm_use_drop_shadow)
+				imagestring($src_img, $this->wm_font_size, $x_shad, $y_shad, $this->wm_text, $drp_color);
+				imagestring($src_img, $this->wm_font_size, $x_axis, $y_axis, $this->wm_text, $txt_color);
+		}
+	
+		//  Output the final image
+		if ($this->dynamic_output == TRUE)
+		{ 
+			$this->image_display_gd($src_img);
+		}
+		else
+		{
+			$this->image_save_gd($src_img);
+		}
+		
+		imagedestroy($src_img);
+	
+		return TRUE;
+	}
+	// END text_watermark()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Create Image - GD
+	 *
+	 * This simply creates an image resource handle
+	 * based on the type of image being processed
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	resource
+	 */			
+	function image_create_gd($path = '', $image_type = '')
+	{
+		if ($path == '')
+			$path = $this->full_src_path;
+			
+		if ($image_type == '')
+			$image_type = $this->image_type;
+	
+		
+		switch ($image_type)
+		{
+			case	 1 :
+						if ( ! function_exists('imagecreatefromgif'))
+						{
+							$this->set_error(array('imglib_unsupported_imagecreate', 'imglib_gif_not_supported'));
+							return FALSE;
+						}
+					
+						return imagecreatefromgif($path);
+				break;
+			case 2 :
+						if ( ! function_exists('imagecreatefromjpeg'))
+						{
+							$this->set_error(array('imglib_unsupported_imagecreate', 'imglib_jpg_not_supported'));
+							return FALSE;
+						}
+					
+						return imagecreatefromjpeg($path);
+				break;
+			case 3 :
+						if ( ! function_exists('imagecreatefrompng'))
+						{
+							$this->set_error(array('imglib_unsupported_imagecreate', 'imglib_png_not_supported'));				
+							return FALSE;
+						}
+					
+						return imagecreatefrompng($path);
+				break;			
+		
+		}
+		
+		$this->set_error(array('imglib_unsupported_imagecreate'));
+		return FALSE;
+	}
+	// END image_create_gd()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Write imge file to disk - GD
+	 *
+	 * Takes an image resource as input and writes the file 
+	 * to the specified destination
+	 *
+	 * @access	public
+	 * @param	resource
+	 * @return	bool
+	 */			
+	function image_save_gd($resource)
+	{	
+		switch ($this->image_type)
+		{
+			case 1 :
+						if ( ! function_exists('imagegif'))
+						{
+							$this->set_error(array('imglib_unsupported_imagecreate', 'imglib_gif_not_supported'));
+							return FALSE;		
+						}
+						
+						@imagegif($resource, $this->full_dst_path);
+				break;
+			case 2	:
+						if ( ! function_exists('imagejpeg'))
+						{
+							$this->set_error(array('imglib_unsupported_imagecreate', 'imglib_jpg_not_supported'));
+							return FALSE;		
+						}
+						
+						if (phpversion() == '4.4.1')
+						{
+							@touch($this->full_dst_path); // PHP 4.4.1 bug #35060 - workaround
+						}
+						
+						@imagejpeg($resource, $this->full_dst_path, $this->quality);
+				break;
+			case 3	:
+						if ( ! function_exists('imagepng'))
+						{
+							$this->set_error(array('imglib_unsupported_imagecreate', 'imglib_png_not_supported'));
+							return FALSE;		
+						}
+					
+						@imagepng($resource, $this->full_dst_path);
+				break;
+			default		:
+							$this->set_error(array('imglib_unsupported_imagecreate'));
+							return FALSE;		
+				break;		
+		}
+	
+		return TRUE;
+	}	
+	// END image_save_gd()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Dynamically ouputs an image
+	 *
+	 * @access	public
+	 * @param	resource
+	 * @return	void
+	 */			
+	function image_display_gd($resource)
+	{		
+		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);
+				break;
+			case 2		:	imagejpeg($resource, '', $this->quality);
+				break;
+			case 3		:	imagepng($resource);
+				break;
+			default		:	echo 'Unable to display the image';
+				break;		
+		}			
+	}
+	// END image_display_gd()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Reproportion Image Width/Height
+	 *
+	 * When creating thumbs, the desired width/height
+	 * can end up warping the image due to an incorrect 
+	 * ratio between the full-sized image and the thumb. 
+	 * 
+	 * This function lets us reproportion the width/height
+	 * if users choose to maintain the aspect ratio when resizing.
+	 *
+	 * @access	public
+	 * @return	void
+	 */			
+	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')
+		{
+			$this->master_dim = ($ratio < 0) ? 'width' : 'height';
+		}
+		
+		if (($this->width != $new_width) AND ($this->height != $new_height))
+		{
+			if ($this->master_dim == 'height')
+			{
+				$this->width = $new_width;
+			}
+			else
+			{
+				$this->height = $new_height;
+			}
+		}
+	}	
+	// END image_reproportion()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Get image properties
+	 *
+	 * A helper function that gets info about the file
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	mixed
+	 */			
+	function get_image_properties($path = '', $return = FALSE)
+	{
+		// For now we require GD but we should
+		// find a way to determine this using IM or NetPBM
+		
+		if ($path == '')
+			$path = $this->full_src_path;
+				
+		if ( ! file_exists($path))
+		{
+			$this->set_error('imglib_invalid_path');		
+			return FALSE;				
+		}
+		
+		$vals = @getimagesize($path);
+		
+		$types = array(1 => 'gif', 2 => 'jpeg', 3 => 'png');
+		
+		$mime = (isset($types[$vals['2']])) ? 'image/'.$types[$vals['2']] : 'image/jpg';
+				
+		if ($return == TRUE)
+		{
+			$v['width']			= $vals['0'];
+			$v['height']		= $vals['1'];
+			$v['image_type']	= $vals['2'];
+			$v['size_str']		= $vals['3']; 
+			$v['mime_type']		= $mime;
+			
+			return $v;
+		}
+		
+		$this->orig_width	= $vals['0'];
+		$this->orig_height	= $vals['1'];
+		$this->image_type	= $vals['2'];
+		$this->size_str		= $vals['3']; 
+		$this->mime_type	= $mime; 
+		
+		return TRUE;
+	}
+	// END get_image_properties()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Size calculator
+	 *
+	 * This function takes a known width x height and
+	 * 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'	=> ''
+	 *				  );    
+	 *
+	 * @access	public
+	 * @param	array
+	 * @return	array
+	 */			
+	function size_calculator($vals)
+	{
+		if ( ! is_array($vals))
+			return;
+			
+		$allowed = array('new_width', 'new_height', 'width', 'height');
+	
+		foreach ($allowed as $item)
+		{
+			if ( ! isset($vals[$item]) OR $vals[$item] == '')
+				$vals[$item] = 0;
+		}
+		
+		if ($vals['width'] == 0 OR $vals['height'] == 0)
+		{
+			return $vals;
+		}
+			
+		if ($vals['new_width'] == 0)
+		{
+			$vals['new_width'] = ceil($vals['width']*$vals['new_height']/$vals['height']);
+		}
+		elseif ($vals['new_height'] == 0)
+		{
+			$vals['new_height'] = ceil($vals['new_width']*$vals['height']/$vals['width']);
+		}
+	
+		return $vals;
+	}
+	// END size_calculator()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Explode source_image
+	 *
+	 * 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
+	 * It returns an associative array with two elements:
+	 * $array['ext']  = '.jpg';
+	 * $array['name'] = 'my.cool';
+	 *
+	 * @access	public
+	 * @param	array
+	 * @return	array
+	 */	
+	function explode_name($source_image)
+	{
+		$x = explode('.', $source_image);
+		$ret['ext'] = '.'.end($x);
+		
+		$name = '';
+		
+		$ct = count($x)-1;
+		
+		for ($i = 0; $i < $ct; $i++)
+		{
+			$name .= $x[$i];
+			
+			if ($i < ($ct - 1))
+			{
+				$name .= '.';
+			}
+		}
+		
+		$ret['name'] = $name;
+		
+		return $ret;
+	}	
+	// END explode_name()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Is GD Installed?
+	 *
+	 * @access	public
+	 * @return	bool
+	 */	
+	function gd_loaded()
+	{
+		if ( ! extension_loaded('gd'))
+		{
+			if ( ! dl('gd.so'))
+			{
+				return FALSE;
+			}
+		}
+		
+		return TRUE;
+	}
+	// END gd_loaded()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Get GD version
+	 *
+	 * @access	public
+	 * @return	mixed
+	 */	
+	function gd_version()
+	{
+		if (function_exists('gd_info'))
+		{
+			$gd_version = @gd_info();
+			$gd_version = preg_replace("/\D/", "", $gd_version['GD Version']);
+			
+			return $gd_version;
+		}
+		
+		return FALSE;
+	}
+	// END gd_version()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Set error message
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	void
+	 */	
+	function set_error($msg)
+	{
+		$obj =& get_instance();
+		$obj->lang->load('imglib');
+		
+		if (is_array($msg))
+		{
+			foreach ($msg as $val)
+			{
+				
+				$msg = ($obj->lang->line($val) == FALSE) ? $val : $obj->lang->line($val);
+				$this->error_msg[] = $msg;
+				log_message('error', $msg);
+			}		
+		}
+		else
+		{
+			$msg = ($obj->lang->line($msg) == FALSE) ? $msg : $obj->lang->line($msg);
+			$this->error_msg[] = $msg;
+			log_message('error', $msg);
+		}
+	}
+	// END set_error()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Show error messages
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	string
+	 */	
+	function display_errors($open = '<p>', $close = '</p>')
+	{	
+		$str = '';
+		foreach ($this->error_msg as $val)
+		{
+			$str .= $open.$val.$close;
+		}
+	
+		return $str;
+	}
+	// END display_errors()
+}
+// END Image_lib Class
+?>
\ No newline at end of file
diff --git a/system/libraries/Input.php b/system/libraries/Input.php
new file mode 100644
index 0000000..6aba5dd
--- /dev/null
+++ b/system/libraries/Input.php
@@ -0,0 +1,585 @@
+<?php  if (!defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * Code Igniter
+ *
+ * An open source application development framework for PHP 4.3.2 or newer
+ *
+ * @package		CodeIgniter
+ * @author		Rick Ellis
+ * @copyright	Copyright (c) 2006, pMachine, Inc.
+ * @license		http://www.codeignitor.com/user_guide/license.html 
+ * @link		http://www.codeigniter.com
+ * @since		Version 1.0
+ * @filesource
+ */
+ 
+// ------------------------------------------------------------------------
+
+/**
+ * Input Class
+ * 
+ * Pre-processes global input data for security
+ *
+ * @package		CodeIgniter
+ * @subpackage	Libraries
+ * @category	Input
+ * @author		Rick Ellis
+ * @link		http://www.codeigniter.com/user_guide/libraries/input.html
+ */
+class CI_Input {
+	var $use_xss_clean		= FALSE;
+	var $ip_address			= FALSE;
+	var $user_agent			= FALSE;
+	var $allow_get_array	= FALSE;
+	
+	/**
+	 * Constructor
+	 *
+	 * Sets whether to globally enable the XSS processing
+	 * and whether to allow the $_GET array
+	 *
+	 * @access	public
+	 */	
+	function CI_Input()
+	{	
+		$CFG =& _load_class('CI_Config');
+		$this->use_xss_clean	= ($CFG->item('global_xss_filtering') === TRUE) ? TRUE : FALSE;
+		$this->allow_get_array	= ($CFG->item('enable_query_strings') === TRUE) ? TRUE : FALSE;
+		
+		log_message('debug', "Input Class Initialized");
+		$this->_sanitize_globals();
+	}
+	// END CI_Input()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Sanitize Globals
+	 *
+	 * This function does the folowing:
+	 *
+	 * Unsets $_GET data (if query strings are not enabled)
+	 *
+	 * Unsets all globals if register_globals is enabled
+	 *
+	 * Standardizes newline characters to \n
+	 *
+	 * @access	private
+	 * @return	void
+	 */
+	function _sanitize_globals()
+	{
+		// Unset globals. This is effectively the same as register_globals = off
+		foreach (array($_GET, $_POST, $_COOKIE) as $global)
+		{
+			if ( ! is_array($global))
+			{
+				unset($$global);
+			}
+			else
+			{
+				foreach ($global as $key => $val)
+				{
+					unset($$key);
+				}    
+			}
+		}
+
+		// Is $_GET data allowed?
+		if ($this->allow_get_array == FALSE)
+		{
+			$_GET = array();
+		}
+		
+		// Clean $_POST Data
+		if (is_array($_POST) AND count($_POST) > 0)
+		{
+			foreach($_POST as $key => $val)
+			{                
+				if (is_array($val))
+				{ 	
+					foreach($val as $k => $v)
+					{                    
+						$_POST[$this->_clean_input_keys($key)][$this->_clean_input_keys($k)] = $this->_clean_input_data($v);
+					}
+				}
+				else
+				{
+					$_POST[$this->_clean_input_keys($key)] = $this->_clean_input_data($val);
+				}
+			}            
+		}
+	
+		// Clean $_COOKIE Data
+		if (is_array($_COOKIE) AND count($_COOKIE) > 0)
+		{
+			foreach($_COOKIE as $key => $val)
+			{              
+				$_COOKIE[$this->_clean_input_keys($key)] = $this->_clean_input_data($val);
+			}    
+		}
+		
+		log_message('debug', "Global POST and COOKIE data sanitized");
+	}	
+	// END _sanitize_globals()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Clean Intput Data
+	 *
+	 * This is a helper function. It escapes data and 
+	 * standardizes newline characters to \n
+	 *
+	 * @access	private
+	 * @param	string
+	 * @return	string
+	 */	
+	function _clean_input_data($str)
+	{
+		if (is_array($str))
+		{
+			$new_array = array();
+			foreach ($str as $key => $val)
+			{
+				$new_array[$key] = $this->_clean_input_data($val);
+			}
+			return $new_array;
+		}
+		
+		if ($this->use_xss_clean === TRUE)
+		{
+			$str = $this->xss_clean($str);
+		}
+		
+		return preg_replace("/\015\012|\015|\012/", "\n", $str);
+	}
+	// END _clean_input_data()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * 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.
+	 *
+	 * @access	private
+	 * @param	string
+	 * @return	string
+	 */
+	function _clean_input_keys($str)
+	{    
+		 if ( ! preg_match("/^[a-z0-9:_\/-]+$/i", $str))
+		 { 
+			exit('Disallowed Key Characters: '.$str);
+		 }
+	
+		if ( ! get_magic_quotes_gpc())
+		{
+		   return addslashes($str);
+		}
+		
+		return $str;
+	}
+	// END _clean_input_keys()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Fetch an item from the POST array
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	string
+	 */
+	function post($index = '', $xss_clean = FALSE)
+	{		
+		if ( ! isset($_POST[$index]))
+		{
+			return FALSE;
+		}
+		else
+		{
+			if ($xss_clean === TRUE)
+			{
+				return $this->xss_clean($_POST[$index]);
+			}
+			else
+			{
+				return $_POST[$index];
+			}
+		}
+	}
+	// END post()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Fetch an item from the COOKIE array
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	string
+	 */
+	function cookie($index = '', $xss_clean = FALSE)
+	{
+		if ( ! isset($_COOKIE[$index]))
+		{
+			return FALSE;
+		}
+		else
+		{
+			if ($xss_clean === TRUE)
+			{
+				return $this->xss_clean($_COOKIE[$index]);
+			}
+			else
+			{
+				return $_COOKIE[$index];
+			}
+		}
+	}
+	// END cookie()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Fetch the IP Address
+	 *
+	 * @access	public
+	 * @return	string
+	 */
+	function ip_address()
+	{
+		if ($this->ip_address !== FALSE)
+		{
+			return $this->ip_address;
+		}
+	
+		$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;
+		$fip = (isset($_SERVER['HTTP_X_FORWARDED_FOR']) AND $_SERVER['HTTP_X_FORWARDED_FOR'] != "") ? $_SERVER['HTTP_X_FORWARDED_FOR'] : FALSE;
+					
+		if ($cip && $rip)	$this->ip_address = $cip;	
+		elseif ($rip)		$this->ip_address = $rip;
+		elseif ($cip)		$this->ip_address = $cip;
+		elseif ($fip)		$this->ip_address = $fip;
+		
+		if (strstr($this->ip_address, ','))
+		{
+			$x = explode(',', $this->ip_address);
+			$this->ip_address = end($x);
+		}
+		
+		if ( ! $this->valid_ip($this->ip_address))
+		{
+			$this->ip_address = '0.0.0.0';
+		}
+		
+		unset($cip);
+		unset($rip);
+		unset($fip);
+		
+		return $this->ip_address;
+	}
+	// END ip_address()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Validate IP Address
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	string
+	 */
+	function valid_ip($ip)
+	{
+		return ( ! preg_match( "/^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/", $ip)) ? FALSE : TRUE;
+	}
+	// END valid_ip()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * User Agent
+	 *
+	 * @access	public
+	 * @return	string
+	 */
+	function user_agent()
+	{
+		if ($this->user_agent !== FALSE)
+		{
+			return $this->user_agent;
+		}
+	
+		$this->user_agent = ( ! isset($_SERVER['HTTP_USER_AGENT'])) ? FALSE : $_SERVER['HTTP_USER_AGENT'];
+		
+		return $this->user_agent;
+	}
+	// END user_agent()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * XSS Clean
+	 *
+	 * Sanitizes data so that Cross Site Scripting Hacks can be
+	 * prevented.Ê This function does a fair amount of work but
+	 * it is extremely thorough, designed to prevent even the
+	 * most obscure XSS attempts.Ê Nothing is ever 100% foolproof,
+	 * of course, but I haven't been able to get anything passed
+	 * the filter.
+	 *
+	 * Note: This function should only be used to deal with data
+	 * upon submission.Ê It's not something that should
+	 * be used for general runtime processing.
+	 *
+	 * This function was based in part on some code and ideas I
+	 * got from Bitflux: http://blog.bitflux.ch/wiki/XSS_Prevention
+	 *
+	 * To help develop this script I used this great list of
+	 * vulnerabilities along with a few other hacks I've 
+	 * harvested from examining vulnerabilities in other programs:
+	 * http://ha.ckers.org/xss.html
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	string
+	 */
+	function xss_clean($str, $charset = 'ISO-8859-1')
+	{	
+		/*
+		 * Remove Null Characters
+		 *
+		 * This prevents sandwiching null characters
+		 * between ascii characters, like Java\0script.
+		 *
+		 */
+		$str = preg_replace('/\0+/', '', $str);
+		$str = preg_replace('/(\\\\0)+/', '', $str);
+
+		/*
+		 * Validate standard character entites
+		 *
+		 * Add a semicolon if missing.  We do this to enable
+		 * the conversion of entities to ASCII later.
+		 *
+		 */
+		$str = preg_replace('#(&\#*\w+)[\x00-\x20]+;#u',"\\1;",$str);
+		
+		/*
+		 * Validate UTF16 two byte encodeing (x00) 
+		 *
+		 * Just as above, adds a semicolon if missing.
+		 *
+		 */
+		$str = preg_replace('#(&\#x*)([0-9A-F]+);*#iu',"\\1\\2;",$str);
+
+		/*
+		 * URL Decode
+		 *
+		 * Just in case stuff like this is submitted:
+		 *
+		 * <a href="http://%77%77%77%2E%67%6F%6F%67%6C%65%2E%63%6F%6D">Google</a>
+		 *
+		 * Note: Normally urldecode() would be easier but it removes plus signs
+		 *
+		 */	
+		$str = preg_replace("/%u0([a-z0-9]{3})/i", "&#x\\1;", $str);
+		$str = preg_replace("/%([a-z0-9]{2})/i", "&#x\\1;", $str);        
+        		
+		/*
+		 * Convert character entities to ASCII 
+		 *
+		 * This permits our tests below to work reliably.
+		 * We only convert entities that are within tags since
+		 * these are the ones that will pose security problems.
+		 *
+		 */
+		 
+        if (preg_match_all("/<(.+?)>/si", $str, $matches))
+        {        
+			for ($i = 0; $i < count($matches['0']); $i++)
+			{
+				$str = str_replace($matches['1'][$i], 
+									$this->_html_entity_decode($matches['1'][$i], $charset), 
+									$str);
+			}
+		}
+	
+		/*
+		 * Convert all tabs to spaces
+		 *
+		 * This prevents strings like this: ja	vascript
+		 * Note: we deal with spaces between characters later.
+		 *
+		 */		
+		$str = preg_replace("#\t+#", " ", $str);
+	
+		/*
+		 * Makes PHP tags safe
+		 *
+		 *  Note: XML tags are inadvertently replaced too:
+		 *
+		 *	<?xml
+		 *
+		 * But it doesn't seem to pose a problem.
+		 *
+		 */		
+		$str = str_replace(array('<?php', '<?PHP', '<?', '?>'),  array('&lt;?php', '&lt;?PHP', '&lt;?', '?&gt;'), $str); // <?php BBEdit bug fix
+	
+		/*
+		 * Compact any exploded words
+		 *
+		 * This corrects words like:  j a v a s c r i p t
+		 * These words are compacted back to their correct state.
+		 *
+		 */		
+		$words = array('javascript', 'vbscript', 'script', 'applet', 'alert', 'document', 'write', 'cookie', 'window');
+		foreach ($words as $word)
+		{
+			$temp = '';
+			for ($i = 0; $i < strlen($word); $i++)
+			{
+				$temp .= substr($word, $i, 1)."\s*";
+			}
+			
+			$temp = substr($temp, 0, -3);
+			$str = preg_replace('#'.$temp.'#s', $word, $str);
+			$str = preg_replace('#'.ucfirst($temp).'#s', ucfirst($word), $str);
+		}
+	
+		/*
+		 * Remove disallowed Javascript in links or img tags
+		 */		
+		 $str = preg_replace("#<a.+?href=.*?(alert\(|alert&\#40;|javascript\:|window\.|document\.|\.cookie|<script|<xss).*?\>.*?</a>#si", "", $str);
+		 $str = preg_replace("#<img.+?src=.*?(alert\(|alert&\#40;|javascript\:|window\.|document\.|\.cookie|<script|<xss).*?\>#si", "", $str);
+		 $str = preg_replace("#<(script|xss).*?\>#si", "", $str);
+
+		/*
+		 * Remove JavaScript Event Handlers
+		 *
+		 * Note: This code is a little blunt.  It removes
+		 * the event handler and anything up to the closing >, 
+		 * but it's unlkely to be a problem.
+		 *
+		 */		
+		 $str = preg_replace('#(<[^>]+.*?)(onblur|onchange|onclick|onfocus|onload|onmouseover|onmouseup|onmousedown|onselect|onsubmit|onunload|onkeypress|onkeydown|onkeyup|onresize)[^>]*>#iU',"\\1>",$str);
+	
+		/*
+		 * Sanitize naughty HTML elements
+		 *
+		 * If a tag containing any of the words in the list 
+		 * below is found, the tag gets converted to entities.
+		 *
+		 * So this: <blink>
+		 * Becomes: &lt;blink&gt;
+		 *
+		 */		
+		$str = preg_replace('#<(/*\s*)(alert|applet|basefont|base|behavior|bgsound|blink|body|embed|expression|form|frameset|frame|head|html|ilayer|iframe|input|layer|link|meta|object|plaintext|style|script|textarea|title|xml|xss)([^>]*)>#is', "&lt;\\1\\2\\3&gt;", $str);
+		
+		/*
+		 * Sanitize naughty scripting elements
+		 *
+		 * Similar to above, only instead of looking for
+		 * tags it looks for PHP and JavaScript commands
+		 * that are disallowed.  Rather than removing the
+		 * code, it simply converts the parenthesis to entities
+		 * rendering the code unexecutable.
+		 *
+		 * For example:	eval('some code')
+		 * Becomes:		eval&#40;'some code'&#41;
+		 *
+		 */
+		$str = preg_replace('#(alert|cmd|passthru|eval|exec|system|fopen|fsockopen|file|file_get_contents|readfile|unlink)(\s*)\((.*?)\)#si', "\\1\\2&#40;\\3&#41;", $str);
+						
+		/*
+		 * Final clean up
+		 *
+		 * This adds a bit of extra precaution in case
+		 * something got through the above filters
+		 *
+		 */	
+		$bad = array(
+						'document.cookie'	=> '',
+						'document.write'	=> '',
+						'window.location'	=> '',
+						"javascript\s*:"	=> '',
+						"Redirect\s+302"	=> '',
+						'<!--'				=> '&lt;!--',
+						'-->'				=> '--&gt;'
+					);
+	
+		foreach ($bad as $key => $val)
+		{
+			$str = preg_replace("#".$key."#i", $val, $str);   
+		}
+		
+                        
+		log_message('debug', "XSS Filtering completed");
+		return $str;
+	}
+	// END xss_clean()
+
+
+	/**
+	 * HTML Entities Decode
+	 *
+	 * This function is a replacement for html_entity_decode()
+	 *
+	 * In some versions of PHP the native function does not work
+	 * when UTF-8 is the specified character set, so this gives us
+	 * a work-around.  More info here:
+	 * http://bugs.php.net/bug.php?id=25670
+	 *
+	 * @access	private
+	 * @param	string
+	 * @param	string
+	 * @return	string
+	 */
+	/* -------------------------------------------------
+    /*  Replacement for html_entity_decode()
+    /* -------------------------------------------------*/
+    
+    /*
+    NOTE: html_entity_decode() has a bug in some PHP versions when UTF-8 is the 
+    character set, and the PHP developers said they were not back porting the
+    fix to versions other than PHP 5.x.
+    */
+	function _html_entity_decode($str, $charset='ISO-8859-1') 
+	{
+		if (stristr($str, '&') === FALSE) return $str;
+	
+		// The reason we are not using html_entity_decode() by itself is because
+		// while it is not technically correct to leave out the semicolon
+		// at the end of an entity most browsers will still interpret the entity
+		// correctly.  html_entity_decode() does not convert entities without
+		// semicolons, so we are left with our own little solution here. Bummer.
+	
+		if (function_exists('html_entity_decode') && (strtolower($charset) != 'utf-8' OR version_compare(phpversion(), '5.0.0', '>=')))
+		{
+			$str = html_entity_decode($str, ENT_COMPAT, $charset);
+			$str = preg_replace('~&#x([0-9a-f]{2,5})~ei', 'chr(hexdec("\\1"))', $str);
+			return preg_replace('~&#([0-9]{2,4})~e', 'chr(\\1)', $str);
+		}
+		
+		// Numeric Entities
+		$str = preg_replace('~&#x([0-9a-f]{2,5});{0,1}~ei', 'chr(hexdec("\\1"))', $str);
+		$str = preg_replace('~&#([0-9]{2,4});{0,1}~e', 'chr(\\1)', $str);
+	
+		// Literal Entities - Slightly slow so we do another check
+		if (stristr($str, '&') === FALSE)
+		{
+			$str = strtr($str, array_flip(get_html_translation_table(HTML_ENTITIES)));
+		}
+		
+		return $str;
+	}
+
+}
+// END Input class
+?>
\ No newline at end of file
diff --git a/system/libraries/Language.php b/system/libraries/Language.php
new file mode 100644
index 0000000..b668aa0
--- /dev/null
+++ b/system/libraries/Language.php
@@ -0,0 +1,113 @@
+<?php  if (!defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * Code Igniter
+ *
+ * An open source application development framework for PHP 4.3.2 or newer
+ *
+ * @package		CodeIgniter
+ * @author		Rick Ellis
+ * @copyright	Copyright (c) 2006, pMachine, Inc.
+ * @license		http://www.codeignitor.com/user_guide/license.html 
+ * @link		http://www.codeigniter.com
+ * @since		Version 1.0
+ * @filesource
+ */
+ 
+// ------------------------------------------------------------------------
+
+/**
+ * Language Class
+ * 
+ * @package		CodeIgniter
+ * @subpackage	Libraries
+ * @category	Language
+ * @author		Rick Ellis
+ * @link		http://www.codeigniter.com/user_guide/libraries/language.html
+ */
+class CI_Language {
+
+	var $language	= array();
+	var $is_loaded	= array();
+
+	/**
+	 * Constructor 
+	 *
+	 * @access	public
+	 */	
+	function CI_Language()
+	{
+		log_message('debug', "Language Class Initialized");
+	}
+	// END CI_Language()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Load a language file
+	 *
+	 * @access	public
+	 * @param	mixed	the name of the language file to be loaded. Can be an array
+	 * @param	string	the language (english, etc.)
+	 * @return	void
+	 */
+	function load($langfile = '', $idiom = '', $return = FALSE)
+	{	
+		$langfile = str_replace(EXT, '', str_replace('_lang.', '', $langfile)).'_lang'.EXT;
+		
+		if (in_array($langfile, $this->is_loaded))
+		{
+			return;
+		}
+		
+		if ($idiom == '')
+		{
+			$obj =& get_instance();
+			$deft_lang = $obj->config->item('language');
+			$idiom = ($deft_lang == '') ? 'english' : $deft_lang;
+		}
+	
+		if ( ! file_exists(BASEPATH.'language/'.$idiom.'/'.$langfile))
+		{
+			show_error('Unable to load the requested language file: language/'.$langfile.EXT);
+		}
+
+		include_once(BASEPATH.'language/'.$idiom.'/'.$langfile);
+		            
+		if ( ! isset($lang))
+		{
+			log_message('error', 'Language file contains no data: language/'.$idiom.'/'.$langfile);
+			return;
+		}
+		
+		if ($return == TRUE)
+		{
+			return $lang;
+		}
+		
+		$this->is_loaded[] = $langfile;
+		$this->language = array_merge($this->language, $lang);
+		unset($lang);
+		
+		log_message('debug', 'Language file loaded: language/'.$idiom.'/'.$langfile);
+		return TRUE;
+	}
+	// END load()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Fetch a single line of text from the language array
+	 *
+	 * @access	public
+	 * @param	string	the language line
+	 * @return	string
+	 */
+	function line($line = '')
+	{
+		return ($line == '' OR ! isset($this->language[$line])) ? FALSE : $this->language[$line];
+	}
+	// END line()
+
+}
+// END Language Class
+?>
\ No newline at end of file
diff --git a/system/libraries/Loader.php b/system/libraries/Loader.php
new file mode 100644
index 0000000..e2467fa
--- /dev/null
+++ b/system/libraries/Loader.php
@@ -0,0 +1,611 @@
+<?php  if (!defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * Code Igniter
+ *
+ * An open source application development framework for PHP 4.3.2 or newer
+ *
+ * @package		CodeIgniter
+ * @author		Rick Ellis
+ * @copyright	Copyright (c) 2006, pMachine, Inc.
+ * @license		http://www.codeignitor.com/user_guide/license.html 
+ * @link		http://www.codeigniter.com
+ * @since		Version 1.0
+ * @filesource
+ */
+ 
+// ------------------------------------------------------------------------
+
+/**
+ * Loader Class
+ * 
+ * Loads views and files
+ *
+ * @package		CodeIgniter
+ * @subpackage	Libraries
+ * @author		Rick Ellis
+ * @category	Loader
+ * @link		http://www.codeigniter.com/user_guide/libraries/loader.html
+ */
+class CI_Loader {
+
+	var $ob_level;
+	var $cached_vars	= array();
+	var $helpers		= array();
+	var $plugins		= array();
+	var $scripts		= array();
+	var $languages		= array();
+	var $view_path		= '';
+
+	/**
+	 * Constructor
+	 *
+	 * Sets the path to the view files and gets the initial output
+	 * buffering level
+	 *
+	 * @access	public
+	 */
+	function CI_Loader()
+	{
+		$this->view_path = APPPATH.'views/';
+		$this->ob_level = ob_get_level();
+				
+		log_message('debug', "Loader Class Initialized");
+	}
+	// END CI_Loader()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Class Loader
+	 *
+	 * This function lets users load and instantiate classes.
+	 * It is designed to be called from a user's app controllers.
+	 *
+	 * @access	public
+	 * @param	string	the name of the class
+	 * @param	mixed	any initialization parameters
+	 * @return	void
+	 */	
+	function library($class, $param = FALSE)
+	{		
+		if ($class == '')
+			return;
+	
+		$obj =& get_instance();
+		$obj->_ci_initialize($class, $param);
+		$obj->_ci_assign_to_models();
+	}
+	// END library()
+
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Model Loader
+	 *
+	 * This function lets users load and instantiate models.
+	 *
+	 * @access	public
+	 * @param	string	the name of the class
+	 * @param	mixed	any initialization parameters
+	 * @return	void
+	 */	
+	function model($model, $name = '', $db_conn = FALSE)
+	{		
+		if ($model == '')
+			return;
+	
+		$obj =& get_instance();
+		$obj->_ci_load_model($model, $name, $db_conn);
+	}
+	// END library()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Database Loader
+	 *
+	 * @access	public
+	 * @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)
+	 * @return	mixed
+	 */	
+	function database($db = '', $return = FALSE, $active_record = FALSE)
+	{
+		$obj =& get_instance();
+	
+		if ($return === TRUE)
+		{
+			return $obj->_ci_init_database($db, TRUE, $active_record);
+		}
+		else
+		{
+			$obj->_ci_init_database($db, FALSE, $active_record);
+			$obj->_ci_assign_to_models();			
+		}
+	}
+	// END database()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Scaffolding Loader
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	void
+	 */	
+	function scaffolding($table = '')
+	{		
+		if ($table == FALSE)
+		{
+			show_error('You must include the name of the table you would like access when you initialize scaffolding');
+		}
+		
+		$obj =& get_instance();
+		$obj->_ci_init_scaffolding($table);
+	}
+	// END scaffolding()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Load View
+	 *
+	 * 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 retun data so that
+	 * a developer can process it in some way.
+	 *
+	 * @access	public
+	 * @param	string
+	 * @param	array
+	 * @param	bool
+	 * @return	void
+	 */
+	function view($view, $vars = array(), $return = FALSE)
+	{
+		return $this->_ci_load(array('view' => $view, 'vars' => $this->_ci_object_to_array($vars), 'return' => $return));
+	}
+	// END view()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Load File
+	 *
+	 * This is a generic file loader
+	 *
+	 * @access	public
+	 * @param	string
+	 * @param	bool
+	 * @return	string
+	 */
+	function file($path, $return = FALSE)
+	{
+		return $this->_ci_load(array('path' => $path, 'return' => $return));
+	}
+	// END file()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Set Variables
+	 *
+	 * Once variables are set they become availabe within
+	 * the controller class and its "view" files.
+	 *
+	 * @access	public
+	 * @param	array
+	 * @return	void
+	 */
+	function vars($vars = array())
+	{
+		$vars = $this->_ci_object_to_array($vars);
+	
+		if (is_array($vars) AND count($vars) > 0)
+		{
+			foreach ($vars as $key => $val)
+			{
+				$this->cached_vars[$key] = $val;
+			}
+		}
+	}
+	// END vars()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Load Helper
+	 *
+	 * This function loads the specified helper file.
+	 *
+	 * @access	public
+	 * @param	mixed
+	 * @return	void
+	 */
+	function helper($helpers = array())
+	{
+		if ( ! is_array($helpers))
+		{
+			$helpers = array($helpers);
+		}
+	
+		foreach ($helpers as $helper)
+		{
+			if (isset($this->helpers[$helper]))
+			{
+				continue;
+			}
+		
+			$helper = strtolower(str_replace(EXT, '', str_replace('_helper', '', $helper)).'_helper');
+		
+			if ( ! file_exists(BASEPATH.'helpers/'.$helper.EXT))
+			{
+				show_error('Unable to load the requested file: helpers/'.$helper.EXT);
+			}
+			
+			include_once(BASEPATH.'helpers/'.$helper.EXT);
+
+			$this->helpers[$helper] = TRUE;
+		}
+		
+		log_message('debug', 'Helpers loaded: '.implode(', ', $helpers));
+	}
+	// END helper()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Load Helpers
+	 *
+	 * This is simply an alias to the above function in case the
+	 * user has written the plural form of this function.
+	 *
+	 * @access	public
+	 * @param	array
+	 * @return	void
+	 */
+	function helpers($helpers = array())
+	{
+		$this->helper($helpers);
+	}
+	// END helpers()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Load Plugin
+	 *
+	 * This function loads the specified plugin.
+	 *
+	 * @access	public
+	 * @param	array
+	 * @return	void
+	 */
+	function plugin($plugins = array())
+	{
+		if ( ! is_array($plugins))
+		{
+			$plugins = array($plugins);
+		}
+	
+		foreach ($plugins as $plugin)
+		{
+			if (isset($this->plugins[$plugin]))
+			{
+				continue;
+			}
+	
+			$plugin = strtolower(str_replace(EXT, '', str_replace('_plugin.', '', $plugin)).'_pi');
+		
+			if ( ! file_exists(BASEPATH.'plugins/'.$plugin.EXT))
+			{
+				show_error('Unable to load the requested file: plugins/'.$plugin.EXT);
+			}
+			
+			include_once(BASEPATH.'plugins/'.$plugin.EXT);	
+			
+			$this->plugins[$plugin] = TRUE;
+		}
+		
+		log_message('debug', 'Plugins loaded: '.implode(', ', $plugins));
+	}
+	// END plugin()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Load Script
+	 *
+	 * This function loads the specified include file from the
+	 * application/scripts/ folder
+	 *
+	 * @access	public
+	 * @param	array
+	 * @return	void
+	 */
+	function script($scripts = array())
+	{
+		if ( ! is_array($scripts))
+		{
+			$scripts = array($scripts);
+		}
+	
+		foreach ($scripts as $script)
+		{
+			if (isset($this->scripts[$script]))
+			{
+				continue;
+			}
+	
+			$script = strtolower(str_replace(EXT, '', $script));
+		
+			if ( ! file_exists(APPPATH.'scripts/'.$script.EXT))
+			{
+				show_error('Unable to load the requested script: scripts/'.$script.EXT);
+			}
+			
+			include_once(APPPATH.'scripts/'.$script.EXT);
+			
+			$this->scripts[$script] = TRUE;
+		}
+		
+		log_message('debug', 'Scripts loaded: '.implode(', ', $scripts));
+	}
+	// END script()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Load Plugins
+	 *
+	 * This is simply an alias to the above function in case the
+	 * user has written the plural form of this function.
+	 *
+	 * @access	public
+	 * @param	array
+	 * @return	void
+	 */
+	function plugins($plugins = array())
+	{
+		$this->plugin($plugins);
+	}
+	// END plugins()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Loads a language file
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	void
+	 */
+	function language($file = '', $lang = '', $return = FALSE)
+	{
+		$obj =& get_instance();
+		return $obj->lang->load($file, $lang, $return);
+	}
+	// END language()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Loads a config file
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	void
+	 */
+	function config($file = '')
+	{
+		$obj =& get_instance();
+		$obj->config->load($file);
+	}
+	// END config()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Set the Path to the "views" folder
+	 *
+	 * @access	private
+	 * @param	string
+	 * @return	void
+	 */
+	function _ci_set_view_path($path)
+	{
+		$this->view_path = $path;
+	}
+	// END _ci_set_view_path()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Loader
+	 *
+	 * This function isn't called directly.  It's called from
+	 * the two functions above.  It's used to load views and files
+	 *
+	 * @access	private
+	 * @param	array
+	 * @return	void
+	 */
+	function _ci_load($data)
+	{	
+		$OUT =& _load_class('CI_Output');
+
+		// This allows anything loaded using $this->load (viwes, files, etc.)
+		// to become accessible from within the Controller and Model functions.
+		$obj =& get_instance();
+		foreach ($obj->ci_is_loaded as $val)
+		{
+			if ( ! isset($this->$val))
+			{
+				$this->$val =& $obj->$val;
+			}	
+		}		
+		
+		// Set the default data variables
+		foreach (array('view', 'vars', 'path', 'return') as $val)
+		{
+			$$val = ( ! isset($data[$val])) ? FALSE : $data[$val];
+		}
+		
+		/*
+		 * Extract and cached variables
+		 *
+		 * You can either set variables using the dedicated
+		 * $this->load_vars() function or via the second
+		 * parameter of this function. We'll
+		 * merge the two types and cache them so that
+		 * views that are embedded within other views
+		 * can have access to these variables.
+		 *
+		 */	
+		
+		if (is_array($vars))
+		{
+			$this->cached_vars = array_merge($this->cached_vars, $vars);
+		}
+		extract($this->cached_vars);
+				
+		// Set the path to the requested file
+		if ($path == '')
+		{
+			$ext = pathinfo($view, PATHINFO_EXTENSION);
+			$file = ($ext == '') ? $view.EXT : $view;
+			$path = $this->view_path.$file;
+		}
+		else
+		{
+			$x = explode('/', $path);
+			$file = end($x);
+		}
+
+		/*
+		 * Buffer the output
+		 *
+		 * We buffer the output for two reasons:
+		 * 1. Speed. You get a significant speed boost.
+		 * 2. So that the final rendered template can be 
+		 * post-processed by the output class.  Why do we
+		 * need post processing?  For one thing, in order to 
+		 * show the elapsed page load time.  Unless we
+		 * can intercept the content right before it's sent to
+		 * the browser and then stop the timer, it won't be acurate.
+		 *
+		 */
+
+		if ( ! file_exists($path))
+		{
+			show_error('Unable to load the requested file: '.$file);
+		}
+
+		ob_start();
+		
+		include($path);
+		log_message('debug', 'File loaded: '.$path);
+		
+		// Return the file data if requested to
+		if ($return === TRUE)
+		{		
+			$buffer = ob_get_contents();
+			ob_end_clean(); 
+			
+			return $buffer;
+		}
+
+		/*
+		 * Flush the buffer... or buff the flusher?
+		 *
+		 * In order to permit templates (views) to be nested within
+		 * other views, we need to flush the content back out whenever 
+		 * we are beyond the first level of output buffering so that 
+		 * it can be seen and included  properly by the first included 
+		 * template and any subsequent ones. Oy!
+		 *
+		 */		
+		if (ob_get_level() > $this->ob_level + 1)
+		{
+			ob_end_flush();
+		}
+		else
+		{
+			$OUT->set_output(ob_get_contents());
+			ob_end_clean();
+		}
+	}
+	// END _load()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Autoloader
+	 *
+	 * The config/autoload.php file contains an array that permits sub-systems, 
+	 * plugins, and helpers to be loaded automatically.
+	 *
+	 * @access	private
+	 * @param	array
+	 * @return	void
+	 */
+	function _ci_autoloader($autoload)
+	{
+		if ($autoload === FALSE)
+		{
+			return;
+		}
+	
+		foreach (array('helper', 'plugin', 'script') as $type)
+		{
+			if (isset($autoload[$type]))
+			{
+				if ( ! is_array($autoload[$type]))
+				{
+					$autoload[$type] = array($autoload[$type]);
+				}
+			
+				foreach ($autoload[$type] as $item)
+				{
+					$this->$type($item);
+				}
+			}
+		}
+	}
+	// END _ci_autoloader()
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Object to Array
+	 *
+	 * Takes an object as input and convers the class variables to array key/vals
+	 *
+	 * @access	public
+	 * @param	object
+	 * @return	array
+	 */
+	function _ci_object_to_array($object)
+	{
+		if ( ! is_object($object))
+		{
+			return $object;
+		}
+		
+		$array = array();
+		foreach (get_object_vars($object) as $key => $val)
+		{
+			$array[$key] = $val;
+		}
+	
+		return $array;
+	}
+	
+}
+// END Loader Class
+?>
\ No newline at end of file
diff --git a/system/libraries/Log.php b/system/libraries/Log.php
new file mode 100644
index 0000000..35e30b6
--- /dev/null
+++ b/system/libraries/Log.php
@@ -0,0 +1,117 @@
+<?php  if (!defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * Code Igniter
+ *
+ * An open source application development framework for PHP 4.3.2 or newer
+ *
+ * @package		CodeIgniter
+ * @author		Rick Ellis
+ * @copyright	Copyright (c) 2006, pMachine, Inc.
+ * @license		http://www.codeignitor.com/user_guide/license.html 
+ * @link		http://www.codeigniter.com
+ * @since		Version 1.0
+ * @filesource
+ */
+ 
+// ------------------------------------------------------------------------
+
+/**
+ * Logging Class
+ * 
+ * @package		CodeIgniter
+ * @subpackage	Libraries
+ * @category	Logging
+ * @author		Rick Ellis
+ * @link		http://www.codeigniter.com/user_guide/general/errors.html
+ */
+class CI_Log {
+
+	var $log_path;
+	var $_threshold	= 1;
+	var $_date_fmt	= 'Y-m-d H:i:s';
+	var $_enabled	= TRUE;
+	var $_levels	= array('ERROR' => '1', 'DEBUG' => '2',  'INFO' => '3', 'ALL' => '4');
+
+	/**
+	 * Constructor
+	 *
+	 * @access	public
+	 * @param	string	the log file path
+	 * @param	string	the error threshold
+	 * @param	string	the date formatting codes
+	 */
+	function CI_Log($path = '', $threshold = '', $date_fmt = '')
+	{	
+		$this->log_path = ($path != '') ? $path : BASEPATH.'logs/';
+
+		if ( ! is_dir($this->log_path) OR ! is_writable($this->log_path))
+		{
+			$this->_enabled = FALSE;
+		}
+		
+		if (ctype_digit($threshold))
+		{
+			$this->_threshold = $threshold;
+		}
+			
+		if ($date_fmt != '')
+		{
+			$this->_date_fmt = $date_fmt;
+		}
+	}
+	// END CI_Log()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Write Log File
+	 *
+	 * Generally this function will be called using the global log_message() function
+	 *
+	 * @access	public
+	 * @param	string	the error level
+	 * @param	string	the error message
+	 * @param	bool	whether the error is a native PHP error
+	 * @return	bool
+	 */		
+	function write_log($level = 'error', $msg, $php_error = FALSE)
+	{		
+		if ($this->_enabled === FALSE)
+		{
+			return FALSE;
+		}
+	
+		$level = strtoupper($level);
+		
+		if ( ! isset($this->_levels[$level]) OR ($this->_levels[$level] > $this->_threshold))
+		{
+			return FALSE;
+		}
+	
+		$filepath = $this->log_path.'log-'.date('Y-m-d').'.php';
+		$message  = '';
+		
+		if ( ! file_exists($filepath))
+		{
+			$message .= "<"."?php  if (!defined('BASEPATH')) exit('No direct script access allowed'); ?".">\n\n";
+		}
+			
+		if ( ! $fp = @fopen($filepath, "a"))
+		{
+			return FALSE;
+		}
+
+		$message .= $level.' '.(($level == 'INFO') ? ' -' : '-').' '.date($this->_date_fmt). ' --> '.$msg."\n";
+		
+		flock($fp, LOCK_EX);	
+		fwrite($fp, $message);
+		flock($fp, LOCK_UN);
+		fclose($fp);
+	
+		@chmod($filepath, 0666); 		
+		return TRUE;
+	}
+	// END write_log()
+}
+// END Log Class
+?>
\ No newline at end of file
diff --git a/system/libraries/Model.php b/system/libraries/Model.php
new file mode 100644
index 0000000..9834f82
--- /dev/null
+++ b/system/libraries/Model.php
@@ -0,0 +1,72 @@
+<?php  if (!defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * Code Igniter
+ *
+ * An open source application development framework for PHP 4.3.2 or newer
+ *
+ * @package		CodeIgniter
+ * @author		Rick Ellis
+ * @copyright	Copyright (c) 2006, pMachine, Inc.
+ * @license		http://www.codeignitor.com/user_guide/license.html 
+ * @link		http://www.codeigniter.com
+ * @since		Version 1.0
+ * @filesource
+ */
+ 
+// ------------------------------------------------------------------------
+
+/**
+ * Code Igniter Model Class
+ *
+ * @package		CodeIgniter
+ * @subpackage	Libraries
+ * @category	Libraries
+ * @author		Rick Ellis
+ * @link		http://www.codeigniter.com/user_guide/libraries/config.html
+ */
+class Model {
+
+	/**
+	 * Constructor
+	 *
+	 * @access public
+	 */
+	function Model()
+	{
+		$this->_assign_libraries(FALSE);
+		log_message('debug', "Model Class Initialized");
+	}
+	// END Model()
+
+	/**
+	 * Assign Libraries
+	 *
+	 * Creates local references to all currently instantiated objects
+	 * so that any syntax that can be legally used in a controller 
+	 * can be used within models.
+	 *
+	 * @access private
+	 */	
+	function _assign_libraries($use_reference = TRUE)
+	{
+		$obj =& get_instance();
+		foreach ($obj->ci_is_loaded as $val)
+		{
+			if ( ! isset($this->$val))
+			{
+				if ($use_reference === TRUE)
+				{
+					$this->$val =& $obj->$val;
+				}
+				else
+				{
+					$this->$val = $obj->$val;
+				}
+			}
+		}
+	}
+	// END _assign_libraries()
+
+}
+// END Model Class
+?>
\ No newline at end of file
diff --git a/system/libraries/Output.php b/system/libraries/Output.php
new file mode 100644
index 0000000..f5db3e0
--- /dev/null
+++ b/system/libraries/Output.php
@@ -0,0 +1,241 @@
+<?php  if (!defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * Code Igniter
+ *
+ * An open source application development framework for PHP 4.3.2 or newer
+ *
+ * @package		CodeIgniter
+ * @author		Rick Ellis
+ * @copyright	Copyright (c) 2006, pMachine, Inc.
+ * @license		http://www.codeignitor.com/user_guide/license.html 
+ * @link		http://www.codeigniter.com
+ * @since		Version 1.0
+ * @filesource
+ */
+ 
+// ------------------------------------------------------------------------
+
+/**
+ * Output Class
+ *
+ * Responsible for sending final output to browser
+ * 
+ * @package		CodeIgniter
+ * @subpackage	Libraries
+ * @category	Output
+ * @author		Rick Ellis
+ * @link		http://www.codeigniter.com/user_guide/libraries/output.html
+ */
+class CI_Output {
+
+	var $final_output;
+	var $cache_expiration = 0;
+
+	function CI_Output()
+	{
+		log_message('debug', "Output Class Initialized");
+	}
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Get Output 
+	 *
+	 * Returns the current output string
+	 *
+	 * @access	public
+	 * @return	string
+	 */	
+	function get_output()
+	{
+		return $this->final_output;
+	}
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Set Output 
+	 *
+	 * Sets the output string
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	void
+	 */	
+	function set_output($output)
+	{
+		$this->final_output = $output;
+	}
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Set Cache 
+	 *
+	 * @access	public
+	 * @param	integer
+	 * @return	void
+	 */	
+	function cache($time)
+	{
+		$this->cache_expiration = ( ! ctype_digit($time)) ? 0 : $time;
+	}
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Display Output
+	 *
+	 * All "view" data is automatically put into this variable 
+	 * by the controller class:
+	 *
+	 * $this->final_output
+	 *
+	 * This function simply echos the variable out.  It also does the following:
+	 * 
+	 * Stops the benchmark timer so the page rendering speed can be shown.
+	 *
+	 * Determines if the "memory_get_usage' function is available so that 
+	 * the memory usage can be shown.
+	 *
+	 * @access	public
+	 * @return	void
+	 */		
+	function _display($output = '')
+	{	
+		$BM =& _load_class('CI_Benchmark');
+		
+		if ($output == '')
+		{
+			$output =& $this->final_output;
+		}
+		
+		if ($this->cache_expiration > 0)
+		{
+			$this->_write_cache($output);
+		}
+
+		$elapsed = $BM->elapsed_time('code_igniter_start', 'code_igniter_end');		
+		$memory	 = ( ! function_exists('memory_get_usage')) ? '0' : round(memory_get_usage()/1024/1024, 2).'MB';
+
+		$output = str_replace('{memory_usage}', $memory, $output);		
+		$output = str_replace('{elapsed_time}', $elapsed, $output);
+		
+		echo $output;
+		
+		log_message('debug', "Final output sent to browser");
+		log_message('debug', "Total execution time: ".$elapsed);		
+	}
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Write a Cache File 
+	 *
+	 * @access	public
+	 * @return	void
+	 */	
+	function _write_cache($output)
+	{
+		$obj =& get_instance();	
+		$path = $obj->config->item('cache_path');
+	
+		$cache_path = ($path == '') ? BASEPATH.'cache/' : $path;
+		
+		if ( ! is_dir($cache_path) OR ! is_writable($cache_path))
+		{
+			return;
+		}
+		
+		$uri =	$obj->config->item('base_url', 1).
+				$obj->config->item('index_page').
+				$obj->uri->uri_string();
+		
+		$cache_path .= md5($uri);
+
+        if ( ! $fp = @fopen($cache_path, 'wb'))
+        {
+			log_message('error', "Unable to write ache file: ".$cache_path);
+            return;
+		}
+		
+		$expire = time() + ($this->cache_expiration * 60);
+		
+        flock($fp, LOCK_EX);
+        fwrite($fp, $expire.'TS--->'.$output);
+        flock($fp, LOCK_UN);
+        fclose($fp);
+		@chmod($cache_path, 0777); 
+
+		log_message('debug', "Cache file written: ".$cache_path);
+	}
+
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Update/serve a cached file 
+	 *
+	 * @access	public
+	 * @return	void
+	 */	
+	function _display_cache()
+	{
+		$CFG =& _load_class('CI_Config');
+		$RTR =& _load_class('CI_Router');
+	
+		$cache_path = ($CFG->item('cache_path') == '') ? BASEPATH.'cache/' : $CFG->item('cache_path');
+			
+		if ( ! is_dir($cache_path) OR ! is_writable($cache_path))
+		{
+			return FALSE;
+		}
+		
+		// Build the file path.  The file name is an MD5 hash of the full URI
+		$uri = $CFG->item('base_url', 1).$CFG->item('index_page').$RTR->uri_string;
+		
+		$filepath = $cache_path.md5($uri);
+		
+		if ( ! @file_exists($filepath))
+		{
+			return FALSE;
+		}
+	
+		if ( ! $fp = @fopen($filepath, 'rb'))
+		{
+			return FALSE;
+		}
+			
+		flock($fp, LOCK_SH);
+		
+		$cache = '';
+		if (filesize($filepath) > 0) 
+		{
+			$cache = fread($fp, filesize($filepath)); 
+		}
+	
+		flock($fp, LOCK_UN);
+		fclose($fp); 
+					
+		// Strip out the embedded timestamp		
+		if ( ! preg_match("/(\d+TS--->)/", $cache, $match))
+		{
+			return FALSE;
+		}
+		
+		// Has the file expired? If so we'll delete it.
+		if (time() >= trim(str_replace('TS--->', '', $match['1'])))
+		{ 		
+			@unlink($filepath);
+			log_message('debug', "Cache file has expired. File deleted");
+			return FALSE;
+		}
+
+		// Display the cache
+		$this->_display(str_replace($match['0'], '', $cache));
+		log_message('debug', "Cache file is current. Sending it to browser.");		
+		return TRUE;
+	}
+
+}
+// END Output Class
+?>
\ No newline at end of file
diff --git a/system/libraries/Pagination.php b/system/libraries/Pagination.php
new file mode 100644
index 0000000..0bbb577
--- /dev/null
+++ b/system/libraries/Pagination.php
@@ -0,0 +1,207 @@
+<?php  if (!defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * Code Igniter
+ *
+ * An open source application development framework for PHP 4.3.2 or newer
+ *
+ * @package		CodeIgniter
+ * @author		Rick Ellis
+ * @copyright	Copyright (c) 2006, pMachine, Inc.
+ * @license		http://www.codeignitor.com/user_guide/license.html 
+ * @link		http://www.codeigniter.com
+ * @since		Version 1.0
+ * @filesource
+ */
+ 
+// ------------------------------------------------------------------------
+
+/**
+ * Pagination Class
+ *
+ * @package		CodeIgniter
+ * @subpackage	Libraries
+ * @category	Pagination
+ * @author		Rick Ellis
+ * @link		http://www.codeigniter.com/user_guide/libraries/pagination.html
+ */
+class CI_Pagination {
+
+	var $base_url			= ''; // The page we are linking to
+	var $total_rows  		= ''; // Total number of items (database results)
+	var $per_page     		= 10; // Max number of items you want shown per page
+	var $num_links    		=  2; // Number of "digit" links to show before/after the currently viewed page
+	var $cur_page     		=  0; // The current page being viewed
+	var $first_link   		= '&lsaquo; First';
+	var $next_link			= '&gt;';
+	var $prev_link			= '&lt;';
+	var $last_link    		= 'Last &rsaquo;';
+	var $uri_segment		= 3;
+	var $full_tag_open		= '';
+	var $full_tag_close		= '';
+	var $first_tag_open		= '';
+	var $first_tag_close	= '&nbsp;';
+	var $last_tag_open		= '&nbsp;';
+	var $last_tag_close		= '';
+	var $cur_tag_open		= '&nbsp;<b>';
+	var $cur_tag_close		= '</b>';
+	var $next_tag_open		= '&nbsp;';
+	var $next_tag_close		= '&nbsp;';
+	var $prev_tag_open		= '&nbsp;';
+	var $prev_tag_close		= '';
+	var $num_tag_open		= '&nbsp;';
+	var $num_tag_close		= '';
+
+	/**
+	 * Constructor
+	 *
+	 * @access	public
+	 * @param	array	initialization parameters
+	 */
+    function CI_Pagination($params = array())
+    {    
+		if (count($params) > 0)
+		{
+			$this->initialize($params);		
+		}
+		
+		log_message('debug', "Pagination Class Initialized");
+    }
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Initialize Preferences
+	 *
+	 * @access	public
+	 * @param	array	initialization parameters
+	 * @return	void
+	 */
+    function initialize($params = array())
+    {    
+		if (count($params) > 0)
+		{
+			foreach ($params as $key => $val)
+			{
+				if (isset($this->$key))
+				{
+					$this->$key = $val;
+				}
+			}		
+		}
+    }
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Generate the pagination links
+	 *
+	 * @access	public
+	 * @return	string
+	 */	
+    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)
+        {
+           return '';
+    	}
+    	
+		// Calculate the total number of pages
+        $num_pages = intval($this->total_rows / $this->per_page);
+        
+		// Use modulus to see if our division has a remainder.If so, add one to our page number.
+        if ($this->total_rows % $this->per_page) 
+        {
+            $num_pages++;
+        }
+ 
+		// Is there only one page? Hm... nothing more to do here then. 
+        if ($num_pages == 1)
+        {
+            return '';
+        }
+        
+		// Determine the current page number.		
+		$obj =& get_instance();	
+		if ($obj->uri->segment($this->uri_segment) != 0)
+		{
+			$this->cur_page = $obj->uri->segment($this->uri_segment);
+		}
+		
+		if ( ! ctype_digit($this->cur_page))
+		{
+			$this->cur_page = 0;
+		}
+		
+		$uri_page_number = $this->cur_page;
+		$this->cur_page = floor(($this->cur_page/$this->per_page) + 1);
+   
+		// Calculate the start and end numbers. These determine
+		// which number to start and end the digit links with
+        $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;
+        
+		// Add a trailing slash to the base URL if needed
+		$this->base_url = preg_replace("/(.+?)\/*$/", "\\1/",  $this->base_url);
+		
+  		// And here we go...
+        $output = '';
+ 
+		// Render the "First" link
+        if  ($this->cur_page > $this->num_links)
+        {
+            $output .= $this->first_tag_open.'<a href="'.$this->base_url.'">'.$this->first_link.'</a>'.$this->first_tag_close;
+        }
+ 
+		// Render the "previous" link
+        if  (($this->cur_page - $this->num_links) >= 0)
+        {
+        	$i = $uri_page_number - $this->per_page;  
+        	if ($i == 0) $i = '';
+            $output .= $this->prev_tag_open.'<a href="'.$this->base_url.$i.'">'.$this->prev_link.'</a>'.$this->prev_tag_close;
+        }
+        
+		// Write the digit links
+        for ($loop = $start -1; $loop <= $end; $loop++) 
+        {
+			$i = ($loop * $this->per_page) - $this->per_page;
+					
+			if ($i >= 0)
+			{
+				if ($this->cur_page == $loop)
+				{
+					$output .= $this->cur_tag_open.$loop.$this->cur_tag_close; // Current page
+				}
+				else
+				{
+					$n = ($i == 0) ? '' : $i;
+					$output .= $this->num_tag_open.'<a href="'.$this->base_url.$n.'">'.$loop.'</a>'.$this->num_tag_close;
+				}
+			}
+        } 
+
+		// Render the "next" link
+        if ($this->cur_page < $num_pages)
+        {  
+            $output .= $this->next_tag_open.'<a href="'.$this->base_url.($this->cur_page * $this->per_page).'">'.$this->next_link.'</a>'.$this->next_tag_close;        
+        }
+
+		// Render the "Last" link
+        if (($this->cur_page + $this->num_links) < $num_pages)
+        {
+            $i = (($num_pages * $this->per_page) - $this->per_page);
+            $output .= $this->last_tag_open.'<a href="'.$this->base_url.$i.'">'.$this->last_link.'</a>'.$this->last_tag_close;
+        }
+    
+		// Kill double slashes.  Note: Sometimes we can end up with a double slash 
+		// in the penultimate link so we'll kill all double shashes.
+		$output = preg_replace("#([^:])//+#", "\\1/", $output);  
+
+		// Add the wrapper HTML if exists
+		$output = $this->full_tag_open.$output.$this->full_tag_close;
+		
+		return $output;		
+    }
+}
+// END Pagination Class
+?>
\ No newline at end of file
diff --git a/system/libraries/Parser.php b/system/libraries/Parser.php
new file mode 100644
index 0000000..9f6a814
--- /dev/null
+++ b/system/libraries/Parser.php
@@ -0,0 +1,178 @@
+<?php  if (!defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * Code Igniter
+ *
+ * An open source application development framework for PHP 4.3.2 or newer
+ *
+ * @package		CodeIgniter
+ * @author		Rick Ellis
+ * @copyright	Copyright (c) 2006, pMachine, Inc.
+ * @license		http://www.codeignitor.com/user_guide/license.html 
+ * @link		http://www.codeigniter.com
+ * @since		Version 1.0
+ * @filesource
+ */
+ 
+// ------------------------------------------------------------------------
+
+/**
+ * Parser Class
+ * 
+ * @package		CodeIgniter
+ * @subpackage	Libraries
+ * @category	Parser
+ * @author		Rick Ellis
+ * @link		http://www.codeigniter.com/user_guide/libraries/parser.html
+ */
+class CI_Parser {
+
+	var $l_delim = '{';
+	var $r_delim = '}';
+	var $object;
+		
+	/**
+	 *  Parse a template
+	 *
+	 * Parses pseudo-variables contained in the specified template, 
+	 * replacing them with the data in the second param
+	 *
+	 * @access	public
+	 * @param	string
+	 * @param	array
+	 * @param	bool
+	 * @return	string
+	 */
+	function parse($template, $data, $return = FALSE)
+	{
+		$OUT =& _load_class('CI_Output');
+
+		$obj =& get_instance();
+		$template = $obj->load->view($template, '', TRUE);
+		
+		if ($template == '')
+		{
+			return FALSE;
+		}
+		
+		foreach ($data as $key => $val)
+		{
+			if ( ! is_array($val))
+			{
+				$template = $this->_parse_single($key, $val, $template);
+			}
+			else
+			{
+				$template = $this->_parse_pair($key, $val, $template);		
+			}
+		}
+		
+		if ($return == FALSE)
+		{
+			$OUT->final_output = $template;
+		}
+		
+		return $template;
+	}
+	// END set_method()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 *  Set the left/right variable delimiters
+	 *
+	 * @access	public
+	 * @param	string
+	 * @param	string
+	 * @return	void
+	 */
+	function set_delimiters($l = '{', $r = '}')
+	{
+		$this->l_delim = $l;
+		$this->r_delim = $r;
+	}
+	// END set_method()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 *  Parse a single key/value
+	 *
+	 * @access	private
+	 * @param	string
+	 * @param	string
+	 * @param	string
+	 * @return	string
+	 */
+	function _parse_single($key, $val, $string)
+	{
+		return str_replace($this->l_delim.$key.$this->r_delim, $val, $string);
+	}
+	// END set_method()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 *  Parse a tag pair
+	 *
+	 * Parses tag pairs:  {some_tag} string... {/some_tag}
+	 *
+	 * @access	private
+	 * @param	string
+	 * @param	array
+	 * @param	string
+	 * @return	string
+	 */
+	function _parse_pair($variable, $data, $string)
+	{	
+		if (FALSE === ($match = $this->_match_pair($string, $variable)))
+		{
+			return $string;
+		}
+
+		$str = '';
+		foreach ($data as $row)
+		{
+			$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);
+				}
+			}
+			
+			$str .= $temp;
+		}
+		
+		return str_replace($match['0'], $str, $string);
+	}
+	// END set_method()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 *  Matches a variable pair
+	 *
+	 * @access	private
+	 * @param	string
+	 * @param	string
+	 * @return	mixed
+	 */
+	function _match_pair($string, $variable)
+	{
+		if ( ! preg_match("|".$this->l_delim . $variable . $this->r_delim."(.+)".$this->l_delim . '/' . $variable . $this->r_delim."|s", $string, $match))
+		{
+			return FALSE;
+		}
+		
+		return $match;
+	}
+	// END _match_pair()
+
+}
+// END Parser Class
+?>
\ No newline at end of file
diff --git a/system/libraries/Router.php b/system/libraries/Router.php
new file mode 100644
index 0000000..abc253e
--- /dev/null
+++ b/system/libraries/Router.php
@@ -0,0 +1,318 @@
+<?php  if (!defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * Code Igniter
+ *
+ * An open source application development framework for PHP 4.3.2 or newer
+ *
+ * @package		CodeIgniter
+ * @author		Rick Ellis
+ * @copyright	Copyright (c) 2006, pMachine, Inc.
+ * @license		http://www.codeignitor.com/user_guide/license.html 
+ * @link		http://www.codeigniter.com
+ * @since		Version 1.0
+ * @filesource
+ */
+ 
+// ------------------------------------------------------------------------
+
+/**
+ * Router Class
+ * 
+ * Parses URIs and determines routing
+ *
+ * @package		CodeIgniter
+ * @subpackage	Libraries
+ * @author		Rick Ellis
+ * @category	Libraries
+ * @link		http://www.codeigniter.com/user_guide/general/routing.html
+ */
+class CI_Router {
+
+	var $config;
+	var $uri_string		= '';
+	var $segments		= array();
+	var $routes 		= array();
+	var $class			= '';
+	var $method			= 'index';
+	var $uri_protocol 	= 'auto';
+	var $default_controller;
+	var $scaffolding_request = FALSE; // Must be set to FALSE
+	
+	/**
+	 * Constructor
+	 *
+	 * Runs the route mapping function. 
+	 */
+	function CI_Router()
+	{
+		$this->config =& _load_class('CI_Config');
+		$this->_set_route_mapping();
+		log_message('debug', "Router Class Initialized");
+	}
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Set the route mapping
+	 *
+	 * This function determies what should be served based on the URI request,
+	 * as well as any "routes" that have been set in the routing config file.
+	 *
+	 * @access	private
+	 * @return	void
+	 */
+	function _set_route_mapping()
+	{		
+		// Are query strings enabled? If so we're done...
+		if ($this->config->item('enable_query_strings') === TRUE AND isset($_GET[$this->config->item('controller_trigger')]))
+		{
+			$this->set_class($_GET[$this->config->item('controller_trigger')]);
+
+			if (isset($_GET[$this->config->item('function_trigger')]))
+			{
+				$this->set_method($_GET[$this->config->item('function_trigger')]);
+			}
+			
+			return;
+		}
+
+		// Load the routes.php file
+		include_once(APPPATH.'config/routes'.EXT);
+		$this->routes = ( ! isset($route) OR ! is_array($route)) ? array() : $route;
+		unset($route);
+
+		// Set the default controller	
+		$this->default_controller = ( ! isset($this->routes['default_controller']) OR $this->routes['default_controller'] == '') ? FALSE : strtolower($this->routes['default_controller']);
+
+		// Fetch the URI string Depending on the server, 
+		// the URI will be available in one of two globals
+		switch ($this->config->item('uri_protocol'))
+		{
+			case 'path_info'	: $this->uri_string = (isset($_SERVER['PATH_INFO'])) ? $_SERVER['PATH_INFO'] : @getenv('PATH_INFO');	
+				break;
+			case 'query_string' : $this->uri_string = (isset($_SERVER['QUERY_STRING'])) ? $_SERVER['QUERY_STRING'] : @getenv('QUERY_STRING'); 
+				break;
+			default : 
+						$path_info = (isset($_SERVER['PATH_INFO'])) ? $_SERVER['PATH_INFO'] : @getenv('PATH_INFO');
+						
+						if ($path_info != '' AND $path_info != "/".SELF)
+						{
+							$this->uri_string = $path_info;
+						}
+						else
+						{
+							$this->uri_string = (isset($_SERVER['QUERY_STRING'])) ? $_SERVER['QUERY_STRING'] : @getenv('QUERY_STRING');
+						}
+				break;
+		}
+	
+		// Is there a URI string? If not, the default controller specified 
+		// by the admin in the "routes" file will be shown.
+		if ($this->uri_string == '')
+		{
+			if ($this->default_controller === FALSE)
+			{
+				show_error("Unable to determine what should be displayed. A default route has not been specified in the routing file.");
+			}
+		
+			$this->set_class($this->default_controller);
+			$this->set_method('index');
+
+			log_message('debug', "No URI present. Default controller set.");
+			return;
+		}
+		
+		// Do we need to remove the suffix specified in the config file?
+		if  ($this->config->item('url_suffix') != "")
+		{
+			$this->uri_string = preg_replace("|".preg_quote($this->config->item('url_suffix'))."$|", "", $this->uri_string);
+		}
+
+		// Explode the URI Segments. The individual segments will
+		// be stored in the $this->segments array.
+		$this->_compile_segments(explode("/", preg_replace("|/*(.+?)/*$|", "\\1", $this->uri_string)));
+
+
+		// Remap the class/method if a route exists
+		unset($this->routes['default_controller']);
+		
+		if (count($this->routes) > 0)
+		{
+			$this->_parse_routes();
+		}
+	}
+	// END _set_route_mapping()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Compile Segments
+	 *
+	 * This function takes an array of URI segments as
+	 * input, and puts it into the $this->segments array.
+	 * It also sets the current class/method
+	 *
+	 * @access	private
+	 * @param	array
+	 * @param	bool
+	 * @return	void
+	 */
+	function _compile_segments($segs, $route = FALSE)
+	{		
+		$segments = array();
+	
+		$i = 1;
+		foreach($segs as $val)
+		{
+			$val = trim($this->_filter_uri($val));
+			
+			if ($val != '')
+				$segments[$i++] = $val;
+		}
+		
+		$this->set_class($segments['1']);
+		
+		if (isset($segments['2']))
+		{
+			// A scaffolding request. No funny business with the URL
+			if ($this->routes['scaffolding_trigger'] == $segments['2'] AND $segments['2'] != '_ci_scaffolding')
+			{
+				$this->scaffolding_request = TRUE;
+				unset($this->routes['scaffolding_trigger']);
+			}
+			else
+			{
+				// A standard method request
+				$this->set_method($segments['2']);
+			}
+		}
+		
+		if ($route == FALSE)
+		{
+			$this->segments = $segments;
+		}
+		
+		unset($segments);
+	}
+	// END _compile_segments()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Filter segments for malicious characters
+	 *
+	 * @access	private
+	 * @param	string
+	 * @return	string
+	 */	
+	function _filter_uri($str)
+	{
+		 if ( ! preg_match("/^[a-z0-9~\s\%\.:_-]+$/i", $str))
+		 { 
+			exit('The URI you submitted has disallowed characters: '.$str);
+		 }
+		 
+		 return $str;
+	}
+	// END _filter_uri()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Set the class name
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	void
+	 */	
+	function set_class($class)
+	{
+		$this->class = $class;
+	}
+	// END _filter_uri()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Fetch the current class
+	 *
+	 * @access	public
+	 * @return	string
+	 */	
+	function fetch_class()
+	{
+		return $this->class;
+	}
+	// END _filter_uri()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 *  Set the method name
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	void
+	 */	
+	function set_method($method)
+	{
+		$this->method = $method;
+	}
+	// END set_method()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 *  Fetch the current method
+	 *
+	 * @access	public
+	 * @return	string
+	 */	
+	function fetch_method()
+	{
+		return $this->method;
+	}
+	// END set_method()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 *  Parse Routes
+	 *
+	 * This function matches any routes that may exist in
+	 * the config/routes.php file against the URI to 
+	 * determine if the class/method need to be remapped.
+	 *
+	 * @access	private
+	 * @return	void
+	 */
+	function _parse_routes()
+	{
+		// Turn the segment array into a URI string
+		$uri = implode('/', $this->segments);
+		$num = count($this->segments);
+
+		// Is there a literal match?  If so we're done
+		if (isset($this->routes[$uri]))
+		{
+			$this->_compile_segments(explode('/', $this->routes[$uri]), TRUE);		
+			return;
+		}
+		
+		// Loop through the route array looking for wildcards
+		foreach ($this->routes as $key => $val)
+		{
+			if (count(explode('/', $key)) != $num)
+				continue;
+		
+			if (preg_match("|".str_replace(':any', '.+', str_replace(':num', '[0-9]+', $key))."$|", $uri))
+			{
+				$this->_compile_segments(explode('/', $val), TRUE);		
+				break;
+			}
+		}	
+	}
+	// END set_method()
+}
+// END Router Class
+?>
\ No newline at end of file
diff --git a/system/libraries/Session.php b/system/libraries/Session.php
new file mode 100644
index 0000000..4f08cf6
--- /dev/null
+++ b/system/libraries/Session.php
@@ -0,0 +1,499 @@
+<?php  if (!defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * Code Igniter
+ *
+ * An open source application development framework for PHP 4.3.2 or newer
+ *
+ * @package		CodeIgniter
+ * @author		Rick Ellis
+ * @copyright	Copyright (c) 2006, pMachine, Inc.
+ * @license		http://www.codeignitor.com/user_guide/license.html 
+ * @link		http://www.codeigniter.com
+ * @since		Version 1.0
+ * @filesource
+ */
+ 
+// ------------------------------------------------------------------------
+
+/**
+ * Session Class
+ * 
+ * @package		CodeIgniter
+ * @subpackage	Libraries
+ * @category	Sessions
+ * @author		Rick Ellis
+ * @link		http://www.codeigniter.com/user_guide/libraries/sessions.html
+ */
+class CI_Session {
+
+	var $now;
+	var $encryption		= TRUE;
+	var $use_database	= FALSE;
+	var $session_table	= FALSE;
+    var $sess_length	= 7200;
+    var $sess_cookie	= 'ci_session';
+	var $userdata		= array();
+    var $gc_probability	= 5;
+    var $object;
+    
+
+	/**
+	 * Session Constructor
+	 *
+	 * The constructor runs the session routines automatically
+	 * whenever the class is instantiated.
+	 */		
+	function CI_Session()
+	{
+		$this->object =& get_instance();
+
+		log_message('debug', "Session Class Initialized");
+		$this->sess_run();
+	}
+	// END display_errors()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Run the session routines
+	 *
+	 * @access	public
+	 * @return	void
+	 */		
+	function sess_run()
+	{
+		/*
+		 *  Set the "now" time
+		 *
+		 * It can either set to GMT or time(). The pref
+		 * is set in the config file.  If the developer
+		 * is doing any sort of time localization they 
+		 * might want to set the session time to GMT so
+		 * they can offset the "last_activity" and
+		 * "last_visit" times based on each user's locale.
+		 *
+		 */
+		if (strtolower($this->object->config->item('time_reference')) == 'gmt')
+		{
+			$now = time();
+			$this->now = mktime(gmdate("H", $now), gmdate("i", $now), gmdate("s", $now), gmdate("m", $now), gmdate("d", $now), gmdate("Y", $now));   
+	
+			if (strlen($this->now) < 10)
+			{
+				$this->now = time();
+				log_message('error', 'The session class could not set a proper GMT timestamp so the local time() value was used.');
+			}
+		}
+		else
+		{
+			$this->now = time();
+		}
+		
+		/*
+		 *  Set the session length
+		 *
+		 * If the session expiration is set to zero in
+		 * the config file we'll set the expiration 
+		 * two years from now.
+		 *
+		 */
+		$expiration = $this->object->config->item('sess_expiration');
+		
+		if (ctype_digit($expiration))
+		{
+			if ($expiration > 0)
+			{
+				$this->sess_length = $this->object->config->item('sess_expiration');
+			}
+			else
+			{
+				$this->sess_length = (60*60*24*365*2);
+			}
+		}
+		
+		// Do we need encryption?
+		$this->encryption = $this->object->config->item('sess_encrypt_cookie');
+		
+		if ($this->encryption == TRUE)	
+		{
+			$this->object->load->library('encrypt');
+		}		
+
+		// Are we using a database?
+		if ($this->object->config->item('sess_use_database') === TRUE AND $this->object->config->item('sess_table_name') != '')
+		{
+			$this->use_database = TRUE;
+			$this->session_table = $this->object->config->item('sess_table_name');
+			$this->object->load->database();
+		}
+		
+		// Set the cookie name
+		if ($this->object->config->item('sess_cookie_name') != FALSE)
+		{
+			$this->sess_cookie = $this->object->config->item('cookie_prefix').$this->object->config->item('sess_cookie_name');
+		}
+	
+		/*
+		 *  Fetch the current session
+		 *
+		 * If a session doesn't exist we'll create
+		 * a new one.  If it does, we'll update it.
+		 *
+		 */
+		if ( ! $this->sess_read())
+		{
+			$this->sess_create();
+		}
+		else
+		{	
+			// We only update the session every five minutes
+			if (($this->userdata['last_activity'] + 300) < $this->now)
+			{
+				$this->sess_update();
+			}
+		}
+		
+		// Delete expired sessions if necessary
+		if ($this->use_database === TRUE)
+		{		
+			$this->sess_gc();
+		}	
+	}
+	// END sess_run()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Fetch the current session data if it exists
+	 *
+	 * @access	public
+	 * @return	void
+	 */
+	function sess_read()
+	{	
+		// Fetch the cookie
+		$session = $this->object->input->cookie($this->sess_cookie);
+		
+		if ($session === FALSE)
+		{
+			log_message('debug', 'A session cookie was not found.');
+			return FALSE;
+		}
+		
+		// Decrypt and unserialize the data
+		if ($this->encryption == TRUE)
+		{
+			$session = $this->object->encrypt->decode($session);
+		}
+
+		$session = @unserialize($this->strip_slashes($session));
+		
+		if ( ! is_array($session) OR ! isset($session['last_activity']))
+		{
+			log_message('error', 'The session cookie data did not contain a valid array. This could be a possible hacking attempt.');
+			return FALSE;
+		}
+		
+		// Is the session current?
+		if (($session['last_activity'] + $this->sess_length) < $this->now) 
+		{
+			$this->sess_destroy();
+			return FALSE;
+		}
+
+		// Does the IP Match?
+		if ($this->object->config->item('sess_match_ip') == TRUE AND $session['ip_address'] != $this->object->input->ip_address())
+		{
+			$this->sess_destroy();
+			return FALSE;
+		}
+		
+		// Does the User Agent Match?
+		if ($this->object->config->item('sess_match_useragent') == TRUE AND $session['user_agent'] != substr($this->object->input->user_agent(), 0, 50))
+		{
+			$this->sess_destroy();
+			return FALSE;
+		}
+		
+		// Is there a corresponding session in the DB?
+		if ($this->use_database === TRUE)
+		{
+			$this->object->db->where('session_id', $session['session_id']);
+					
+			if ($this->object->config->item('sess_match_ip') == TRUE)
+			{
+				$this->object->db->where('ip_address', $session['ip_address']);
+			}
+
+			if ($this->object->config->item('sess_match_useragent') == TRUE)
+			{
+				$this->object->db->where('user_agent', $session['user_agent']);
+			}
+			
+			$query = $this->object->db->get($this->session_table);
+
+			if ($query->num_rows() == 0)
+			{
+				$this->sess_destroy();
+				return FALSE;
+			}
+			else
+			{
+				$row = $query->row();
+				if (($row->last_activity + $this->sess_length) < $this->now) 
+				{
+					$this->object->db->where('session_id', $session['session_id']);
+					$this->object->db->delete($this->session_table);
+					$this->sess_destroy();
+					return FALSE;
+				}
+			}
+		}
+	
+		// Session is valid!
+		$this->userdata = $session;
+		unset($session);
+		
+		return TRUE;
+	}
+	// END sess_read()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Write the session cookie
+	 *
+	 * @access	public
+	 * @return	void
+	 */
+	function sess_write()
+	{								
+		$cookie_data = serialize($this->userdata);
+		
+		if ($this->encryption == TRUE)
+		{
+			$cookie_data = $this->object->encrypt->encode($cookie_data);
+		}
+
+		setcookie(
+					$this->sess_cookie, 
+					$cookie_data, 
+					$this->sess_length + $this->now, 
+					$this->object->config->item('cookie_path'), 
+					$this->object->config->item('cookie_domain'), 
+					0
+				);
+	}
+	// END sess_read()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Create a new session
+	 *
+	 * @access	public
+	 * @return	void
+	 */
+	function sess_create()
+	{	
+		$sessid = '';
+		while (strlen($sessid) < 32) 
+		{    
+			$sessid .= mt_rand(0, mt_getrandmax());
+		}
+	
+		$this->userdata = array(
+							'session_id' 	=> md5(uniqid($sessid, TRUE)),
+							'ip_address' 	=> $this->object->input->ip_address(),
+							'user_agent' 	=> substr($this->object->input->user_agent(), 0, 50),
+							'last_activity'	=> $this->now
+							);
+		
+		
+		// Save the session in the DB if needed
+		if ($this->use_database === TRUE)
+		{
+			$this->object->db->query($this->object->db->insert_string($this->session_table, $this->userdata));
+		}
+			
+		// Write the cookie
+		$this->userdata['last_visit'] = 0;		
+		$this->sess_write();
+	}
+	// END sess_read()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Update an existing session
+	 *
+	 * @access	public
+	 * @return	void
+	 */
+	function sess_update()
+	{	
+        if (($this->userdata['last_activity'] + $this->sess_length) < $this->now) 
+        {
+			$this->userdata['last_visit'] = $this->userdata['last_activity'];
+        }
+	
+		$this->userdata['last_activity'] = $this->now;
+		
+		// Update the session in the DB if needed
+		if ($this->use_database === TRUE)
+		{		
+			$this->object->db->query($this->object->db->update_string($this->session_table, array('last_activity' => $this->now), array('session_id' => $this->userdata['session_id'])));
+		}
+		
+		// Write the cookie
+		$this->sess_write();
+	}
+	// END sess_update()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Destroy the current session
+	 *
+	 * @access	public
+	 * @return	void
+	 */
+	function sess_destroy()
+	{
+		setcookie(
+					$this->sess_cookie, 
+					addslashes(serialize(array())), 
+					($this->now - 31500000), 
+					$this->object->config->item('cookie_path'), 
+					$this->object->config->item('cookie_domain'), 
+					0
+				);
+	}
+	// END sess_destroy()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Garbage collection
+	 *
+	 * This deletes expired session rows from database
+	 * if the probability percentage is met
+	 *
+	 * @access	public
+	 * @return	void
+	 */
+    function sess_gc()
+    {  
+		srand(time());
+		if ((rand() % 100) < $this->gc_probability) 
+		{  
+			$expire = $this->now - $this->sess_length;
+			
+			$this->object->db->where("last_activity < {$expire}");
+			$this->object->db->delete($this->session_table);
+
+			log_message('debug', 'Session garbage collection performed.');
+		}    
+    }
+	// END sess_destroy()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Fetch a specific item form  the session array
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	string
+	 */		
+	function userdata($item)
+	{
+    	return ( ! isset($this->userdata[$item])) ? FALSE : $this->userdata[$item];
+	}
+	// END sess_destroy()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Add or change data in the "userdata" array
+	 *
+	 * @access	public
+	 * @param	mixed
+	 * @param	string
+	 * @return	void
+	 */		
+	function set_userdata($newdata = array(), $newval = '')
+	{
+		if (is_string($newdata))
+		{
+			$newdata = array($newdata => $newval);
+		}
+	
+		if (count($newdata) > 0)
+		{
+			foreach ($newdata as $key => $val)
+			{
+				$this->userdata[$key] = $val;
+			}
+		}
+	
+    	$this->sess_write();
+	}
+	// END set_userdata()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Delete a session variable from the "userdata" array
+	 *
+	 * @access	array
+	 * @return	void
+	 */		
+	function unset_userdata($newdata = array())
+	{
+		if (is_string($newdata))
+		{
+			$newdata = array($newdata => '');
+		}
+	
+		if (count($newdata) > 0)
+		{
+			foreach ($newdata as $key => $val)
+			{
+				unset($this->userdata[$key]);
+			}
+		}
+	
+    	$this->sess_write();
+	}
+	// END set_userdata()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Strip slashes
+	 *
+	 * @access	public
+	 * @param	mixed
+	 * @return	mixed
+	 */
+     function strip_slashes($vals)
+     {
+     	if (is_array($vals))
+     	{	
+     		foreach ($vals as $key=>$val)
+     		{
+     			$vals[$key] = $this->strip_slashes($val);
+     		}
+     	}
+     	else
+     	{
+     		$vals = stripslashes($vals);
+     	}
+     	
+     	return $vals;
+	}
+	// END strip_slashes()
+}
+// END Session Class
+?>
\ No newline at end of file
diff --git a/system/libraries/Sha1.php b/system/libraries/Sha1.php
new file mode 100644
index 0000000..13196eb
--- /dev/null
+++ b/system/libraries/Sha1.php
@@ -0,0 +1,254 @@
+<?php  if (!defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * Code Igniter
+ *
+ * An open source application development framework for PHP 4.3.2 or newer
+ *
+ * @package		CodeIgniter
+ * @author		Rick Ellis
+ * @copyright	Copyright (c) 2006, pMachine, Inc.
+ * @license		http://www.codeignitor.com/user_guide/license.html 
+ * @link		http://www.codeigniter.com
+ * @since		Version 1.0
+ * @filesource
+ */
+ 
+// ------------------------------------------------------------------------
+
+/**
+ * SHA1 Encoding Class
+ *
+ * Purpose: Provides 160 bit hashing using The Secure Hash Algorithm 
+ * developed at the National Institute of Standards and Technology. The 40 
+ * character SHA1 message hash is computationally infeasible to crack.
+ * 
+ * This class is a fallback for servers that are not running PHP greater than 
+ * 4.3, or do not have the MHASH library.
+ *
+ * This class is based on two scripts:
+ *  
+ * Marcus Campbell's PHP implementation (GNU license) 
+ * http://www.tecknik.net/sha-1/
+ *
+ * ...which is based on Paul Johnston's JavaScript version 
+ * (BSD license). http://pajhome.org.uk/
+ * 
+ * I encapsulated the functions and wrote one additional method to fix
+ * a hex conversion bug. - Rick Ellis
+ * 
+ * @package		CodeIgniter
+ * @subpackage	Libraries
+ * @category	Encryption
+ * @author		Rick Ellis
+ * @link		http://www.codeigniter.com/user_guide/general/encryption.html
+ */
+class CI_SHA {
+
+	function CI_SHA()
+	{
+		log_message('debug', "SHA1 Class Initialized");
+	}
+
+	/**
+	 * Generate the Hash
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	string
+	 */	
+    function generate($str) 
+    {
+        $n = ((strlen($str) + 8) >> 6) + 1;
+        
+        for ($i = 0; $i < $n * 16; $i++)
+        {
+            $x[$i] = 0;
+        }
+        
+        for ($i = 0; $i < strlen($str); $i++)
+        {
+            $x[$i >> 2] |= ord(substr($str, $i, 1)) << (24 - ($i % 4) * 8);
+        }
+        
+        $x[$i >> 2] |= 0x80 << (24 - ($i % 4) * 8);
+        
+        $x[$n * 16 - 1] = strlen($str) * 8;
+        
+        $a =  1732584193;
+        $b = -271733879;
+        $c = -1732584194;
+        $d =  271733878;
+        $e = -1009589776;
+        
+        for ($i = 0; $i < sizeof($x); $i += 16) 
+        {
+            $olda = $a;
+            $oldb = $b;
+            $oldc = $c;
+            $oldd = $d;
+            $olde = $e;
+            
+            for($j = 0; $j < 80; $j++) 
+            {
+                if ($j < 16)
+                {
+                    $w[$j] = $x[$i + $j];
+                }
+                else
+                {
+                    $w[$j] = $this->_rol($w[$j - 3] ^ $w[$j - 8] ^ $w[$j - 14] ^ $w[$j - 16], 1);
+                }
+                
+                $t = $this->_safe_add($this->_safe_add($this->_rol($a, 5), $this->_ft($j, $b, $c, $d)), $this->_safe_add($this->_safe_add($e, $w[$j]), $this->_kt($j)));
+                
+                $e = $d;
+                $d = $c;
+                $c = $this->_rol($b, 30);
+                $b = $a;
+                $a = $t;
+            }
+
+            $a = $this->_safe_add($a, $olda);
+            $b = $this->_safe_add($b, $oldb);
+            $c = $this->_safe_add($c, $oldc);
+            $d = $this->_safe_add($d, $oldd);
+            $e = $this->_safe_add($e, $olde);
+        }
+        
+        return $this->_hex($a).$this->_hex($b).$this->_hex($c).$this->_hex($d).$this->_hex($e);
+    }
+  	// END generate()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Convert a decimal to hex
+	 *
+	 * @access	private
+	 * @param	string
+	 * @return	string
+	 */	
+    function _hex($str)
+    {
+        $str = dechex($str);
+        
+        if (strlen($str) == 7)
+        {
+            $str = '0'.$str;
+        }
+            
+        return $str;
+    }    
+  	// END _hex()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 *  Return result based on iteration
+	 *
+	 * @access	private
+	 * @return	string
+	 */	
+    function _ft($t, $b, $c, $d) 
+    {
+        if ($t < 20) 
+            return ($b & $c) | ((~$b) & $d);
+        if ($t < 40) 
+            return $b ^ $c ^ $d;
+        if ($t < 60) 
+            return ($b & $c) | ($b & $d) | ($c & $d);
+        
+        return $b ^ $c ^ $d;
+    }
+    // END _ft()
+  
+	// --------------------------------------------------------------------
+
+	/**
+	 * Determine the additive constant
+	 *
+	 * @access	private
+	 * @return	string
+	 */	
+    function _kt($t) 
+    {
+        if ($t < 20) 
+        {
+            return 1518500249;
+        } 
+        else if ($t < 40) 
+        {
+            return 1859775393;
+        } 
+        else if ($t < 60) 
+        {
+            return -1894007588;
+        } 
+        else 
+        {
+            return -899497514;
+        }
+    }
+  	// END _kt()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Add integers, wrapping at 2^32
+	 *
+	 * @access	private
+	 * @return	string
+	 */	
+    function _safe_add($x, $y)
+    {
+        $lsw = ($x & 0xFFFF) + ($y & 0xFFFF);
+        $msw = ($x >> 16) + ($y >> 16) + ($lsw >> 16);
+    
+        return ($msw << 16) | ($lsw & 0xFFFF);
+    }
+  	// END _safe_add()
+  	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Bitwise rotate a 32-bit number
+	 *
+	 * @access	private
+	 * @return	integer
+	 */	
+    function _rol($num, $cnt)
+    {
+        return ($num << $cnt) | $this->_zero_fill($num, 32 - $cnt);
+    }
+  
+	// --------------------------------------------------------------------
+
+	/**
+	 * Pad string with zero
+	 *
+	 * @access	private
+	 * @return	string
+	 */	
+    function _zero_fill($a, $b) 
+    {
+        $bin = decbin($a);
+        
+        if (strlen($bin) < $b)
+        {
+            $bin = 0;
+        }
+        else
+        {
+            $bin = substr($bin, 0, strlen($bin) - $b);
+        }
+        
+        for ($i=0; $i < $b; $i++) 
+        {
+            $bin = "0".$bin;
+        }
+        
+        return bindec($bin);
+    }
+}
+// END CI_SHA
+?>
\ No newline at end of file
diff --git a/system/libraries/Trackback.php b/system/libraries/Trackback.php
new file mode 100644
index 0000000..583c6d2
--- /dev/null
+++ b/system/libraries/Trackback.php
@@ -0,0 +1,561 @@
+<?php  if (!defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * Code Igniter
+ *
+ * An open source application development framework for PHP 4.3.2 or newer
+ *
+ * @package		CodeIgniter
+ * @author		Rick Ellis
+ * @copyright	Copyright (c) 2006, pMachine, Inc.
+ * @license		http://www.codeignitor.com/user_guide/license.html 
+ * @link		http://www.codeigniter.com
+ * @since		Version 1.0
+ * @filesource
+ */
+ 
+// ------------------------------------------------------------------------
+
+/**
+ * Trackback Class
+ *
+ * Trackback Sending/Receiving Class
+ * 
+ * @package		CodeIgniter
+ * @subpackage	Libraries
+ * @category	Trackbacks
+ * @author		Paul Burdick
+ * @link		http://www.codeigniter.com/user_guide/libraries/trackback.html
+ */
+class CI_Trackback {
+		
+	var $time_format	= 'local';
+	var $charset		= 'UTF-8';
+	var $data			= array('url' => '', 'title' => '', 'excerpt' => '', 'blog_name' => '', 'charset' => '');
+	var $convert_ascii	= TRUE;
+	var $response		= '';
+	var $error_msg		= array();
+
+	/**
+	 * Constructor
+	 *
+	 * @access	public
+	 */
+	function CI_Trackback()
+	{
+		log_message('debug', "Trackback Class Initialized");
+	}
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Send Trackback
+	 *
+	 * @access	public
+	 * @param	array
+	 * @return	bool
+	 */	
+	function send($tb_data)
+	{		
+		if ( ! is_array($tb_data))
+		{ 
+			$this->set_error('The send() method must be passed an array');
+			return FALSE;
+		}
+		
+		// Pre-process the Trackback Data
+		foreach (array('url', 'title', 'excerpt', 'blog_name', 'ping_url') as $item)
+		{
+			if ( ! isset($tb_data[$item]))
+			{ 
+				$this->set_error('Required item missing: '.$item);
+				return FALSE;
+			}
+			
+			switch ($item)
+			{
+				case 'ping_url'	: $$item = $this->extract_urls($tb_data[$item]);
+					break;
+				case 'excerpt'	: $$item = $this->limit_characters($this->convert_xml(strip_tags(stripslashes($tb_data[$item]))));
+					break;
+				case 'url'	 	: $$item = str_replace('&#45;', '-', $this->convert_xml(strip_tags(stripslashes($tb_data[$item]))));
+					break;
+				default			: $$item = $this->convert_xml(strip_tags(stripslashes($tb_data[$item])));
+					break;
+			}
+
+			// Convert High ASCII Characters
+			if ($this->convert_ascii == TRUE)
+			{
+				if ($item == 'excerpt')
+				{
+					$$item = $this->convert_ascii($$item);
+				}
+				elseif ($item == 'title')
+				{
+					$$item = $this->convert_ascii($$item);
+				}
+				elseif($item == 'blog_name')
+				{
+					$$item = $this->convert_ascii($$item);
+				}
+			}
+		}
+
+		// Build the Trackback data string
+		$charset = ( ! isset($tb_data['charset'])) ? $this->charset : $tb_data['charset'];
+		
+		$data = "url=".rawurlencode($url)."&title=".rawurlencode($title)."&blog_name=".rawurlencode($blog_name)."&excerpt=".rawurlencode($excerpt)."&charset=".rawurlencode($charset); 
+				
+		// Send Trackback(s)
+		$return = TRUE;
+		if (count($ping_url) > 0)
+		{
+			foreach ($ping_url as $url)
+			{
+				if ($this->process($url, $data) == FALSE)
+				{
+					$return = FALSE;
+				}
+			}	
+		}
+
+		return $return;
+	}	
+	// END send()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Receive Trackback  Data
+	 *
+	 * This function simply validates the incoming TB data.
+	 * It returns false on failure and true on success.
+	 * If the data is valid it is set to the $this->data array
+	 * so that it can be inserted into a database.
+	 *
+	 * @access	public
+	 * @return	bool
+	 */	
+	function receive()
+	{  					
+		foreach (array('url', 'title', 'blog_name', 'excerpt') as $val)
+		{
+			if ( ! isset($_POST[$val]) OR $_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']));
+	
+			if ($val != 'url' && function_exists('mb_convert_encoding'))
+			{
+				$_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]);
+			
+			if ($val == 'excerpt')
+			{
+				$_POST['excerpt'] = $this->limit_characters($_POST['excerpt']);
+			}
+			
+			$this->data[$val] = $_POST[$val];
+		}
+
+		return TRUE;
+	}	
+	// END receive()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Send Trackback Error Message
+	 *
+	 * Allows custom errros to be set.  By default it 
+	 * sends the "incomplete information" error, as that's
+	 * the most common one.
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	void
+	 */	
+	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>";
+		exit;
+	}
+	// END send_error()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Send Trackback Success Message
+	 *
+	 * This should be called when a trackback has been
+	 * successfully received and inserted.
+	 *
+	 * @access	public
+	 * @return	void
+	 */		
+	function send_success()
+	{
+		echo "<?xml version=\"1.0\" encoding=\"utf-8\"?".">\n<response>\n<error>0</error>\n</response>";
+		exit;
+	}
+	// END send_success()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Fetch a particular item
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	string
+	 */	
+	function data($item)
+	{
+		return ( ! isset($this->data[$item])) ? '' : $this->data[$item];
+	}
+	// END data()
+
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Process Trackback
+	 *
+	 * Opens a socket connection and passes the data to 
+	 * the server.  Returns true on success, false on failure
+	 *
+	 * @access	public
+	 * @param	string
+	 * @param	string
+	 * @return	bool
+	 */	
+	function process($url, $data)
+	{
+		$target = parse_url($url);
+	
+		// Open the socket
+		if ( ! $fp = @fsockopen($target['host'], 80))
+		{
+			$this->set_error('Invalid Connection: '.$url);
+			return FALSE;
+		}
+
+		// Build the path
+		$ppath = ( ! isset($target['path'])) ? $url : $target['path'];
+		
+		$path = (isset($target['query']) && $target['query'] != "") ? $ppath.'?'.$target['query'] : $ppath;
+
+		// Add the Trackback ID to the data string
+		if ($id = $this->get_id($url))
+		{
+			$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);
+   
+		// Was it successful?
+		$this->response = "";
+		
+		while(!feof($fp))
+		{
+			$this->response .= fgets($fp, 128);
+		}  
+		@fclose($fp);
+		
+		if ( ! eregi("<error>0</error>", $this->response))
+		{
+			$message = 'An unknown error was encountered';
+			
+			if (preg_match("/<message>(.*?)<\/message>/is", $this->response, $match))
+			{
+				$message = trim($match['1']);
+			}
+			
+			$this->set_error($message);
+			return FALSE;
+		}
+
+		return TRUE;
+	}
+	// END process()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Extract Trackback URLs
+	 *
+	 * This function lets multiple trackbacks be sent.
+	 * It takes a string of URLs (separated by comma or
+	 * space) and puts each URL into an array
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	string
+	 */	
+	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 any comma that might be at the end
+		if (substr($urls, -1) == ",")
+		{
+			$urls = substr($urls, 0, -1);
+		}
+				
+		// Break into an array via commas
+		$urls = preg_split('/[,]/', $urls);
+		
+		// Removes duplicates
+		$urls = array_unique($urls);
+		
+		array_walk($urls, array($this, 'validate_url')); 
+		
+		return $urls;
+	}
+	// END extract_urls()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Validate URL
+	 *
+	 * Simply adds "http://" if missing
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	string
+	 */	
+	function validate_url($url)
+	{
+		$url = trim($url);
+
+		if (substr($url, 0, 4) != "http")
+		{
+			$url = "http://".$url;
+		}
+	}
+	// END validate_url()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Find the Trackback URL's ID
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	string
+	 */	
+	function get_id($url)
+	{	
+		$tb_id = "";
+		
+		if (strstr($url, '?'))
+		{
+			$tb_array = explode('/', $url);
+			$tb_end   = $tb_array[count($tb_array)-1];
+			
+			if ( ! ctype_digit($tb_end))
+			{
+				$tb_end  = $tb_array[count($tb_array)-2];
+			}
+			
+			$tb_array = explode('=', $tb_end);
+			$tb_id	= $tb_array[count($tb_array)-1];
+		}
+		else
+		{
+			if (ereg("/$", $url))
+			{
+				$url = substr($url, 0, -1);
+			}
+				
+			$tb_array = explode('/', $url);
+			$tb_id	= $tb_array[count($tb_array)-1];
+			
+			if ( ! ctype_digit($tb_id))
+			{
+				$tb_id  = $tb_array[count($tb_array)-2];
+			}
+		}	
+				
+		if ( ! preg_match ("/^([0-9]+)$/", $tb_id)) 
+		{
+			return false;
+		}
+		else
+		{
+			return $tb_id;
+		}		
+	}
+	// END get_id()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Convert Reserved XML characters to Entities
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	string
+	 */
+	function convert_xml($str)
+	{
+		$temp = '__TEMP_AMPERSANDS__';
+		
+		$str = preg_replace("/&#(\d+);/", "$temp\\1;", $str);
+		$str = preg_replace("/&(\w+);/",  "$temp\\1;", $str);
+		
+		$str = str_replace(array("&","<",">","\"", "'", "-"),
+						   array("&amp;", "&lt;", "&gt;", "&quot;", "&#39;", "&#45;"),
+						   $str);
+			
+		$str = preg_replace("/$temp(\d+);/","&#\\1;",$str);
+		$str = preg_replace("/$temp(\w+);/","&\\1;", $str);
+			
+		return $str;
+	}	
+	// END get_id()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Character limiter
+	 *
+	 * Limits the string based on the character count. Will preserve complete words.
+	 *
+	 * @access	public
+	 * @param	string
+	 * @param	integer
+	 * @param	string
+	 * @return	string
+	 */
+	function limit_characters($str, $n = 500, $end_char = '&#8230;')
+	{
+		if (strlen($str) < $n) 
+		{
+			return $str;
+		}
+			
+		$str = preg_replace("/\s+/", ' ', preg_replace("/(\r\n|\r|\n)/", " ", $str));
+	
+		if (strlen($str) <= $n)
+		{
+			return $str;
+		}
+										
+		$out = "";
+		foreach (explode(' ', trim($str)) as $val)
+		{
+			$out .= $val.' ';			
+			if (strlen($out) >= $n)
+			{
+				return trim($out).$end_char; 
+			}		
+		}
+	}
+	// END get_id()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * High ASCII to Entities
+	 *
+	 * Converts Hight ascii text and MS Word special chars
+	 * to character entities
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	string
+	 */
+	function convert_ascii($str)
+	{
+	   $count	= 1;
+	   $out	= '';
+	   $temp	= array();
+		   
+	   for ($i = 0, $s = strlen($str); $i < $s; $i++)
+	   {
+		   $ordinal = ord($str[$i]);
+		   
+		   if ($ordinal < 128)
+		   {
+			   $out .= $str[$i];			
+		   }
+		   else
+		   {
+			   if (count($temp) == 0)
+			   {
+				   $count = ($ordinal < 224) ? 2 : 3;
+			   }
+			   
+			   $temp[] = $ordinal;
+			   
+			   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);
+	
+				   $out .= '&#'.$number.';';
+				   $count = 1;
+				   $temp = array();
+			   }   
+		   }   
+	   }
+	   
+	   return $out;
+	}
+	// END convert_ascii()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Set error message
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	void
+	 */	
+	function set_error($msg)
+	{
+		log_message('error', $msg);
+		$this->error_msg[] = $msg;
+	}
+	// END convert_ascii()
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Show error messages
+	 *
+	 * @access	public
+	 * @param	string
+	 * @param	string
+	 * @return	string
+	 */	
+	function display_errors($open = '<p>', $close = '</p>')
+	{	
+		$str = '';
+		foreach ($this->error_msg as $val)
+		{
+			$str .= $open.$val.$close;
+		}
+	
+		return $str;
+	}
+	// END display_errors()
+}
+// END Trackback Class
+?>
\ No newline at end of file
diff --git a/system/libraries/URI.php b/system/libraries/URI.php
new file mode 100644
index 0000000..4c2fa9c
--- /dev/null
+++ b/system/libraries/URI.php
@@ -0,0 +1,243 @@
+<?php  if (!defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * Code Igniter
+ *
+ * An open source application development framework for PHP 4.3.2 or newer
+ *
+ * @package		CodeIgniter
+ * @author		Rick Ellis
+ * @copyright	Copyright (c) 2006, pMachine, Inc.
+ * @license		http://www.codeignitor.com/user_guide/license.html 
+ * @link		http://www.codeigniter.com
+ * @since		Version 1.0
+ * @filesource
+ */
+ 
+// ------------------------------------------------------------------------
+
+/**
+ * URI Class
+ * 
+ * Parses URIs and determines routing
+ *
+ * @package		CodeIgniter
+ * @subpackage	Libraries
+ * @category	URI
+ * @author		Rick Ellis
+ * @link		http://www.codeigniter.com/user_guide/libraries/uri.html
+ */
+class CI_URI {
+
+	var $uri;
+	var	$keyval	= array();
+
+	/**
+	 * Constructor
+	 *
+	 * Simply globalizes the $RTR object.  The front
+	 * loads the Router class early on so it's not available
+	 * normally as other classes are. 
+	 *
+	 * @access	public
+	 */		
+	function CI_URI()
+	{
+		$this->uri =& _load_class('CI_Router');		
+		log_message('debug', "URI Class Initialized");
+	}
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Fetch a URI Segment
+	 *
+	 * This function returns the URI segment based on the number provided.  
+	 *
+	 * @access	public
+	 * @param	integer
+	 * @param	bool
+	 * @return	string
+	 */
+	function segment($n, $no_result = FALSE)
+	{
+		return ( ! isset($this->uri->segments[$n])) ? $no_result : $this->uri->segments[$n];
+	}
+
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Generate a key value pair from the URI string
+	 *
+	 * This function generates and associative array of URI data starting 
+	 * at the supplied segment. For example, if this is your URI:
+	 *
+	 *	www.your-site.com/user/search/name/joe/location/UK/gender/male
+	 *
+	 * You can use this function to generate an array with this prototype:
+	 *
+	 * array (
+	 *			name => joe
+	 *			location => UK
+	 *			gender => male
+	 *		 )
+	 * 
+	 * @access	public
+	 * @param	integer	the starting segment number
+	 * @param	array	an array of default values
+	 * @return	array
+	 */
+	function uri_to_assoc($n = 3, $default = array())
+	{
+		if ( ! ctype_digit($n))
+		{
+			return $default;
+		}
+	
+		if (isset($this->keyval[$n]))
+		{
+			return $this->keyval[$n];
+		}
+	
+		if ($this->total_segments() < $n)
+		{
+			if (count($default) == 0)
+			{
+				return array();
+			}
+			
+			$retval = array();
+			foreach ($default as $val)
+			{
+				$retval[$val] = FALSE;
+			}		
+			return $default;
+		}
+
+		$segments = array_slice($this->segment_array(), ($n - 1));
+
+		$i = 0;
+		$lastval = '';
+		$retval  = array();
+		foreach ($segments as $seg)
+		{
+			if ($i % 2)
+			{
+				$retval[$lastval] = $seg;
+			}
+			else
+			{
+				$retval[$seg] = FALSE;
+				$lastval = $seg;
+			}
+		
+			$i++;
+		}
+
+		if (count($default) > 0)
+		{
+			foreach ($default as $val)
+			{
+				if ( ! array_key_exists($val, $retval))
+				{
+					$retval[$val] = FALSE;
+				}
+			}
+		}
+
+		// Cache the array for reuse
+		$this->keyval[$n] = $retval;
+		return $retval;
+	}
+
+	/**
+	 * Generate a URI string from an associative array
+	 *
+	 * 
+	 * @access	public
+	 * @param	array	an associative array of key/values
+	 * @return	array
+	 */	function assoc_to_uri($array)
+	{	
+		$temp = array();
+		foreach ((array)$array as $key => $val)
+		{
+			$temp[] = $key;
+			$temp[] = $val;
+		}
+		
+		return implode('/', $temp);
+	}
+
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Fetch a URI Segment and add a trailing slash
+	 *
+	 * @access	public
+	 * @param	integer
+	 * @param	string
+	 * @return	string
+	 */
+	function slash_segment($n, $where = 'trailing')
+	{	
+		if ($where == 'trailing')
+		{
+			$trailing	= '/';
+			$leading	= '';
+		}
+		elseif ($where == 'leading')
+		{
+			$leading	= '/';
+			$trailing	= '';
+		}
+		else
+		{
+			$leading	= '/';
+			$trailing	= '/';
+		}
+		return ( ! isset($this->uri->segments[$n])) ? '' : $leading.$this->uri->segments[$n].$trailing;
+	}
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Segment Array
+	 *
+	 * @access	public
+	 * @return	array
+	 */
+	function segment_array()
+	{
+		return $this->uri->segments;
+	}
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Total number of segments
+	 *
+	 * @access	public
+	 * @return	integer
+	 */
+	function total_segments()
+	{
+		return count($this->uri->segments);
+	}
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Fetch the entire URI string
+	 *
+	 * @access	public
+	 * @return	string
+	 */
+	function uri_string()
+	{
+		return $this->uri->uri_string;
+	}
+
+}
+// END URI Class
+?>
\ No newline at end of file
diff --git a/system/libraries/Unit_test.php b/system/libraries/Unit_test.php
new file mode 100644
index 0000000..bf50350
--- /dev/null
+++ b/system/libraries/Unit_test.php
@@ -0,0 +1,331 @@
+<?php  if (!defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * Code Igniter
+ *
+ * An open source application development framework for PHP 4.3.2 or newer
+ *
+ * @package		CodeIgniter
+ * @author		Rick Ellis
+ * @copyright	Copyright (c) 2006, pMachine, Inc.
+ * @license		http://www.codeignitor.com/user_guide/license.html 
+ * @link		http://www.codeigniter.com
+ * @since		Version 1.3.1
+ * @filesource
+ */
+ 
+// ------------------------------------------------------------------------
+
+/**
+ * Unit Testing Class
+ * 
+ * Simple testing class
+ *
+ * @package		CodeIgniter
+ * @subpackage	Libraries
+ * @category	UnitTesting
+ * @author		Rick Ellis
+ * @link		http://www.codeigniter.com/user_guide/libraries/uri.html
+ */
+class CI_Unit_test {
+
+	var $active			= TRUE;
+	var $results 		= array();
+	var $strict			= FALSE;
+	var $_template 		= NULL;
+	var $_template_rows	= NULL;
+
+	function CI_Unit_test()
+	{
+		log_message('debug', "Unit Testing Class Initialized");
+	}	
+
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Run the tests
+	 *
+	 * Runs the supplied tests
+	 *
+	 * @access	public
+	 * @param	mixed
+	 * @param	mixed
+	 * @param	string
+	 * @return	string
+	 */	
+	function run($test, $expected = TRUE, $test_name = 'undefined')
+	{
+		if ($this->active == FALSE)
+			return;
+			
+		if (in_array($expected, array('is_string', 'is_bool', 'is_true', 'is_false', 'is_int', 'is_numeric', 'is_float', 'is_double', 'is_array', 'is_null')))
+		{		
+			$expected = str_replace('is_float', 'is_double', $expected);
+			$result = ($expected($test)) ? TRUE : FALSE;	
+			$extype = str_replace(array('true', 'false'), 'bool', str_replace('is_', '', $expected));
+		}
+		else
+		{
+			if ($this->strict == TRUE)
+				$result = ($test === $expected) ? TRUE : FALSE;	
+			else
+				$result = ($test == $expected) ? TRUE : FALSE;	
+			
+			$extype = gettype($expected);
+		}
+				
+		$back = $this->_backtrace();
+	
+		$report[] = array (
+							'test_name'			=> $test_name,
+							'test_datatype'		=> gettype($test),
+							'res_datatype'		=> $extype,
+							'result'			=> ($result === TRUE) ? 'passed' : 'failed',
+							'file'				=> $back['file'],
+							'line'				=> $back['line']
+						);
+
+		$this->results[] = $report;		
+				
+		return($this->report($this->result($report)));
+	}
+
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Generate a report
+	 *
+	 * Displays a table with the test data
+	 *
+	 * @access	public
+	 * @return	string
+	 */
+	function report($result = array())
+	{	
+		if (count($result) == 0)
+		{
+			$result = $this->result();
+		}
+		
+		$this->_parse_template();
+	
+		$r = '';
+		foreach ($result as $res)
+		{
+			$table = '';
+		
+			foreach ($res as $key => $val)
+			{
+				$temp = $this->_template_rows;			
+				$temp = str_replace('{item}', $key, $temp);
+				$temp = str_replace('{result}', $val, $temp);
+				$table .= $temp;
+			}
+			
+			$r .= str_replace('{rows}', $table, $this->_template);
+		}
+	
+		return $r;	
+	}	
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Use strict comparison
+	 *
+	 * Causes the evaluation to use === rather then ==
+	 *
+	 * @access	public
+	 * @param	bool
+	 * @return	null
+	 */
+	function use_strict($state = TRUE)
+	{
+		$this->strict = ($state == FALSE) ? FALSE : TRUE;
+	}
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Make Unit testing active
+	 *
+	 * Enables/disables unit testing  
+	 *
+	 * @access	public
+	 * @param	bool
+	 * @return	null
+	 */
+	function active($state = TRUE)
+	{
+		$this->active = ($state == FALSE) ? FALSE : TRUE;
+	}
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Result Array
+	 *
+	 * Returns the raw result data
+	 *
+	 * @access	public
+	 * @return	array
+	 */
+	function result($results = array())
+	{	
+		$obj =& get_instance();
+		$obj->load->language('unit_test');
+		
+		if (count($results) == 0)
+		{
+			$results = $this->results;
+		}
+		
+		$retval = array();
+		foreach ($results as $result)
+		{
+			$temp = array();
+			foreach ($result as $key => $val)
+			{
+				if (is_array($val))
+				{
+					foreach ($val as $k => $v)
+					{
+						if (FALSE !== ($line = $obj->lang->line(strtolower('ut_'.$v))))
+						{
+							$v = $line;
+						}				
+						$temp[$obj->lang->line('ut_'.$k)] = $v;					
+					}
+				}
+				else
+				{
+					if (FALSE !== ($line = $obj->lang->line(strtolower('ut_'.$val))))
+					{
+						$val = $line;
+					}				
+					$temp[$obj->lang->line('ut_'.$key)] = $val;
+				}
+			}
+			
+			$retval[] = $temp;
+		}
+	
+		return $retval;
+	}
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Set the template
+	 *
+	 * This lets us set the template to be used to display results
+	 *
+	 * @access	public
+	 * @params	string
+	 * @return	void
+	 */	
+	function set_template($tempalte)
+	{
+		$this->_template = $tempalte;
+	}
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Generate a backtrace
+	 *
+	 * This lets us show file names and line numbers 
+	 *
+	 * @access	private
+	 * @return	array
+	 */
+	function _backtrace() 
+	{
+		if (function_exists('debug_backtrace')) 
+		{
+			$back = debug_backtrace();
+			
+			$file = ( ! isset($back['1']['file'])) ? '' : $back['1']['file'];
+			$line = ( ! isset($back['1']['line'])) ? '' : $back['1']['line'];
+						
+			return array('file' => $file, 'line' => $line);
+		}
+		return array('file' => 'Unknown', 'line' => 'Unknown');
+	}
+
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Get Default Template
+	 *
+	 * @access	private
+	 * @return	string
+	 */
+	function _default_template()
+	{	
+		$this->_template = '	
+		<div style="margin:15px;background-color:#ccc;">
+		<table border="0" cellpadding="4" cellspacing="1" style="width:100%;">		
+		{rows}
+		</table></div>';
+		
+		$this->_template_rows = '
+		<tr>
+		<td style="background-color:#fff;width:140px;font-size:12px;font-weight:bold;">{item}</td>
+		<td style="background-color:#fff;font-size:12px;">{result}</td>
+		</tr>
+		';	
+	}
+	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Parse Template
+	 *
+	 * Harvests the data within the template {pseudo-variables}
+	 *
+	 * @access	private
+	 * @return	void
+	 */
+ 	function _parse_template()
+ 	{
+ 		if ( ! is_null($this->_template_rows))
+ 		{
+ 			return;
+ 		}
+ 		
+ 		if (is_null($this->_template))
+ 		{
+ 			$this->_default_template();
+ 			return;
+ 		}
+ 		
+		if ( ! preg_match("/\{rows\}(.*?)\{\/rows\}/si", $this->_template, $match))
+		{
+ 			$this->_default_template();
+ 			return;
+		}
+
+		$this->_template_rows = $match['1'];
+		$this->_template = str_replace($match['0'], '{rows}', $this->_template); 	
+ 	}
+ 	
+}
+// END Unit_test Class
+
+/**
+ * Helper functions to test boolean true/false
+ * 
+ *
+ * @access	private
+ * @return	bool
+ */
+function is_true($test)
+{
+	return (is_bool($test) AND $test === TRUE) ? TRUE : FALSE;
+}
+function is_false($test)
+{
+	return (is_bool($test) AND $test === FALSE) ? TRUE : FALSE;
+}
+
+?>
\ No newline at end of file
diff --git a/system/libraries/Upload.php b/system/libraries/Upload.php
new file mode 100644
index 0000000..6d12dbc
--- /dev/null
+++ b/system/libraries/Upload.php
@@ -0,0 +1,775 @@
+<?php  if (!defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * Code Igniter
+ *
+ * An open source application development framework for PHP 4.3.2 or newer
+ *
+ * @package		CodeIgniter
+ * @author		Rick Ellis
+ * @copyright	Copyright (c) 2006, pMachine, Inc.
+ * @license		http://www.codeignitor.com/user_guide/license.html 
+ * @link		http://www.codeigniter.com
+ * @since		Version 1.0
+ * @filesource
+ */
+ 
+// ------------------------------------------------------------------------
+
+/**
+ * File Uploading Class
+ * 
+ * @package		CodeIgniter
+ * @subpackage	Libraries
+ * @category	Uploads
+ * @author		Rick Ellis
+ * @link		http://www.codeigniter.com/user_guide/libraries/file_uploading.html
+ */
+class CI_Upload {
+	
+	var $max_size		= 0;
+	var $max_width		= 0;
+	var $max_height		= 0;
+	var $allowed_types	= "";
+	var $file_temp		= "";
+	var $file_name		= "";
+	var $orig_name		= "";
+	var $file_type		= "";
+	var $file_size		= "";
+	var $file_ext		= "";
+	var $file_path		= "";
+	var $overwrite		= FALSE;
+	var $encrypt_name	= FALSE;
+	var $is_image		= FALSE;
+	var $image_width	= '';
+	var $image_height	= '';
+	var $image_type		= '';
+	var $image_size_str	= '';    
+	var $error_msg		= array();
+	var $mimes			= array();
+	var $remove_spaces	= TRUE;
+	var $xss_clean		= FALSE;
+	var $temp_prefix	= "temp_file_";
+		
+	/**
+	 * Constructor
+	 *
+	 * @access	public
+	 */
+	function CI_Upload($props = array())
+	{
+		if (count($props) > 0)
+		{
+			$this->initialize($props);
+		}
+		
+		log_message('debug', "Upload Class Initialized");
+	}
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Initialize preferences
+	 *
+	 * @access	public
+	 * @param	array
+	 * @return	void
+	 */	
+	function initialize($config = array())
+	{  
+		foreach ($config as $key => $val)
+		{
+			$method = 'set_'.$key;
+			if (method_exists($this, $method))
+			{
+				$this->$method($val);
+			}
+			else
+			{
+				$this->$key = $val;
+			}			
+		}
+	}
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Perform the file upload
+	 *
+	 * @access	public
+	 * @return	bool
+	 */	
+    function do_upload()
+    {
+		// Is $_FILES['userfile'] set? If not, no reason to continue.
+    	if ( ! isset($_FILES['userfile']))
+    	{
+			$this->set_error('upload_userfile_not_set');
+			return FALSE;
+    	}
+    	
+		// Is the upload path valid?
+		if ( ! $this->validate_upload_path())
+		{
+			return FALSE;
+		}
+		    	    	
+		// Was the file able to be uploaded? If not, determine the reason why.
+		if ( ! is_uploaded_file($_FILES['userfile']['tmp_name'])) 
+		{
+            $error = ( ! isset($_FILES['userfile']['error'])) ? 4 : $_FILES['userfile']['error'];
+
+            switch($error)
+            { 
+                case 1  :   $this->set_error('upload_file_exceeds_limit');
+                    break;
+                case 3  :   $this->set_error('upload_file_partial');
+                    break;
+                case 4  :   $this->set_error('upload_no_file_selected');
+                    break;
+                default :   $this->set_error('upload_no_file_selected');
+                    break;
+            }
+            
+            return FALSE;
+		}
+ 
+		// Set the uploaded data as class variables
+		$this->file_temp = $_FILES['userfile']['tmp_name'];		
+		$this->file_name = $_FILES['userfile']['name'];
+		$this->file_size = $_FILES['userfile']['size'];		
+		$this->file_type = preg_replace("/^(.+?);.*$/", "\\1", $_FILES['userfile']['type']);
+		$this->file_type = strtolower($this->file_type);
+		$this->file_ext	 = $this->get_extension($_FILES['userfile']['name']);
+		
+		// Convert the file size to kilobytes
+		if ($this->file_size > 0)
+		{
+			$this->file_size = round($this->file_size/1024, 2);
+		}
+
+		// Is the file type allowed to be uploaded?
+        if ( ! $this->is_allowed_filetype())
+        {
+			$this->set_error('upload_invalid_filetype');
+			return FALSE;
+        }
+
+		// Is the file size within the allowed maximum?
+        if ( ! $this->is_allowed_filesize())
+        {
+			$this->set_error('upload_invalid_filesize');
+			return FALSE;    
+        }
+        
+		// Are the image dimensions within the allowed size?
+		// Note: This can fail if the server has an open_basdir restriction.
+        if ( ! $this->is_allowed_dimensions())
+        {
+			$this->set_error('upload_invalid_dimensions');
+			return FALSE;    
+        }
+        
+		// Sanitize the file name for security
+        $this->file_name = $this->clean_file_name($this->file_name);
+        
+		// Remove white spaces in the name
+        if ($this->remove_spaces == TRUE)
+        {
+            $this->file_name = preg_replace("/\s+/", "_", $this->file_name);
+        }
+        
+		/*
+		 * Validate the file name
+		 * This function appends an number onto the end of
+		 * the file if one with the same name already exists.
+		 * If it returns false there was a problem.
+		 */
+		$this->orig_name = $this->file_name;
+
+		if ($this->overwrite == FALSE)
+		{
+			$this->file_name = $this->set_filename($this->file_path, $this->file_name);
+			
+			if ($this->file_name === FALSE)
+			{
+				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
+		 * reliably work in most environments
+		 */
+		if ( ! @copy($this->file_temp, $this->file_path.$this->file_name))
+		{                            
+			if ( ! @move_uploaded_file($this->file_temp, $this->file_path.$this->file_name))
+			{
+				 $this->set_error('upload_destination_error');
+				 return FALSE;
+			}
+		} 
+		
+		/*
+		 * Run the file through the XSS hacking filter
+		 * This helps prevent malicious code from being
+		 * embedded within a file.  Scripts can easily 
+		 * be disguised as images or other file types.
+		 */
+		if ($this->xss_clean == TRUE)
+		{
+			$this->do_xss_clean();
+		}
+ 
+		/*
+		 * Set the finalized image dimensions
+		 * This sets the image width/height (assuming the
+		 * file was an image).  We use this information
+		 * in the "data" function.
+		 */
+        $this->set_image_properties($this->file_path.$this->file_name);        
+        
+		return TRUE;
+    }
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Finalized Data Array 
+	 *	
+	 * Returns an associative array containing all of the information 
+	 * related to the upload, allowing the developer easy access in one array.
+	 *
+	 * @access	public
+	 * @return	array
+	 */	
+	function data()
+	{
+		return array (
+					'file_name'			=> $this->file_name,
+					'file_type'			=> $this->file_type,
+					'file_path'			=> $this->file_path,
+					'full_path'			=> $this->file_path.$this->file_name,
+					'raw_name'			=> str_replace($this->file_ext, '', $this->file_name),
+					'orig_name'			=> $this->orig_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,
+				);
+	}
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Set Upload Path 
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	void
+	 */	
+    function set_upload_path($path)
+    {     
+		$this->file_path = $path;
+	}
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Set the file name 
+	 *
+	 * This function takes a filename/path as input and looks for the 
+	 * existnace of a file with the same name. If found, it will append a 
+	 * number to the end of the filename to avoid overwritting a pre-existing file.
+	 *
+	 * @access	public
+	 * @param	string
+	 * @param	string
+	 * @return	string
+	 */	
+	function set_filename($path, $filename)
+	{
+		if ($this->encrypt_name == TRUE)
+		{		
+			mt_srand();
+			$filename = md5(uniqid(mt_rand())).$this->file_ext; 			
+		}
+	
+		if ( ! file_exists($path.$filename))
+		{
+			return $filename;
+		}
+	
+		$filename = str_replace($this->file_ext, '', $filename);
+		
+		$new_filename = '';
+		for ($i = 1; $i < 100; $i++)
+		{			
+			if ( ! file_exists($path.$filename.$i.$this->file_ext))
+			{
+				$new_filename = $filename.$i.$this->file_ext;
+				break;
+			}
+		}
+
+		if ($new_filename == '')
+		{
+			$this->set_error('upload_bad_filename');
+			return FALSE;
+		}
+		else
+		{
+			return $new_filename;
+		}
+	}
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Set Maximum File Size 
+	 *
+	 * @access	public
+	 * @param	integer
+	 * @return	void
+	 */	
+    function set_max_filesize($n)
+    {
+        $this->max_size = ( ! eregi("^[[:digit:]]+$", $n)) ? 0 : $n; 
+    }
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Set Maximum Image Width 
+	 *
+	 * @access	public
+	 * @param	integer
+	 * @return	void
+	 */	
+    function set_max_width($n)
+    {    
+        $this->max_width = ( ! eregi("^[[:digit:]]+$", $n)) ? 0 : $n; 
+    }
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Set Maximum Image Height 
+	 *
+	 * @access	public
+	 * @param	integer
+	 * @return	void
+	 */	
+    function set_max_height($n)
+    {
+        $this->max_height = ( ! eregi("^[[:digit:]]+$", $n)) ? 0 : $n; 
+    }
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Set Allowed File Types 
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	void
+	 */	
+    function set_allowed_types($types)
+    {
+    	$this->allowed_types = explode('|', $types);
+    }
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Set Image Properties
+	 *
+	 * Uses GD to determine the width/height/type of image
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	void
+	 */	
+    function set_image_properties($path = '')
+    {
+        if ( ! $this->is_image())
+        {
+            return;    
+        }
+            
+        if (function_exists('getimagesize')) 
+        {
+            if (FALSE !== ($D = @getimagesize($path)))
+            {	
+				$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
+			}
+        }
+    }
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Set XSS Clean
+	 *
+	 * Enables the XSS flag so that the file that was uploaded
+	 * will be run through the XSS filter.
+	 *
+	 * @access	public
+	 * @param	bool
+	 * @return	void
+	 */
+	function set_xss_clean($flag = FALSE)
+	{
+		$this->xss_clean = ($flag == TRUE) ? TRUE : FALSE;
+	}
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Validate the image
+	 *
+	 * @access	public
+	 * @return	bool
+	 */	
+    function is_image()
+    {
+        $img_mimes = array(
+                            'image/gif',
+                            'image/jpg', 
+                            'image/jpe',
+                            'image/jpeg', 
+                            'image/pjpeg',
+                            'image/png',
+                            'image/x-png'
+                           );
+    
+
+		return (in_array($this->file_type, $img_mimes)) ? TRUE : FALSE;
+    }
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Verify that the filetype is allowed
+	 *
+	 * @access	public
+	 * @return	bool
+	 */	
+    function is_allowed_filetype()
+    {
+    	if (count($this->allowed_types) == 0)
+    	{
+			$this->set_error('upload_no_file_types');
+			return FALSE;
+    	}
+    	     	 
+    	foreach ($this->allowed_types as $val)
+    	{
+    		$mime = $this->mimes_types(strtolower($val));
+    	
+    		if (is_array($mime))
+    		{
+    			if (in_array($this->file_type, $mime))
+    			{
+    				return TRUE;
+    			}
+    		}
+    		else
+    		{
+				if ($mime == $this->file_type)
+				{
+					return TRUE;
+				}	
+    		}    	
+    	}
+    	
+    	return FALSE;
+    }
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Verify that the file is within the allowed size
+	 *
+	 * @access	public
+	 * @return	bool
+	 */	
+    function is_allowed_filesize()
+    {    
+        if ($this->max_size != 0  AND  $this->file_size > $this->max_size)
+        {
+            return FALSE;
+        }
+        else
+        {
+            return TRUE;
+        }
+    }
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Verify that the image is within the allowed width/height
+	 *
+	 * @access	public
+	 * @return	bool
+	 */	
+    function is_allowed_dimensions()
+    {
+        if ( ! $this->is_image())
+        {
+            return TRUE;    
+        }
+    
+        if (function_exists('getimagesize')) 
+        {
+            $D = @getimagesize($this->file_temp);
+            
+            if ($this->max_width > 0 AND $D['0'] > $this->max_width)
+            {
+                return FALSE;
+            }
+
+            if ($this->max_height > 0 AND $D['1'] > $this->max_height)
+            {
+                return FALSE;
+            }
+                       
+            return TRUE;
+        }
+
+        return TRUE;
+    }
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * VAlidate Upload Path 
+	 *
+	 * Verifies that it is a valid upload path with proper permissions.
+	 *
+	 *
+	 * @access	public
+	 * @return	bool
+	 */	
+    function validate_upload_path()
+    {    
+    	if ($this->file_path == '')
+    	{ 
+			$this->set_error('upload_no_filepath');
+			return FALSE;
+    	}
+    	
+		if (function_exists('realpath') AND @realpath($this->file_path) !== FALSE)
+		{
+			$this->file_path = str_replace("\\", "/", realpath($this->file_path)); 
+		}
+    
+        if ( ! @is_dir($this->file_path))
+        {
+			$this->set_error('upload_no_filepath');
+			return FALSE;
+        }
+        
+        if ( ! is_writable($this->file_path))
+        {
+			$this->set_error('upload_not_writable');
+			return FALSE;
+        }
+                
+		$this->file_path = preg_replace("/(.+?)\/*$/", "\\1/",  $this->file_path);
+		return TRUE;
+    }
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Extract the file extension
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	string
+	 */	
+	function get_extension($filename)
+	{
+		$x = explode('.', $filename);
+		return '.'.end($x);
+	}	
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Clean the file name for security
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	string
+	 */		
+	function clean_file_name($filename)
+	{
+        $bad = array(
+						"<!--",
+						"-->",
+						"'",
+						"<",
+						">",
+						'"',
+						'&',
+						'$',
+						'=',
+						';',
+						'?',
+						'/',
+						"%20",
+						"%22",
+						"%3c",		// <
+						"%253c", 	// <
+						"%3e", 		// >
+						"%0e", 		// >
+						"%28", 		// (  
+						"%29", 		// ) 
+						"%2528", 	// (
+						"%26", 		// &
+						"%24", 		// $
+						"%3f", 		// ?
+						"%3b", 		// ;
+						"%3d"		// =
+        			);
+        			
+        foreach ($bad as $val)
+        {
+			$filename = str_replace($val, '', $filename);   
+        }
+        
+		return $filename;
+	}
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Runs the file through the XSS clean function
+	 *
+	 * This prevents people from embedding malicious code in their files.  
+	 * I'm not sure that it won't negatively affect certain files in unexpected ways,
+	 * but so far I haven't found that it causes trouble.
+	 *
+	 * @access	public
+	 * @return	void
+	 */	
+	function do_xss_clean()
+	{		
+		$file = $this->file_path.$this->file_name;
+		
+		if (filesize($file) == 0) 
+		{
+			return FALSE;
+		}
+	
+		if ( ! $fp = @fopen($file, 'rb'))
+		{
+			return FALSE;
+		}
+			
+        flock($fp, LOCK_EX);
+
+		$data = fread($fp, filesize($file)); 
+		
+		$obj =& get_instance();	
+		$data = $obj->input->xss_clean($data);
+
+        fwrite($fp, $data);
+        flock($fp, LOCK_UN);
+        fclose($fp);
+	}
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Set an error message
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	void
+	 */	
+	function set_error($msg)
+	{
+		$obj =& get_instance();	
+		$obj->lang->load('upload');
+		
+		if (is_array($msg))
+		{
+			foreach ($msg as $val)
+			{
+				$msg = ($obj->lang->line($val) == FALSE) ? $val : $obj->lang->line($val);				
+				$this->error_msg[] = $msg;
+				log_message('error', $msg);
+			}		
+		}
+		else
+		{
+			$msg = ($obj->lang->line($msg) == FALSE) ? $msg : $obj->lang->line($msg);
+			$this->error_msg[] = $msg;
+			log_message('error', $msg);
+		}
+	}
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Display the error message
+	 *
+	 * @access	public
+	 * @param	string
+	 * @param	string
+	 * @return	string
+	 */	
+	function display_errors($open = '<p>', $close = '</p>')
+	{
+		$str = '';
+		foreach ($this->error_msg as $val)
+		{
+			$str .= $open.$val.$close;
+		}
+	
+		return $str;
+	}
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * List of Mime Types
+	 *
+	 * This is a list of mime types.  We use it to validate
+	 * the "allowed types" set by the developer
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	string
+	 */	
+	function mimes_types($mime)
+	{
+		if (count($this->mimes) == 0)
+		{
+			if (@include(APPPATH.'config/mimes'.EXT))
+			{
+				$this->mimes = $mimes;
+				unset($mimes);
+			}
+		}
+	
+		return ( ! isset($this->mimes[$mime])) ? FALSE : $this->mimes[$mime];
+	}
+
+}
+// END Upload Class
+?>
\ No newline at end of file
diff --git a/system/libraries/Validation.php b/system/libraries/Validation.php
new file mode 100644
index 0000000..df8c70e
--- /dev/null
+++ b/system/libraries/Validation.php
@@ -0,0 +1,692 @@
+<?php  if (!defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * Code Igniter
+ *
+ * An open source application development framework for PHP 4.3.2 or newer
+ *
+ * @package		CodeIgniter
+ * @author		Rick Ellis
+ * @copyright	Copyright (c) 2006, pMachine, Inc.
+ * @license		http://www.codeignitor.com/user_guide/license.html 
+ * @link		http://www.codeigniter.com
+ * @since		Version 1.0
+ * @filesource
+ */
+ 
+// ------------------------------------------------------------------------
+
+/**
+ * Validation Class
+ * 
+ * @package		CodeIgniter
+ * @subpackage	Libraries
+ * @category	Validation
+ * @author		Rick Ellis
+ * @link		http://www.codeigniter.com/user_guide/libraries/validation.html
+ */
+class CI_Validation {
+	
+	var $error_string		= '';
+	var $_error_array		= array();
+	var $_rules				= array();
+	var $_fields			= array();
+	var $_error_messages	= array();
+	var $_current_field  	= '';
+	var $_safe_form_data 	= FALSE;
+	var $_error_prefix		= '<p>';
+	var $_error_suffix		= '</p>';
+	var $obj;
+	
+
+	/**
+	 * Constructor 
+	 *
+	 */	
+	function CI_Validation()
+	{	
+		$this->obj =& get_instance();
+		log_message('debug', "Validation Class Initialized");
+	}
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Set Fields
+	 *
+	 * This function takes an array of field names as input
+	 * and generates class variables with the same name, which will
+	 * either be blank or contain the $_POST value corresponding to it
+	 *
+	 * @access	public
+	 * @param	string
+	 * @param	string
+	 * @return	void
+	 */
+	function set_fields($data = '', $field = '')
+	{	
+		if ($data == '')
+			return;
+	
+		if ( ! is_array($data))
+		{
+			if ($field == '')
+				return;
+			
+			$data = array($data => $field);
+		}
+	
+		$this->_fields = $data;
+	
+		foreach($this->_fields as $key => $val)
+		{		
+			$this->$key = ( ! isset($_POST[$key]) OR is_array($_POST[$key])) ? '' : $this->prep_for_form($_POST[$key]);
+			
+			$error = $key.'_error';
+			if ( ! isset($this->$error))
+			{
+				$this->$error = '';
+			}
+		}		
+	}
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Set Rules
+	 *
+	 * This function takes an array of field names and validation 
+	 * rules as input ad simply stores is for use later.
+	 *
+	 * @access	public
+	 * @param	mixed
+	 * @param	string
+	 * @return	void
+	 */
+	function set_rules($data, $rules = '')
+	{
+		if ( ! is_array($data))
+		{
+			if ($rules == '')
+				return;
+				
+			$data[$data] = $rules;
+		}
+	
+		foreach ($data as $key => $val)
+		{
+			$this->_rules[$key] = $val;
+		}
+	}
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * 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.
+	 *
+	 * @access	public
+	 * @param	string
+	 * @param	string
+	 * @return	string
+	 */
+	function set_message($lang, $val = '')
+	{
+		if ( ! is_array($lang))
+		{
+			$lang = array($lang => $val);
+		}
+	
+		$this->_error_messages = array_merge($this->_error_messages, $lang);
+	}
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Set The Error Delimiter
+	 *
+	 * Permits a prefix/suffix to be added to each error message
+	 *
+	 * @access	public
+	 * @param	string
+	 * @param	string
+	 * @return	void
+	 */	
+	function set_error_delimiters($prefix = '<p>', $suffix = '</p>')
+	{
+		$this->_error_prefix = $prefix;
+		$this->_error_suffix = $suffix;
+	}
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Run the Validator
+	 *
+	 * This function does all the work.
+	 *
+	 * @access	public
+	 * @return	bool
+	 */		
+	function run()
+	{
+		// Do we even have any data to process?  Mm?
+		if (count($_POST) == 0 OR count($this->_rules) == 0)
+		{
+			return FALSE;
+		}
+	
+		// Load the language file containing error messages
+		$this->obj->lang->load('validation');
+							
+		// Cycle through the rules and test for errors
+		foreach ($this->_rules as $field => $rules)
+		{
+			//Explode out the rules!
+			$ex = explode('|', $rules);
+
+			// Is the field required?  If not, if the field is blank  we'll move on to the next text
+			if ( ! in_array('required', $ex))
+			{
+				if ( ! isset($_POST[$field]) OR $_POST[$field] == '')
+				{
+					continue;
+				}
+			}
+			
+			/*
+			 * Are we dealing with an "isset" rule?
+			 *
+			 * Before going further, we'll see if one of the rules
+			 * is to check whether the item is set (typically this
+			 * applies only to checkboxes).  If so, we'll
+			 * test for it here since there's not reason to go
+			 * further
+			 */
+			if ( ! isset($_POST[$field]))
+			{			
+				if (in_array('isset', $ex) OR in_array('required', $ex))
+				{
+					if ( ! isset($this->messages['isset'])) 
+					{
+						if (FALSE === ($line = $this->obj->lang->line('isset')))
+						{
+							$line = 'The field was not set';
+						}							
+					}
+					else
+					{
+						$line = $this->_error_messages['isset'];
+					}
+					
+					$field = ( ! isset($this->_fields[$field])) ? $field : $this->_fields[$field];
+					$this->_error_array[] = sprintf($line, $field);	
+				}
+						
+				continue;
+			}
+	
+			/*
+			 * Set the current field
+			 *
+			 * The various prepping functions need to know the
+			 * current field name so they can do this:
+			 *
+			 * $_POST[$this->_current_field] == 'bla bla';
+			 */
+			$this->_current_field = $field;
+
+			// Cycle through the rules!
+			foreach ($ex As $rule)
+			{
+
+				// Is the rule a callback?			
+				$callback = FALSE;
+				if (substr($rule, 0, 9) == 'callback_')
+				{
+					$rule = substr($rule, 9);
+					$callback = TRUE;
+				}			
+			
+				// Strip the parameter (if exists) from the rule
+				// Rules can contain a parameter: max_length[5]
+				$param = FALSE;
+				if (preg_match("/.*?(\[.*?\]).*/", $rule, $match))
+				{
+					$param = substr(substr($match['1'], 1), 0, -1);
+					$rule  = str_replace($match['1'], '', $rule);
+				}
+
+				// Call the function that corresponds to the rule
+				if ($callback === TRUE)
+				{
+					if ( ! method_exists($this->obj, $rule))
+					{ 		
+						continue;
+					}
+					
+					$result = $this->obj->$rule($_POST[$field], $param);
+				}
+				else
+				{				
+					if ( ! method_exists($this, $rule))
+					{
+						/*
+						 * Run the native PHP function if called for
+						 *
+						 * 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))
+						{
+							$_POST[$field] = $rule($_POST[$field]);
+							$this->$field = $_POST[$field];
+						}
+											
+						continue;
+					}
+					
+					$result = $this->$rule($_POST[$field], $param);
+				}
+				
+				// Did the rule test negatively?  If so, grab the error.
+				if ($result === FALSE)
+				{
+					if ( ! isset($this->_error_messages[$rule])) 
+					{
+						if (FALSE === ($line = $this->obj->lang->line($rule)))
+						{
+							$line = 'Unable to access an error message corresponding to your field name.';
+						}						
+					}
+					else
+					{
+						$line = $this->_error_messages[$rule];;
+					}				
+
+					// Build the error message
+					$mfield = ( ! isset($this->_fields[$field])) ? $field : $this->_fields[$field];
+					$mparam = ( ! isset($this->_fields[$param])) ? $param : $this->_fields[$param];
+					$message = sprintf($line, $mfield, $mparam);
+					
+					// Set the error variable.  Example: $this->username_error
+					$error = $field.'_error';
+					$this->$error = $this->_error_prefix.$message.$this->_error_suffix;
+
+					// Add the error to the error array
+					$this->_error_array[] = $message;				
+					continue 2;
+				}
+			}
+		}
+		
+		$total_errors = count($this->_error_array);
+
+		/*
+		 * Recompile the class variables
+		 *
+		 * If any prepping functions were called the $_POST data
+		 * might now be different then the corresponding class
+		 * variables so we'll set them anew.
+		 */	
+		if ($total_errors > 0)
+		{
+			$this->_safe_form_data = TRUE;
+		}
+		
+		$this->set_fields();
+ 
+		// Did we end up with any errors?
+		if ($total_errors == 0)
+		{
+			return TRUE;
+		}
+		
+		// Generate the error string
+		foreach ($this->_error_array as $val)
+		{
+			$this->error_string .= $this->_error_prefix.$val.$this->_error_suffix."\n";
+		}
+
+		return FALSE;
+	}
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Required
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	bool
+	 */
+	function required($str)
+	{
+		if ( ! is_array($str))
+		{
+			return (trim($str) == '') ? FALSE : TRUE;
+		}
+		else
+		{
+			return ( ! empty($str));
+		}
+	}
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Match one field to another
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	bool
+	 */
+	function matches($str, $field)
+	{
+		if ( ! isset($_POST[$field]))
+		{
+			return FALSE;
+		}
+		
+		return ($str !== $_POST[$field]) ? FALSE : TRUE;
+	}
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Minimum Length
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	bool
+	 */	
+	function min_length($str, $val)
+	{
+		if ( ! ctype_digit($val))
+		{
+			return FALSE;
+		}
+	
+		return (strlen($str) < $val) ? FALSE : TRUE;
+	}
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Max Length
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	bool
+	 */	
+	function max_length($str, $val)
+	{
+		if ( ! ctype_digit($val))
+		{
+			return FALSE;
+		}
+	
+		return (strlen($str) > $val) ? FALSE : TRUE;
+	}
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Exact Length
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	bool
+	 */	
+	function exact_length($str, $val)
+	{
+		if ( ! ctype_digit($val))
+		{
+			return FALSE;
+		}
+	
+		return (strlen($str) != $val) ? FALSE : TRUE;
+	}
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Valid Email
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	bool
+	 */	
+	function valid_email($str)
+	{
+		return ( ! preg_match("/^([a-z0-9\+_\-]+)(\.[a-z0-9\+_\-]+)*@([a-z0-9\-]+\.)+[a-z]{2,6}$/ix", $str)) ? FALSE : TRUE;
+	}
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Alpha
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	bool
+	 */		
+	function alpha($str)
+	{
+		return ( ! preg_match("/^([-a-z])+$/i", $str)) ? FALSE : TRUE;
+	}
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Alpha-numeric
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	bool
+	 */	
+	function alpha_numeric($str)
+	{
+		return ( ! preg_match("/^([-a-z0-9])+$/i", $str)) ? FALSE : TRUE;
+	}
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Alpha-numeric with underscores and dashes
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	bool
+	 */	
+	function alpha_dash($str)
+	{
+		return ( ! preg_match("/^([-a-z0-9_-])+$/i", $str)) ? FALSE : TRUE;
+	}
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Numeric
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	bool
+	 */	
+	function numeric($str)
+	{
+		return ( ! ctype_digit($str)) ? FALSE : TRUE;
+	}
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Set Select
+	 *
+	 * Enables pull-down lists to be set to the value the user
+	 * selected in the event of an error
+	 *
+	 * @access	public
+	 * @param	string
+	 * @param	string
+	 * @return	string
+	 */	
+	function set_select($field = '', $value = '')
+	{
+		if ($field == '' OR $value == '' OR  ! isset($_POST[$field]))
+		{
+			return '';
+		}
+			
+		if ($_POST[$field] == $value)
+		{
+			return ' selected="selected"';
+		}
+	}
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Set Radio
+	 *
+	 * Enables radio buttons to be set to the value the user
+	 * selected in the event of an error
+	 *
+	 * @access	public
+	 * @param	string
+	 * @param	string
+	 * @return	string
+	 */	
+	function set_radio($field = '', $value = '')
+	{
+		if ($field == '' OR $value == '' OR  ! isset($_POST[$field]))
+		{
+			return '';
+		}
+			
+		if ($_POST[$field] == $value)
+		{
+			return ' checked="checked"';
+		}
+	}
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Set Checkbox
+	 *
+	 * Enables checkboxes to be set to the value the user
+	 * selected in the event of an error
+	 *
+	 * @access	public
+	 * @param	string
+	 * @param	string
+	 * @return	string
+	 */	
+	function set_checkbox($field = '', $value = '')
+	{
+		if ($field == '' OR $value == '' OR  ! isset($_POST[$field]))
+		{
+			return '';
+		}
+			
+		if ($_POST[$field] == $value)
+		{
+			return ' checked="checked"';
+		}
+	}
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Prep data for form
+	 *
+	 * This function allows HTML to be safely shown in a form.
+	 * Special characters are converted.
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	string
+	 */
+    function prep_for_form($str = '')
+    {
+    	if ($this->_safe_form_data == FALSE OR $str == '')
+    	{
+    		return $str;
+    	}
+            
+		return str_replace(array("'", '"', '<', '>'), array("&#39;", "&quot;", '&lt;', '&gt;'), stripslashes($str));
+    }
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Prep URL
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	string
+	 */	
+    function prep_url($str = '')
+    {
+		if ($str == 'http://' OR $str == '')
+		{
+			$_POST[$this->_current_field] = '';
+			return;
+		}
+		
+		if (substr($str, 0, 7) != 'http://' && substr($str, 0, 8) != 'https://')
+		{
+			$str = 'http://'.$str;
+		}
+		
+		$_POST[$this->_current_field] = $str;
+    }
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Strip Image Tags
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	string
+	 */	
+    function strip_image_tags($str)
+    {                    
+        $_POST[$this->_current_field] = $this->input->strip_image_tags($str);
+    }
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * XSS Clean
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	string
+	 */	
+	function xss_clean($str)
+	{
+		$_POST[$this->_current_field] = $this->obj->input->xss_clean($str);
+	}
+	
+	// --------------------------------------------------------------------
+	
+	/**
+	 * Convert PHP tags to entities
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	string
+	 */	
+    function encode_php_tags($str)
+    { 
+    	$_POST[$this->_current_field] = str_replace(array('<?php', '<?PHP', '<?', '?>'),  array('&lt;?php', '&lt;?PHP', '&lt;?', '?&gt;'), $str);
+	}
+
+}
+// END Validation Class
+?>
\ No newline at end of file
diff --git a/system/libraries/Xmlrpc.php b/system/libraries/Xmlrpc.php
new file mode 100644
index 0000000..9eeb46a
--- /dev/null
+++ b/system/libraries/Xmlrpc.php
@@ -0,0 +1,1409 @@
+<?php  if (!defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * Code Igniter
+ *
+ * An open source application development framework for PHP 4.3.2 or newer
+ *
+ * @package		CodeIgniter
+ * @author		Rick Ellis
+ * @copyright	Copyright (c) 2006, pMachine, Inc.
+ * @license		http://www.codeignitor.com/user_guide/license.html 
+ * @link		http://www.codeigniter.com
+ * @since		Version 1.0
+ * @filesource
+ */
+ 
+if ( ! function_exists('xml_parser_create'))
+{	
+    show_error('Your PHP installation does not support XML');
+}
+
+/**
+ * XML-RPC request handler class
+ * 
+ * @package		CodeIgniter
+ * @subpackage	Libraries
+ * @category	XML-RPC
+ * @author		Paul Burdick
+ * @link		http://www.codeigniter.com/user_guide/libraries/xmlrpc.html
+ */
+class CI_XML_RPC {
+
+	var $debug			= FALSE; 	// Debugging on or off	
+	var $xmlrpcI4		= 'i4'; 
+	var $xmlrpcInt		= 'int';
+	var $xmlrpcBoolean	= 'boolean';
+	var $xmlrpcDouble	= 'double';	
+	var $xmlrpcString	= 'string';
+	var $xmlrpcDateTime	= 'dateTime.iso8601';
+	var $xmlrpcBase64	= 'base64';
+	var $xmlrpcArray	= 'array';
+	var $xmlrpcStruct	= 'struct';
+	
+	var $xmlrpcTypes	= array();
+	var $valid_parents	= array();
+	var $xmlrpcerr		= array();	// Response numbers
+	var $xmlrpcstr		= array();  // Response strings
+	
+	var $xmlrpc_defencoding = 'UTF-8';
+	var $xmlrpcName			= 'XML-RPC for CodeIgniter';
+	var $xmlrpcVersion		= '1.1';
+	var $xmlrpcerruser		= 800; // Start of user errors
+	var $xmlrpcerrxml		= 100; // Start of XML Parse errors
+	var $xmlrpc_backslash	= ''; // formulate backslashes for escaping regexp
+	
+	var $client;
+	var $method;
+	var $data;
+	var $message			= '';
+	var $error				= '';  		// Error string for request
+	var $result;
+	var $response			= array();  // Response from remote server
+
+
+	//-------------------------------------
+    //  VALUES THAT MULTIPLE CLASSES NEED
+    //-------------------------------------   
+
+	function CI_XML_RPC ($config = array()) 
+	{
+		
+		$this->xmlrpcName 		= $this->xmlrpcName;
+		$this->xmlrpc_backslash = chr(92).chr(92);
+		
+		// Types for info sent back and forth
+		$this->xmlrpcTypes = array(
+			$this->xmlrpcI4       => '1',
+			$this->xmlrpcInt      => '1',
+			$this->xmlrpcBoolean  => '1',
+			$this->xmlrpcString   => '1',
+			$this->xmlrpcDouble   => '1',
+			$this->xmlrpcDateTime => '1',
+			$this->xmlrpcBase64   => '1',
+			$this->xmlrpcArray    => '2',
+			$this->xmlrpcStruct   => '3'
+			);
+			
+		// 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')
+									 );
+			
+			
+		// XML-RPC Responses
+		$this->xmlrpcerr['unknown_method'] = '1';
+		$this->xmlrpcstr['unknown_method'] = 'This is not a known method for this XML-RPC Server';
+		$this->xmlrpcerr['invalid_return'] = '2';
+		$this->xmlrpcstr['invalid_return'] = 'The XML data receieved was either invalid or not in the correct form for XML-RPC.  Turn on debugging to examine the XML data further.';
+		$this->xmlrpcerr['incorrect_params'] = '3';
+		$this->xmlrpcstr['incorrect_params'] = 'Incorrect parameters were passed to method';
+		$this->xmlrpcerr['introspect_unknown'] = '4';
+		$this->xmlrpcstr['introspect_unknown'] = "Cannot inspect signature for request: method unknown";
+		$this->xmlrpcerr['http_error'] = '5';
+		$this->xmlrpcstr['http_error'] = "Did not receive a '200 OK' response from remote server.";
+		$this->xmlrpcerr['no_data'] = '6';
+		$this->xmlrpcstr['no_data'] ='No data received from server.';
+		
+		$this->initialize($config);
+		
+		log_message('debug', "XML-RPC Class Initialized");
+	}
+	
+	
+	//-------------------------------------
+    //  Initialize Prefs
+    //-------------------------------------   
+
+	function initialize($config = array()) 
+	{
+		if (sizeof($config) > 0)
+		{
+			foreach ($config as $key => $val)
+			{
+				if (isset($this->$key))
+				{
+					$this->$key = $val;			
+				}
+			}
+		}
+	}
+	// END
+	
+	//-------------------------------------
+    //  Take URL and parse it
+    //-------------------------------------   
+
+	function server($url, $port=80) 
+	{
+		if (substr($url, 0, 4) != "http")
+		{
+			$url = "http://".$url;
+		}
+		
+		$parts = parse_url($url);
+		
+		$path = (!isset($parts['path'])) ? '/' : $parts['path'];
+		
+		if (isset($parts['query']) && $parts['query'] != '')
+		{
+			$path .= '?'.$parts['query'];
+		}	
+		
+		$this->client = new XML_RPC_Client($path, $parts['host'], $port);
+	}
+	// END
+	
+	//-------------------------------------
+	//  Set Timeout
+	//-------------------------------------   
+
+	function timeout($seconds=5) 
+	{
+		if ( ! is_null($this->client) && is_int($seconds))
+		{
+			$this->client->timeout = $seconds;
+		}
+	}
+	// END
+	
+	//-------------------------------------
+	//  Set Methods
+	//-------------------------------------   
+
+	function method($function) 
+	{
+		$this->method = $function;
+	}
+	// END
+	
+	//-------------------------------------
+	//  Take Array of Data and Create Objects
+	//-------------------------------------   
+
+	function request($incoming) 
+	{
+		if ( ! is_array($incoming))
+		{
+			// Send Error
+		}
+		
+		foreach($incoming as $key => $value)
+		{
+			$this->data[$key] = $this->values_parsing($value);
+		}
+	}
+	// END
+	
+	
+	//-------------------------------------
+	//  Set Debug
+	//-------------------------------------   
+
+	function set_debug($flag = TRUE)
+	{
+		$this->debug = ($flag == TRUE) ? TRUE : FALSE;
+	}
+	
+	//-------------------------------------
+	//  Values Parsing
+	//-------------------------------------   
+
+	function values_parsing($value, $return = FALSE)
+	{
+		if (is_array($value) && isset($value['0']))
+		{
+			if ( ! isset($value['1']) OR ! isset($this->xmlrpcTypes[strtolower($value['1'])]))
+			{
+				$temp = new XML_RPC_Values($value['0'], 'string');
+			}
+			elseif(is_array($value['0']) && ($value['1'] == 'struct' OR $value['1'] == 'array'))
+			{
+				while (list($k) = each($value['0']))
+				{
+					$value['0'][$k] = $this->values_parsing($value['0'][$k], TRUE);
+				}
+				
+				$temp = new XML_RPC_Values($value['0'], $value['1']);
+			}
+			else
+			{
+				$temp = new XML_RPC_Values($value['0'], $value['1']);
+			}
+		}
+		else
+		{
+			$temp = new XML_RPC_Values($value, 'string');
+		}
+
+		return $temp;
+	}
+	// END
+
+
+	//-------------------------------------
+	//  Sends XML-RPC Request
+	//-------------------------------------   
+
+	function send_request() 
+	{
+		$this->message = new XML_RPC_Message($this->method,$this->data);
+		$this->message->debug = $this->debug;
+	
+		if ( ! $this->result = $this->client->send($this->message))
+		{
+			$this->error = $this->result->errstr;
+			return FALSE;
+		}
+		elseif( ! is_object($this->result->val))
+		{
+			$this->error = $this->result->errstr;
+			return FALSE;
+		}
+		
+		$this->response = $this->result->decode();
+		
+		return TRUE;
+	}
+	// END
+	
+	//-------------------------------------
+	//  Returns Error
+	//-------------------------------------   
+
+	function display_error() 
+	{
+		return $this->error;
+	}
+	// END
+	
+	//-------------------------------------
+	//  Returns Remote Server Response
+	//-------------------------------------   
+
+	function display_response() 
+	{
+		return $this->response;
+	}
+	// END
+	
+	//-------------------------------------
+	//  Sends an Error Message for Server Request
+	//-------------------------------------   
+	
+	function send_error_message($number, $message)
+	{
+		return new XML_RPC_Response('0',$number, $message);
+	}
+	// END
+	
+	
+	//-------------------------------------
+	//  Send Response for Server Request
+	//-------------------------------------   
+	
+	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
+		
+		$response = $this->values_parsing($response);
+	
+		return new XML_RPC_Response($response);
+	}
+	// END
+	
+} // END XML_RPC Class
+
+	
+	
+/**
+ * XML-RPC Client class
+ * 
+ * @category	XML-RPC
+ * @author		Paul Burdick
+ * @link		http://www.codeigniter.com/user_guide/libraries/xmlrpc.html
+ */
+class XML_RPC_Client extends CI_XML_RPC
+{
+	var $path			= '';
+	var $server			= '';
+	var $port			= 80;
+	var $errno			= '';
+	var $errstring		= '';
+	var $timeout		= 5;
+	var $no_multicall	= false;
+
+	function XML_RPC_Client($path, $server, $port=80)
+	{
+		parent::CI_XML_RPC();
+		
+		$this->port = $port; 
+		$this->server = $server; 
+		$this->path = $path;
+	}
+	
+	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 $this->sendPayload($msg);
+	}
+
+	function sendPayload($msg)
+	{	
+		$fp = @fsockopen($this->server, $this->port,$this->errno, $this->errstr, $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;
+		}
+		
+		if(empty($msg->payload))
+		{
+			// $msg = XML_RPC_Messages
+			$msg->createPayload();
+		}
+		
+		$r = "\r\n";
+		$op  = "POST {$this->path} HTTP/1.0$r";
+		$op .= "Host: {$this->server}$r";
+		$op .= "Content-Type: text/xml$r";
+		$op .= "User-Agent: {$this->xmlrpcName}$r";
+		$op .= "Content-Length: ".strlen($msg->payload). "$r$r";
+		$op .= $msg->payload;
+		
+
+		if (!fputs($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;
+		}
+		$resp = $msg->parseResponse($fp);
+		fclose($fp);
+		return $resp;
+	}
+
+} // end class XML_RPC_Client
+
+
+/**
+ * XML-RPC Response class
+ * 
+ * @category	XML-RPC
+ * @author		Paul Burdick
+ * @link		http://www.codeigniter.com/user_guide/libraries/xmlrpc.html
+ */
+class XML_RPC_Response
+{
+	var $val = 0;
+	var $errno = 0;
+	var $errstr = '';
+	var $headers = array();
+
+	function XML_RPC_Response($val, $code = 0, $fstr = '')
+	{	
+		if ($code != 0)
+		{
+			// error
+			$this->errno = $code;
+			$this->errstr = htmlentities($fstr); 
+		}
+		else if (!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.");
+			$this->val = new XML_RPC_Values();
+		}
+		else
+		{
+			$this->val = $val;
+		}
+	}
+
+	function faultCode()
+	{
+		return $this->errno;
+	}
+
+	function faultString()
+	{
+		return $this->errstr;
+	}
+
+	function value()
+	{
+		return $this->val;
+	}
+	
+	function prepare_response()
+	{
+		$result = "<methodResponse>\n";
+		if ($this->errno)
+		{
+			$result .= '<fault>
+	<value>
+		<struct>
+			<member>
+				<name>faultCode</name>
+				<value><int>' . $this->errno . '</int></value>
+			</member>
+			<member>
+				<name>faultString</name>
+				<value><string>' . $this->errstr . '</string></value>
+			</member>
+		</struct>
+	</value>
+</fault>';
+		}
+		else
+		{
+			$result .= "<params>\n<param>\n" .
+					$this->val->serialize_class() . 
+					"</param>\n</params>";
+		}
+		$result .= "\n</methodResponse>";
+		return $result;
+	}
+	
+	function decode($array=FALSE)
+	{
+		$obj =& get_instance();	
+
+		if ($array !== FALSE && is_array($array))
+		{
+			while (list($key) = each($array))
+			{
+				if (is_array($array[$key]))
+				{
+					$array[$key] = $this->decode($array[$key]);
+				}
+				else
+				{
+					$array[$key] = $obj->input->xss_clean($array[$key]);
+				}
+			}
+			
+			$result = $array;
+		}
+		else
+		{
+			$result = $this->xmlrpc_decoder($this->val);
+			
+			if (is_array($result))
+			{
+				$result = $this->decode($result);
+			}
+			else
+			{
+				$result = $obj->input->xss_clean($result);
+			}
+		}
+		
+		return $result;
+	}
+
+	
+	
+	//-------------------------------------
+	//  XML-RPC Object to PHP Types
+	//------------------------------------- 
+
+	function xmlrpc_decoder($xmlrpc_val)
+	{
+		$kind = $xmlrpc_val->kindOf();
+
+		if($kind == 'scalar')
+		{
+			return $xmlrpc_val->scalarval();
+		}
+		elseif($kind == 'array')
+		{
+			reset($xmlrpc_val->me);
+			list($a,$b) = each($xmlrpc_val->me);
+			$size = sizeof($b);
+			
+			$arr = array();
+
+			for($i = 0; $i < $size; $i++)
+			{
+				$arr[] = $this->xmlrpc_decoder($xmlrpc_val->me['array'][$i]);
+			}
+			return $arr; 
+		}
+		elseif($kind == 'struct')
+		{
+			reset($xmlrpc_val->me['struct']);
+			$arr = array();
+
+			while(list($key,$value) = each($xmlrpc_val->me['struct']))
+			{
+				$arr[$key] = $this->xmlrpc_decoder($value);
+			}
+			return $arr;
+		}
+	}
+	
+	
+	//-------------------------------------
+	//  ISO-8601 time to server or UTC time
+	//------------------------------------- 
+
+	function iso8601_decode($time, $utc=0)
+	{
+		// return a timet in the localtime, or UTC
+		$t = 0;
+		if (ereg("([0-9]{4})([0-9]{2})([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})", $time, $regs))
+		{
+			if ($utc == 1)
+				$t = gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
+			else
+				$t = mktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
+		} 
+		return $t;
+	}
+	
+} // End Response Class
+
+
+
+/**
+ * XML-RPC Message class
+ * 
+ * @category	XML-RPC
+ * @author		Paul Burdick
+ * @link		http://www.codeigniter.com/user_guide/libraries/xmlrpc.html
+ */
+class XML_RPC_Message extends CI_XML_RPC
+{
+	var $payload;
+	var $method_name;
+	var $params			= array();
+	var $xh 			= array();
+
+	function XML_RPC_Message($method, $pars=0)
+	{
+		parent::CI_XML_RPC();
+		
+		$this->method_name = $method;
+		if (is_array($pars) && sizeof($pars) > 0)
+		{
+			for($i=0; $i<sizeof($pars); $i++)
+			{
+				// $pars[$i] = XML_RPC_Values
+				$this->params[] = $pars[$i];
+			}
+		}
+	}
+	
+	//-------------------------------------
+	//  Create Payload to Send
+	//-------------------------------------   
+	
+	function createPayload()
+	{
+		$this->payload = "<?xml version=\"1.0\"?".">\r\n<methodCall>\r\n";
+		$this->payload .= '<methodName>' . $this->method_name . "</methodName>\r\n";
+		$this->payload .= "<params>\r\n";
+		
+		for($i=0; $i<sizeof($this->params); $i++)
+		{
+			// $p = XML_RPC_Values
+			$p = $this->params[$i];
+			$this->payload .= "<param>\r\n".$p->serialize_class()."</param>\r\n";
+		}
+		
+		$this->payload .= "</params>\r\n</methodCall>\r\n";
+	}
+	
+	//-------------------------------------
+	//  Parse External XML-RPC Server's Response
+	//-------------------------------------   
+	
+	function parseResponse($fp)
+	{
+		$data = '';
+		
+		while($datum = fread($fp, 4096))
+		{
+			$data .= $datum;
+		}
+		
+		//-------------------------------------
+		//  DISPLAY HTTP CONTENT for DEBUGGING
+		//-------------------------------------
+		
+		if ($this->debug === TRUE)
+		{
+			echo "<pre>";
+			echo "---DATA---\n" . htmlspecialchars($data) . "\n---END DATA---\n\n";
+			echo "</pre>";
+		}
+		
+		//-------------------------------------
+		//  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;
+		}
+		
+		
+		//-------------------------------------
+		//  Check for HTTP 200 Response
+		//-------------------------------------  
+		
+		if(ereg("^HTTP",$data) && !ereg("^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;
+		}
+		
+		//-------------------------------------
+		//  Create and Set Up XML Parser
+		//------------------------------------- 
+	
+		$parser = xml_parser_create($this->xmlrpc_defencoding);
+
+		$this->xh[$parser]				 = array();
+		$this->xh[$parser]['isf']		 = 0;
+		$this->xh[$parser]['ac']		 = '';
+		$this->xh[$parser]['headers'] 	 = array();
+		$this->xh[$parser]['stack']		 = array();
+		$this->xh[$parser]['valuestack'] = array();
+		$this->xh[$parser]['isf_reason'] = 0;
+
+		xml_set_object($parser, $this);
+		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
+		//-------------------------------------  
+		
+		$lines = explode("\r\n", $data);
+		while (($line = array_shift($lines)))
+		{
+			if (strlen($line) < 1)
+			{
+				break;
+			}
+			$this->xh[$parser]['headers'][] = $line;
+		}
+		$data = implode("\r\n", $lines);
+		
+		
+		//-------------------------------------
+		//  PARSE XML DATA
+		//-------------------------------------  	
+
+		if (!xml_parse($parser, $data, sizeof($data)))
+		{
+			$errstr = sprintf('XML error: %s at line %d',
+					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);
+			return $r;
+		}
+		xml_parser_free($parser);
+		
+		// ---------------------------------------
+		//  Got Ourselves Some Badness, It Seems
+		// ---------------------------------------
+		
+		if ($this->xh[$parser]['isf'] > 1)
+		{
+			if ($this->debug === TRUE)
+			{
+				echo "---Invalid Return---\n";
+				echo $this->xh[$parser]['isf_reason'];
+				echo "---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;
+		}
+		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;
+		}
+		
+		//-------------------------------------
+		//  DISPLAY XML CONTENT for DEBUGGING
+		//-------------------------------------  	
+		
+		if ($this->debug === TRUE)
+		{
+			echo "<pre>";
+			
+			if (count($this->xh[$parser]['headers'] > 0))
+			{
+				echo "---HEADERS---\n";
+				foreach ($this->xh[$parser]['headers'] as $header)
+				{
+					echo "$header\n";
+				}
+				echo "---END HEADERS---\n\n";
+			}
+			
+			echo "---DATA---\n" . htmlspecialchars($data) . "\n---END DATA---\n\n";
+			
+			echo "---PARSED---\n" ;
+			var_dump($this->xh[$parser]['value']);
+			echo "\n---END PARSED---</pre>";
+		}
+		
+		//-------------------------------------
+		//  SEND RESPONSE
+		//-------------------------------------  
+		
+		$v = $this->xh[$parser]['value'];
+			
+		if ($this->xh[$parser]['isf'])
+		{
+			$errno_v = $v->me['struct']['faultCode'];
+			$errstr_v = $v->me['struct']['faultString'];
+			$errno = $errno_v->scalarval();
+
+			if ($errno == 0)
+			{
+				// FAULT returned, errno needs to reflect that
+				$errno = -1;
+			}
+
+			$r = new XML_RPC_Response($v, $errno, $errstr_v->scalarval());
+		}
+		else
+		{
+			$r = new XML_RPC_Response($v);
+		}
+
+		$r->headers = $this->xh[$parser]['headers'];
+		return $r;
+	}
+	
+	// ------------------------------------
+	//  Begin Return Message Parsing section
+	// ------------------------------------
+	
+	// quick explanation of components:
+	//   ac - used to accumulate values
+	//   isf - used to indicate a fault
+	//   lv - used to indicate "looking for a value": implements
+	//        the logic to allow values with no types to be strings
+	//   params - used to store parameters in method calls
+	//   method - used to store method name
+	//	 stack - array with parent tree of the xml element,
+	//			 used to validate the nesting of elements
+
+	//-------------------------------------
+	//  Start Element Handler
+	//------------------------------------- 
+
+	function open_tag($the_parser, $name, $attrs)
+	{
+		// 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 ($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
+			if (!in_array($this->xh[$the_parser]['stack'][0], $this->valid_parents[$name]))
+			{
+				$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)
+		{
+			case 'STRUCT':
+			case 'ARRAY':
+				// Creates array for child elements
+				
+				$cur_val = array('value' => array(),
+								 'type'	 => $name);
+								 
+				array_unshift($this->xh[$the_parser]['valuestack'], $cur_val);
+			break;
+			case 'METHODNAME':
+			case 'NAME':
+				$this->xh[$the_parser]['ac'] = '';
+			break;
+			case 'FAULT':
+				$this->xh[$the_parser]['isf'] = 1;
+			break;
+			case 'PARAM':
+				$this->xh[$the_parser]['value'] = null;
+			break;
+			case 'VALUE':
+				$this->xh[$the_parser]['vt'] = 'value';
+				$this->xh[$the_parser]['ac'] = '';
+				$this->xh[$the_parser]['lv'] = 1;
+			break;
+			case 'I4':
+			case 'INT':
+			case 'STRING':
+			case 'BOOLEAN':
+			case 'DOUBLE':
+			case 'DATETIME.ISO8601':
+			case 'BASE64':
+				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";
+					return;
+				}
+				
+				$this->xh[$the_parser]['ac'] = '';
+			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;
+			case 'DATA':
+			case 'METHODCALL':
+			case 'METHODRESPONSE':
+			case 'PARAMS':
+				// valid elements that add little to processing
+			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;
+		}
+		
+		// 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;
+	}
+	// END
+
+
+	//-------------------------------------
+	//  End Element Handler
+	//------------------------------------- 
+
+	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
+		// tag so we be safe there as well.
+		
+		$curr_elem = array_shift($this->xh[$the_parser]['stack']);
+	
+		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]['vt']	= strtolower($name);
+			break;
+			case 'NAME':
+				$this->xh[$the_parser]['valuestack'][0]['name'] = $this->xh[$the_parser]['ac'];
+			break;
+			case 'BOOLEAN':
+			case 'I4':
+			case 'INT':
+			case 'STRING':
+			case 'DOUBLE':
+			case 'DATETIME.ISO8601':
+			case 'BASE64':
+				$this->xh[$the_parser]['vt'] = strtolower($name);
+				
+				if ($name == 'STRING')
+				{
+					$this->xh[$the_parser]['value'] = $this->xh[$the_parser]['ac'];
+				}
+				elseif ($name=='DATETIME.ISO8601')
+				{
+					$this->xh[$the_parser]['vt']    = $this->xmlrpcDateTime;
+					$this->xh[$the_parser]['value'] = $this->xh[$the_parser]['ac'];
+				}
+				elseif ($name=='BASE64')
+				{
+					$this->xh[$the_parser]['value'] = base64_decode($this->xh[$the_parser]['ac']);
+				}
+				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;
+					}
+				}
+				elseif ($name=='DOUBLE')
+				{
+					// we have a DOUBLE
+					// we must check that only 0123456789-.<space> are characters here
+					if (!ereg("^[+-]?[eE0123456789 \\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'];
+					}
+				}
+				else
+				{
+					// we have an I4/INT
+					// we must check that only 0123456789-<space> are characters here
+					if (!ereg("^[+-]?[0123456789 \\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]['ac'] = '';
+				$this->xh[$the_parser]['lv'] = 3; // indicate we've found a value
+			break;
+			case 'VALUE':
+				// This if() detects if no scalar was inside <VALUE></VALUE>
+				if ($this->xh[$the_parser]['vt']=='value')
+				{
+					$this->xh[$the_parser]['value']	= $this->xh[$the_parser]['ac'];
+					$this->xh[$the_parser]['vt']	= $this->xmlrpcString;
+				}
+				
+				// 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')
+				{
+					// Array
+					$this->xh[$the_parser]['valuestack'][0]['values'][] = $temp;
+				}
+				else
+				{
+					// Struct
+	    			$this->xh[$the_parser]['value'] = $temp;
+				}
+			break;
+			case 'MEMBER':
+				$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;
+			case 'DATA':
+				$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;
+			case 'METHODNAME':
+				$this->xh[$the_parser]['method'] = ereg_replace("^[\n\r\t ]+", '', $this->xh[$the_parser]['ac']);
+			break;
+			case 'PARAMS':
+			case 'FAULT':
+			case 'METHODCALL':
+			case 'METHORESPONSE':
+				// We're all good kids with nuthin' to do
+			break;
+			default:
+				// End of an Invalid Element.  Taken care of during the opening tag though
+			break;
+		}
+	}
+
+	//-------------------------------------
+	//  Parses Character Data
+	//------------------------------------- 
+
+	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'] == 1)
+			{
+				$this->xh[$the_parser]['lv'] = 2; // Found a value
+			}
+				
+			if( ! @isset($this->xh[$the_parser]['ac']))
+			{
+				$this->xh[$the_parser]['ac'] = '';
+			}
+				
+			$this->xh[$the_parser]['ac'] .= $data;
+		}
+	}
+	
+	
+	function addParam($par) { $this->params[]=$par; }
+	
+	function output_parameters($array=FALSE)
+	{
+		$obj =& get_instance();	
+
+		if ($array !== FALSE && is_array($array))
+		{
+			while (list($key) = each($array))
+			{
+				if (is_array($array[$key]))
+				{
+					$array[$key] = $this->output_parameters($array[$key]);
+				}
+				else
+				{
+					$array[$key] = $obj->input->xss_clean($array[$key]);
+				}
+			}
+			
+			$parameters = $array;
+		}
+		else
+		{
+			$parameters = array();
+		
+			for ($i = 0; $i < sizeof($this->params); $i++)
+    		{
+    			$a_param = $this->decode_message($this->params[$i]);
+    			
+    			if (is_array($a_param))
+    			{
+    				$parameters[] = $this->output_parameters($a_param);
+    			}
+    			else
+    			{
+    				$parameters[] = $obj->input->xss_clean($a_param);
+    			}
+    		}	
+    	}
+    	
+    	return $parameters;
+	}
+	
+	
+	function decode_message($param)
+	{
+		$kind = $param->kindOf();
+
+		if($kind == 'scalar')
+		{
+			return $param->scalarval();
+		}
+		elseif($kind == 'array')
+		{
+			reset($param->me);
+			list($a,$b) = each($param->me);
+			
+			$arr = array();
+
+			for($i = 0; $i < sizeof($b); $i++)
+			{
+				$arr[] = $this->decode_message($param->me['array'][$i]);
+			}
+			
+			return $arr; 
+		}
+		elseif($kind == 'struct')
+		{
+			reset($param->me['struct']);
+			
+			$arr = array();
+
+			while(list($key,$value) = each($param->me['struct']))
+			{
+				$arr[$key] = $this->decode_message($value);
+			}
+			
+			return $arr;
+		}
+	}
+	
+} // End XML_RPC_Messages class
+
+
+
+/**
+ * XML-RPC Values class
+ * 
+ * @category	XML-RPC
+ * @author		Paul Burdick
+ * @link		http://www.codeigniter.com/user_guide/libraries/xmlrpc.html
+ */
+class XML_RPC_Values extends CI_XML_RPC
+{
+	var $me 	= array();
+	var $mytype	= 0;
+
+	function XML_RPC_Values($val=-1, $type='')
+	{	
+		parent::CI_XML_RPC();
+		
+		if ($val != -1 || $type != '')
+		{
+			$type = $type == '' ? 'string' : $type;
+			
+			if ($this->xmlrpcTypes[$type] == 1)
+			{
+				$this->addScalar($val,$type);
+			}
+			elseif ($this->xmlrpcTypes[$type] == 2)
+			{
+				$this->addArray($val);
+			}
+			elseif ($this->xmlrpcTypes[$type] == 3)
+			{
+				$this->addStruct($val);
+			}
+		}
+	}
+
+	function addScalar($val, $type='string')
+	{
+		$typeof = $this->xmlrpcTypes[$type];
+		
+		if ($this->mytype==1)
+		{
+			echo '<strong>XML_RPC_Values</strong>: scalar can have only one value<br />';
+			return 0;
+		}
+		
+		if ($typeof != 1)
+		{
+			echo '<strong>XML_RPC_Values</strong>: not a scalar type (${typeof})<br />';
+			return 0;
+		}
+
+		if ($type == $this->xmlrpcBoolean)
+		{
+			if (strcasecmp($val,'true')==0 || $val==1 || ($val==true && strcasecmp($val,'false')))
+			{
+				$val = 1;
+			}
+			else
+			{
+				$val=0;
+			}
+		}
+
+		if ($this->mytype == 2)
+		{
+			// adding to an array here
+			$ar = $this->me['array'];
+			$ar[] = new XML_RPC_Values($val, $type);
+			$this->me['array'] = $ar;
+		}
+		else
+		{
+			// a scalar, so set the value and remember we're scalar
+			$this->me[$type] = $val;
+			$this->mytype = $typeof;
+		}
+		return 1;
+	}
+
+	function addArray($vals)
+	{
+		if ($this->mytype != 0)
+		{
+			echo '<strong>XML_RPC_Values</strong>: already initialized as a [' . $this->kindOf() . ']<br />';
+			return 0;
+		}
+
+		$this->mytype = $this->xmlrpcTypes['array'];
+		$this->me['array'] = $vals;
+		return 1;
+	}
+
+	function addStruct($vals)
+	{
+		if ($this->mytype != 0)
+		{
+			echo '<strong>XML_RPC_Values</strong>: already initialized as a [' . $this->kindOf() . ']<br />';
+			return 0;
+		}
+		$this->mytype = $this->xmlrpcTypes['struct'];
+		$this->me['struct'] = $vals;
+		return 1;
+	}
+
+	function kindOf()
+	{
+		switch($this->mytype)
+		{
+			case 3:
+				return 'struct';
+				break;
+			case 2:
+				return 'array';
+				break;
+			case 1:
+				return 'scalar';
+				break;
+			default:
+				return 'undef';
+		}
+	}
+
+	function serializedata($typ, $val)
+	{
+		$rs = '';
+		
+		switch($this->xmlrpcTypes[$typ])
+		{
+			case 3:
+				// struct
+				$rs .= "<struct>\n";
+				reset($val);
+				while(list($key2, $val2) = each($val))
+				{
+					$rs .= "<member>\n<name>{$key2}</name>\n";
+					$rs .= $this->serializeval($val2);
+					$rs .= "</member>\n";
+				}
+				$rs .= '</struct>';
+			break;
+			case 2:
+				// array
+				$rs .= "<array>\n<data>\n";
+				for($i=0; $i < sizeof($val); $i++)
+				{
+					$rs .= $this->serializeval($val[$i]);
+				}
+				$rs.="</data>\n</array>\n";
+				break;
+			case 1:
+				// others
+				switch ($typ)
+				{
+					case $this->xmlrpcBase64:
+						$rs .= "<{$typ}>" . base64_encode($val) . "</{$typ}>\n";
+					break;
+					case $this->xmlrpcBoolean:
+						$rs .= "<{$typ}>" . ($val ? '1' : '0') . "</{$typ}>\n";
+					break;
+					case $this->xmlrpcString:
+						$rs .= "<{$typ}>" . htmlspecialchars($val). "</{$typ}>\n";
+					break;
+					default:
+						$rs .= "<{$typ}>{$val}</{$typ}>\n";
+					break;
+				}
+			default:
+			break;
+		}
+		return $rs;
+	}
+
+	function serialize_class()
+	{
+		return $this->serializeval($this);
+	}
+
+	function serializeval($o)
+	{
+		
+		$ar = $o->me;
+		reset($ar);
+		
+		list($typ, $val) = each($ar);
+		$rs = "<value>\n".$this->serializedata($typ, $val)."</value>\n";
+		return $rs;
+	}
+	
+	function scalarval()
+	{
+		reset($this->me);
+		list($a,$b) = each($this->me);
+		return $b;
+	}
+
+
+	//-------------------------------------
+	// Encode time in ISO-8601 form.
+	//------------------------------------- 
+	
+	// Useful for sending time in XML-RPC
+
+	function iso8601_encode($time, $utc=0)
+	{	
+		if ($utc == 1)
+		{
+			$t = strftime("%Y%m%dT%H:%M:%S", $time);
+		}
+		else
+		{
+			if (function_exists('gmstrftime'))
+				$t = gmstrftime("%Y%m%dT%H:%M:%S", $time);
+			else
+				$t = strftime("%Y%m%dT%H:%M:%S", $time - date('Z'));
+		}
+		return $t;
+	}
+	
+}
+// END XML_RPC_Values Class
+?>
\ No newline at end of file
diff --git a/system/libraries/Xmlrpcs.php b/system/libraries/Xmlrpcs.php
new file mode 100644
index 0000000..eaec87a
--- /dev/null
+++ b/system/libraries/Xmlrpcs.php
@@ -0,0 +1,492 @@
+<?php  if (!defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * Code Igniter
+ *
+ * An open source application development framework for PHP 4.3.2 or newer
+ *
+ * @package		CodeIgniter
+ * @author		Rick Ellis
+ * @copyright	Copyright (c) 2006, pMachine, Inc.
+ * @license		http://www.codeignitor.com/user_guide/license.html 
+ * @link		http://www.codeigniter.com
+ * @since		Version 1.0
+ * @filesource
+ */
+ 
+// ------------------------------------------------------------------------
+
+/**
+ * XML-RPC server class
+ * 
+ * @package		CodeIgniter
+ * @subpackage	Libraries
+ * @category	XML-RPC
+ * @author		Paul Burdick
+ * @link		http://www.codeigniter.com/user_guide/libraries/xmlrpc.html
+ */
+class CI_XML_RPC_Server extends CI_XML_RPC
+{
+	var $methods		= array(); 	//array of methods mapped to function names and signatures
+	var $debug_msg		= '';		// Debug Message
+	var $system_methods = array(); // XML RPC Server methods
+	var $controller_obj;
+
+
+	//-------------------------------------
+	//  Constructor, more or less
+	//-------------------------------------  
+
+	function CI_XML_RPC_Server($config=array())
+	{	
+		parent::CI_XML_RPC();
+		$this->set_system_methods();
+	
+		if (isset($config['functions']) && is_array($config['functions']))
+		{
+			$this->methods = $config['functions'];
+		}
+		
+		log_message('debug', "XML-RPC Server Class Initialized");
+	}
+	
+	//-------------------------------------
+	//  Initialize Prefs and Serve
+	//-------------------------------------  
+	
+	function initialize($config=array())
+	{	
+		if (isset($config['functions']) && is_array($config['functions']))
+		{
+			$this->methods = $config['functions'];
+		}
+		
+		if (isset($config['debug']))
+		{
+			$this->debug = $config['debug'];
+		}
+	}
+	
+	//-------------------------------------
+	//  Setting of System Methods
+	//------------------------------------- 
+	
+	function set_system_methods ()
+	{
+		$system_methods = array(
+		'system.listMethods' => array(
+			'function' => 'this.listMethods',
+			'signature' => array(array($this->xmlrpcArray, $this->xmlrpcString), array($this->xmlrpcArray)),
+			'docstring' => 'Returns an array of available methods on this server'),
+		'system.methodHelp' => array(
+			'function' => 'this.methodHelp',
+			'signature' => array(array($this->xmlrpcString, $this->xmlrpcString)),
+			'docstring' => 'Returns a documentation string for the specified method'),
+		'system.methodSignature' => array(
+			'function' => 'this.methodSignature',
+			'signature' => array(array($this->xmlrpcArray, $this->xmlrpcString)),
+			'docstring' => 'Returns an array describing the return type and required parameters of a method'),
+		'system.multicall' => array(
+			'function' => 'this.multicall',
+			'signature' => array(array($this->xmlrpcArray, $this->xmlrpcArray)),
+			'docstring' => 'Combine multiple RPC calls in one request. See http://www.xmlrpc.com/discuss/msgReader$1208 for details')
+		);
+	}
+
+
+	//-------------------------------------
+	//  Main Server Function
+	//------------------------------------- 
+	
+	function serve()
+	{
+		$r = $this->parseRequest();
+		$payload  = '<?xml version="1.0" encoding="'.$this->xmlrpc_defencoding.'"?'.'>'."\n";
+		$payload .= $this->debug_msg;
+		$payload .= $r->prepare_response();
+		
+		header("Content-Type: text/xml");
+		header("Content-Length: ".strlen($payload));
+		echo $payload;
+	}
+
+	//-------------------------------------
+	//  Add Method to Class
+	//-------------------------------------  
+	
+	function add_to_map($methodname,$function,$sig,$doc)
+	{
+		$this->methods[$methodname] = array(
+			'function'  => $function,
+			'signature' => $sig,
+			'docstring' => $doc
+		);
+	}
+
+
+	//-------------------------------------
+	//  Parse Server Request
+	//------------------------------------- 
+	
+	function parseRequest($data='')
+	{
+		global $HTTP_RAW_POST_DATA;
+		
+		//-------------------------------------
+		//  Get Data
+		//-------------------------------------  
+
+		if ($data == '')
+		{
+			$data = $HTTP_RAW_POST_DATA;
+		}
+
+
+		//-------------------------------------
+		//  Set up XML Parser
+		//------------------------------------- 
+		
+		$parser = xml_parser_create($this->xmlrpc_defencoding);
+		$parser_object = new XML_RPC_Message("filler");
+		
+		$parser_object->xh[$parser]					= array();
+		$parser_object->xh[$parser]['isf']			= 0;
+		$parser_object->xh[$parser]['isf_reason']	= '';
+		$parser_object->xh[$parser]['params']		= array();
+		$parser_object->xh[$parser]['stack']		= array();
+		$parser_object->xh[$parser]['valuestack']	= array();
+		$parser_object->xh[$parser]['method']		= '';
+
+		xml_set_object($parser, $parser_object);
+		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');
+		
+		
+		//-------------------------------------
+		//  PARSE + PROCESS XML DATA
+		//-------------------------------------  	
+		
+		if ( ! xml_parse($parser, $data, 1))
+		{
+			// return XML error as a faultCode
+			$r = new XML_RPC_Response(0,
+			$this->xmlrpcerrxml + xml_get_error_code($parser),
+			sprintf('XML error: %s at line %d',
+				xml_error_string(xml_get_error_code($parser)),
+				xml_get_current_line_number($parser)));
+			xml_parser_free($parser);
+		}
+		elseif($parser_object->xh[$parser]['isf'])
+		{
+			return new XML_RPC_Response(0,
+										$this->xmlrpcerr['invalid_return'],
+										$this->xmlrpcstr['invalid_retrun']);
+		}
+		else
+		{
+			xml_parser_free($parser);
+			
+			$m = new XML_RPC_Message($parser_object->xh[$parser]['method']);
+			$plist='';
+			
+			for($i=0; $i < sizeof($parser_object->xh[$parser]['params']); $i++)
+			{
+				$plist .= "$i - " .  print_r(get_object_vars($parser_object->xh[$parser]['params'][$i]), TRUE). ";\n";
+				
+				$m->addParam($parser_object->xh[$parser]['params'][$i]);
+			}
+			
+			if ($this->debug === TRUE)
+			{
+				echo "<pre>";
+				echo "---PLIST---\n" . $plist . "\n---PLIST END---\n\n";
+				echo "</pre>";
+			}
+			
+			$r = $this->execute($m);
+		}
+		
+		//-------------------------------------
+		//  SET DEBUGGING MESSAGE
+		//-------------------------------------  	
+		
+		if ($this->debug === TRUE) 
+		{
+			$this->debug_msg = "<!-- DEBUG INFO:\n\n".$plist."\n END DEBUG-->\n";
+		}
+		
+		return $r;
+	}
+
+	//-------------------------------------
+	//  Executes the Method
+	//------------------------------------- 
+	
+	function execute($m)
+	{
+		$methName = $m->method_name;
+		
+		// Check to see if it is a system call
+		// If so, load the system_methods
+		$sysCall = ereg("^system\.", $methName);
+		$methods = $sysCall ? $this->system_methods : $this->methods;
+		
+		//-------------------------------------
+		//  Check for Function
+		//------------------------------------- 
+		
+		if (!isset($methods[$methName]['function']))
+		{
+			return new XML_RPC_Response(0,
+				$this->xmlrpcerr['unknown_method'],
+				$this->xmlrpcstr['unknown_method']);
+		}
+		else
+		{
+			// See if we are calling function in an object
+			
+			$method_parts = explode(".",$methods[$methName]['function']);
+			$objectCall = (isset($method_parts['1']) && $method_parts['1'] != "") ? true : false;
+			
+			if ($objectCall && !is_callable(array($method_parts['0'],$method_parts['1'])))
+			{
+				return new XML_RPC_Response(0,
+				$this->xmlrpcerr['unknown_method'],
+				$this->xmlrpcstr['unknown_method']);
+			}
+			elseif (!$objectCall && !is_callable($methods[$methName]['function']))
+			{
+				return new XML_RPC_Response(0,
+					$this->xmlrpcerr['unknown_method'],
+					$this->xmlrpcstr['unknown_method']);
+			}		
+		}
+
+		//-------------------------------------
+		//  Checking Methods Signature
+		//------------------------------------- 
+		
+		if (isset($methods[$methName]['signature']))
+		{
+			$sig = $methods[$methName]['signature'];
+			for($i=0; $i<sizeof($sig); $i++)
+			{
+				$current_sig = $sig[$i];
+		
+				if (sizeof($current_sig) == sizeof($m->params)+1)
+				{
+					for($n=0; $n < sizeof($m->params); $n++)
+					{
+						$p = $m->params[$n];
+						$pt = ($p->kindOf() == 'scalar') ? $p->scalartyp() : $p->kindOf();
+						
+						if ($pt != $current_sig[$n+1])
+						{
+							$pno = $n+1;
+							$wanted = $current_sig[$n+1];
+							
+							return new XML_RPC_Response(0,
+								$this->xmlrpcerr['incorrect_params'],
+								$this->xmlrpcstr['incorrect_params'] . 
+								": Wanted {$wanted}, got {$pt} at param {$pno})");
+						}
+					}
+				}
+			}
+		}
+
+		//-------------------------------------
+		//  Calls the Function
+		//------------------------------------- 
+
+		if ($objectCall)
+		{
+			if ($method_parts['1'] == "this")
+			{
+				return call_user_func(array($this, $method_parts['0']), $m);
+			}
+			else
+			{
+				$obj =& get_instance();
+				return $obj->$method_parts['1']($m);
+				//$class = new $method_parts['0'];
+				//return $class->$method_parts['1']($m);
+				//return call_user_func(array(&$method_parts['0'],$method_parts['1']), $m);
+			}
+		}
+		else
+		{
+			return call_user_func($methods[$methName]['function'], $m);
+		}
+	}
+	
+	
+	//-------------------------------------
+	//  Server Function:  List Methods
+	//------------------------------------- 
+	
+	function listMethods($m)
+	{
+		$v = new XML_RPC_Values();
+		$output = array();
+		foreach($this->$methods as $key => $value)
+		{
+			$output[] = new XML_RPC_Values($key, 'string');
+		}
+		
+		foreach($this->system_methods as $key => $value)
+		{
+			$output[]= new XML_RPC_Values($key, 'string');
+		}
+
+		$v->addArray($output);
+		return new XML_RPC_Response($v);
+	}
+	
+	//-------------------------------------
+	//  Server Function:  Return Signature for Method
+	//------------------------------------- 
+		
+	function methodSignature($m)
+	{
+		$methName = $m->getParam(0);
+		$method_name = $methName->scalarval();
+		
+		$methods = ereg("^system\.", $method_name) ? $this->system_methods : $this->methods;
+		
+		if (isset($methods[$method_name]))
+		{
+			if ($methods[$method_name]['signature'])
+			{
+				$sigs = array();
+				$signature = $methods[$method_name]['signature'];
+				
+				for($i=0; $i < sizeof($signature); $i++)
+				{
+					$cursig = array();
+					$inSig = $signature[$i];
+					for($j=0; $j<sizeof($inSig); $j++)
+					{
+						$cursig[]= new XML_RPC_Values($inSig[$j], 'string');
+					}
+					$sigs[]= new XML_RPC_Values($cursig, 'array');
+				}
+				$r = new XML_RPC_Response(new XML_RPC_Values($sigs, 'array'));
+			}
+			else
+			{
+				$r = 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;
+	}
+	
+	//-------------------------------------
+	//  Server Function:  Doc String for Method
+	//------------------------------------- 
+	
+	function methodHelp($m)
+	{
+		$methName = $m->getParam(0);
+		$method_name = $methName->scalarval();
+		
+		$methods = ereg("^system\.", $method_name) ? $this->system_methods : $this->methods;
+	
+		if (isset($methods[$methName]))
+		{
+			$docstring = isset($methods[$method_name]['docstring']) ? $methods[$method_name]['docstring'] : '';
+			$r = new XML_RPC_Response(new XML_RPC_Values($docstring, 'string'));
+		}
+		else
+		{
+			$r = new XML_RPC_Response(0, $this->xmlrpcerr['introspect_unknown'], $this->xmlrpcstr['introspect_unknown']);
+		}
+		return $r;
+	}
+
+	//-------------------------------------
+	//  Server Function:  Multi-call
+	//------------------------------------- 
+
+	function multicall($m)
+	{
+		$calls = $m->getParam(0);
+		list($a,$b)=each($calls->me);
+		$result = array();
+
+		for ($i = 0; $i < sizeof($b); $i++)
+		{
+			$call = $calls->me['array'][$i];
+			$result[$i] = $this->do_multicall($call);
+		}
+
+		return new XML_RPC_Response(new XML_RPC_Values($result, 'array'));
+	}
+	
+	
+	//-------------------------------------
+	//  Multi-call Function:  Error Handling
+	//------------------------------------- 
+
+	function multicall_error($err)
+	{
+		$str  = is_string($err) ? $this->xmlrpcstr["multicall_${err}"] : $err->faultString();
+		$code = is_string($err) ? $this->xmlrpcerr["multicall_${err}"] : $err->faultCode();
+		
+		$struct['faultCode'] = new XML_RPC_Values($code, 'int');
+		$struct['faultString'] = new XML_RPC_Values($str, 'string');
+	
+		return new XML_RPC_Values($struct, 'struct');
+	}
+	
+	
+	//-------------------------------------
+	//  Multi-call Function:  Processes method
+	//------------------------------------- 
+	
+	function do_multicall($call)
+	{
+		if ($call->kindOf() != 'struct')
+			return $this->multicall_error('notstruct');
+		elseif (!$methName = $call->me['struct']['methodName'])
+			return $this->multicall_error('nomethod');
+		
+		list($scalar_type,$scalar_value)=each($methName->me);
+		$scalar_type = $scalar_type == $this->xmlrpcI4 ? $this->xmlrpcInt : $scalar_type;
+			
+		if ($methName->kindOf() != 'scalar' || $scalar_type != 'string') 
+			return $this->multicall_error('notstring');
+		elseif ($scalar_value == 'system.multicall')
+			return $this->multicall_error('recursion');
+		elseif (!$params = $call->me['struct']['params'])
+			return $this->multicall_error('noparams');
+		elseif ($params->kindOf() != 'array')
+			return $this->multicall_error('notarray');
+			
+		list($a,$b)=each($params->me);
+		$numParams = sizeof($b);
+
+		$msg = new XML_RPC_Message($scalar_value);
+		for ($i = 0; $i < $numParams; $i++)
+		{
+			$msg->params[] = $params->me['array'][$i];
+		}
+
+		$result = $this->execute($msg);
+
+		if ($result->faultCode() != 0)
+		{
+			return $this->multicall_error($result);
+		}
+
+		return new XML_RPC_Values(array($result->value()), 'array');
+	}	
+	
+}
+// END XML_RPC_Server class
+?>
\ No newline at end of file
diff --git a/system/libraries/index.html b/system/libraries/index.html
new file mode 100644
index 0000000..5a1f5d6
--- /dev/null
+++ b/system/libraries/index.html
@@ -0,0 +1,15 @@
+<html>

+

+<head>

+

+<title>403 Forbidden</title>

+

+</head>

+

+<body bgcolor='#ffffff'>

+

+<p>Directory access is forbidden.<p>

+

+</body>

+

+</html>
\ No newline at end of file