From 9b6663f87a7e679ffba691cf516191fc840cf978 Mon Sep 17 00:00:00 2001
From: Bharat Mediratta    '.$text.'\s]*)["\']?[^>]*)?>#is', '$1', $str);
 	}
 
-	/**
-	 * Remove PHP tags from a string.
-	 *
-	 * @param   string  string to sanitize
-	 * @return  string
-	 */
-	public static function encode_php_tags($str)
-	{
-		return str_replace(array('', '?>'), array('<?', '?>'), $str);
-	}
-
 } // End security
\ No newline at end of file
diff --git a/system/helpers/text.php b/system/helpers/text.php
index 66bcd243..ed7f9cbf 100644
--- a/system/helpers/text.php
+++ b/system/helpers/text.php
@@ -2,7 +2,7 @@
 /**
  * Text helper class.
  *
- * $Id: text.php 4679 2009-11-10 01:45:52Z isaiah $
+ * $Id: text.php 4689 2009-12-02 01:39:24Z isaiah $
  *
  * @package    Core
  * @author     Kohana Team
@@ -298,27 +298,37 @@ class text_Core {
 	 */
 	public static function auto_link_urls($text)
 	{
-		// Finds all http/https/ftp/ftps links that are not part of an existing html anchor
-		if (preg_match_all('~\b(?)(?:ht|f)tps?://\S+(?:/|\b)~i', $text, $matches))
-		{
-			foreach ($matches[0] as $match)
-			{
-				// Replace each link with an anchor
-				$text = str_replace($match, html::anchor($match), $text);
-			}
-		}
 
-		// Find all naked www.links.com (without http://)
-		if (preg_match_all('~\b(? $name));
+				throw new Cache_Exception('The :group: group is not defined in your configuration.', array(':group:' => $name));
 		}
 
 		if (is_array($config))
@@ -74,7 +74,7 @@ class Cache_Core {
 
 		// Load the driver
 		if ( ! Kohana::auto_load($driver))
-			throw new Kohana_Exception('The :driver: driver for the :class: library could not be found',
+			throw new Cache_Exception('The :driver: driver for the :class: library could not be found',
 									   array(':driver:' => $this->config['driver'], ':class:' => get_class($this)));
 
 		// Initialize the driver
@@ -82,7 +82,7 @@ class Cache_Core {
 
 		// Validate the driver
 		if ( ! ($this->driver instanceof Cache_Driver))
-			throw new Kohana_Exception('The :driver: driver for the :library: library must implement the :interface: interface',
+			throw new Cache_Exception('The :driver: driver for the :library: library must implement the :interface: interface',
 									   array(':driver:' => $this->config['driver'], ':library:' => get_class($this), ':interface:' => 'Cache_Driver'));
 
 		Kohana_Log::add('debug', 'Cache Library initialized');
@@ -103,6 +103,16 @@ class Cache_Core {
 			$key = array($key => $value);
 		}
 
+		if ($this->config['prefix'] !== NULL)
+		{
+			$key = $this->add_prefix($key);
+			
+			if ($tags !== NULL)
+			{
+				$tags = $this->add_prefix($tags, FALSE);
+			}
+		}
+
 		return $this->driver->set($key, $tags, $lifetime);
 	}
 
@@ -119,6 +129,17 @@ class Cache_Core {
 			$single = TRUE;
 		}
 
+		if ($this->config['prefix'] !== NULL)
+		{
+			$keys = $this->add_prefix($keys, FALSE);
+			
+			if ( ! $single)
+			{
+			    return $this->strip_prefix($this->driver->get($keys, $single));
+			}
+
+		}
+		
 		return $this->driver->get($keys, $single);
 	}
 
@@ -132,7 +153,15 @@ class Cache_Core {
 			$tags = array($tags);
 		}
 
-		return $this->driver->get_tag($tags);
+		if ($this->config['prefix'] !== NULL)
+		{
+		    $tags = $this->add_prefix($tags, FALSE);
+		    return $this->strip_prefix($this->driver->get_tag($tags));
+		}
+		else
+		{
+		    return $this->driver->get_tag($tags);
+		}
 	}
 
 	/**
@@ -145,6 +174,11 @@ class Cache_Core {
 			$keys = array($keys);
 		}
 
+		if ($this->config['prefix'] !== NULL)
+		{
+			$keys = $this->add_prefix($keys, FALSE);
+		}
+
 		return $this->driver->delete($keys);
 	}
 
@@ -158,6 +192,11 @@ class Cache_Core {
 			$tags = array($tags);
 		}
 
+		if ($this->config['prefix'] !== NULL)
+		{
+			$tags = $this->add_prefix($tags, FALSE);
+		}
+
 		return $this->driver->delete_tag($tags);
 	}
 
@@ -168,4 +207,44 @@ class Cache_Core {
 	{
 		return $this->driver->delete_all();
 	}
+
+	/**
+	 * Add a prefix to keys or tags
+	 */
+	protected function add_prefix($array, $to_key = TRUE)
+	{
+		$out = array();
+
+		foreach($array as $key => $value)
+		{
+			if ($to_key)
+			{
+				$out[$this->config['prefix'].$key] = $value;
+			}
+			else
+			{
+				$out[$key] = $this->config['prefix'].$value;
+			}
+		}
+
+		return $out;
+	}
+
+	/**
+	 * Strip a prefix to keys or tags
+	 */
+	protected function strip_prefix($array)
+	{
+		$out = array();
+
+		$start = strlen($this->config['prefix']);
+
+		foreach($array as $key => $value)
+		{
+			$out[substr($key, $start)] = $value;
+		}
+
+		return $out;
+	}
+
 } // End Cache Library
\ No newline at end of file
diff --git a/system/libraries/Controller.php b/system/libraries/Controller.php
index da84bfc1..830c06e5 100644
--- a/system/libraries/Controller.php
+++ b/system/libraries/Controller.php
@@ -3,7 +3,7 @@
  * Kohana Controller class. The controller class must be extended to work
  * properly, so this class is defined as abstract.
  *
- * $Id: Controller.php 4679 2009-11-10 01:45:52Z isaiah $
+ * $Id: Controller.php 4721 2009-12-17 23:02:07Z isaiah $
  *
  * @package    Core
  * @author     Kohana Team
@@ -27,12 +27,6 @@ abstract class Controller_Core {
 			// Set the instance to the first controller loaded
 			Kohana::$instance = $this;
 		}
-
-		// URI should always be available
-		$this->uri = URI::instance();
-
-		// Input should always be available
-		$this->input = Input::instance();
 	}
 
 	/**
diff --git a/system/libraries/Database.php b/system/libraries/Database.php
index d3716c59..38a38fbf 100644
--- a/system/libraries/Database.php
+++ b/system/libraries/Database.php
@@ -1,9 +1,9 @@
 cache instanceof Cache)
+		if ($this->cache instanceof Cache AND ($type == NULL OR $type == Database::CROSS_REQUEST))
 		{
 			// Using cross-request Cache library
 			if ($sql === TRUE)
@@ -370,7 +373,7 @@ abstract class Database_Core {
 				$this->cache->delete_all();
 			}
 		}
-		elseif (is_array($this->cache))
+		elseif (is_array($this->cache) AND ($type == NULL OR $type == Database::PER_REQUEST))
 		{
 			// Using per-request memory cache
 			if ($sql === TRUE)
diff --git a/system/libraries/Database_Builder.php b/system/libraries/Database_Builder.php
index 5a5a058c..4e6951e7 100644
--- a/system/libraries/Database_Builder.php
+++ b/system/libraries/Database_Builder.php
@@ -29,6 +29,7 @@ class Database_Builder_Core {
 	protected $columns  = array();
 	protected $values   = array();
 	protected $type;
+	protected $distinct = FALSE;
 
 	// TTL for caching (using Cache library)
 	protected $ttl      = FALSE;
@@ -77,7 +78,8 @@ class Database_Builder_Core {
 		if ($this->type === Database::SELECT)
 		{
 			// SELECT columns FROM table
-			$sql = 'SELECT '.$this->compile_select();
+			$sql = $this->distinct ? 'SELECT DISTINCT ' : 'SELECT ';
+			$sql .= $this->compile_select();
 
 			if ( ! empty($this->from))
 			{
@@ -146,7 +148,13 @@ class Database_Builder_Core {
 
 		foreach ($this->select as $alias => $name)
 		{
-			if (is_string($alias))
+			if ($name instanceof Database_Builder)
+			{
+				// Using a subquery
+				$name->db = $this->db;
+				$vals[] = '('.(string) $name.') AS '.$this->db->quote_column($alias);
+			}
+			elseif (is_string($alias))
 			{
 				$vals[] = $this->db->quote_column($name, $alias);
 			}
@@ -374,28 +382,48 @@ class Database_Builder_Core {
 	/**
 	 * Add conditions to the HAVING clause (AND)
 	 *
-	 * @param  mixed   Column name or array of columns => vals
+	 * @param  mixed   Column name or array of triplets
 	 * @param  string  Operation to perform
 	 * @param  mixed   Value
 	 * @return Database_Builder
 	 */
 	public function and_having($columns, $op = '=', $value = NULL)
 	{
-		$this->having[] = array('AND' => array($columns, $op, $value));
+		if (is_array($columns))
+		{
+			foreach ($columns as $column)
+			{
+				$this->having[] = array('AND' => $column);
+			}
+		}
+		else
+		{
+			$this->having[] = array('AND' => array($columns, $op, $value));
+		}
 		return $this;
 	}
 
 	/**
 	 * Add conditions to the HAVING clause (OR)
 	 *
-	 * @param  mixed   Column name or array of columns => vals
+	 * @param  mixed   Column name or array of triplets
 	 * @param  string  Operation to perform
 	 * @param  mixed   Value
 	 * @return Database_Builder
 	 */
 	public function or_having($columns, $op = '=', $value = NULL)
 	{
-		$this->having[] = array('OR' => array($columns, $op, $value));
+		if (is_array($columns))
+		{
+			foreach ($columns as $column)
+			{
+				$this->having[] = array('OR' => $column);
+			}
+		}
+		else
+		{
+			$this->having[] = array('OR' => array($columns, $op, $value));
+		}
 		return $this;
 	}
 
@@ -408,13 +436,25 @@ class Database_Builder_Core {
 	 */
 	public function order_by($columns, $direction = NULL)
 	{
-		if (is_string($columns))
+		if (is_array($columns))
 		{
-			$columns = array($columns => $direction);
+			foreach ($columns as $column => $direction)
+			{
+				if (is_string($column))
+				{
+					$this->order_by[] = array($column => $direction);
+				}
+				else
+				{
+					// $direction is the column name when the array key is numeric
+					$this->order_by[] = array($direction => NULL);
+				}
+			}
+		}
+		else
+		{
+			$this->order_by[] = array($columns => $direction);
 		}
-
-		$this->order_by[] = $columns;
-
 		return $this;
 	}
 
@@ -542,28 +582,48 @@ class Database_Builder_Core {
 	/**
 	 * Add conditions to the WHERE clause (AND)
 	 *
-	 * @param  mixed   Column name or array of columns => vals
+	 * @param  mixed   Column name or array of triplets
 	 * @param  string  Operation to perform
 	 * @param  mixed   Value
 	 * @return Database_Builder
 	 */
 	public function and_where($columns, $op = '=', $value = NULL)
 	{
-		$this->where[] = array('AND' => array($columns, $op, $value));
+		if (is_array($columns))
+		{
+			foreach ($columns as $column)
+			{
+				$this->where[] = array('AND' => $column);
+			}
+		}
+		else
+		{
+			$this->where[] = array('AND' => array($columns, $op, $value));
+		}
 		return $this;
 	}
 
 	/**
 	 * Add conditions to the WHERE clause (OR)
 	 *
-	 * @param  mixed   Column name or array of columns => vals
+	 * @param  mixed   Column name or array of triplets
 	 * @param  string  Operation to perform
 	 * @param  mixed   Value
 	 * @return Database_Builder
 	 */
 	public function or_where($columns, $op = '=', $value = NULL)
 	{
-		$this->where[] = array('OR' => array($columns, $op, $value));
+		if (is_array($columns))
+		{
+			foreach ($columns as $column)
+			{
+				$this->where[] = array('OR' => $column);
+			}
+		}
+		else
+		{
+			$this->where[] = array('OR' => array($columns, $op, $value));
+		}
 		return $this;
 	}
 
@@ -779,6 +839,19 @@ class Database_Builder_Core {
 		return $this;
 	}
 
+	/**
+	 * Create a SELECT query and specify selected columns
+	 *
+	 * @param   string|array    column name or array(alias => column)
+	 * @return  Database_Builder
+	 */
+	public function select_distinct($columns = NULL)
+	{
+		$this->select($columns);
+		$this->distinct = TRUE;
+		return $this;
+	}
+
 	/**
 	 * Create an UPDATE query
 	 *
diff --git a/system/libraries/Database_Mysql.php b/system/libraries/Database_Mysql.php
index cb531194..a5775037 100644
--- a/system/libraries/Database_Mysql.php
+++ b/system/libraries/Database_Mysql.php
@@ -2,7 +2,7 @@
 /**
  * MySQL database connection.
  *
- * $Id: Database_Mysql.php 4684 2009-11-18 14:26:48Z isaiah $
+ * $Id: Database_Mysql.php 4712 2009-12-10 21:47:09Z cbandy $
  *
  * @package    Kohana
  * @author     Kohana Team
@@ -31,16 +31,15 @@ class Database_Mysql_Core extends Database {
 
 		extract($this->config['connection']);
 
-		// Set the connection type
-		$connect = ($this->config['persistent'] === TRUE) ? 'mysql_pconnect' : 'mysql_connect';
-
 		$host = isset($host) ? $host : $socket;
 		$port = isset($port) ? ':'.$port : '';
 
 		try
 		{
 			// Connect to the database
-			$this->connection = $connect($host.$port, $user, $pass, TRUE);
+			$this->connection = ($this->config['persistent'] === TRUE)
+				? mysql_pconnect($host.$port, $user, $pass, $params)
+				: mysql_connect($host.$port, $user, $pass, TRUE, $params);
 		}
 		catch (Kohana_PHP_Exception $e)
 		{
diff --git a/system/libraries/Database_Mysqli.php b/system/libraries/Database_Mysqli.php
index 523fcb19..08ed99df 100644
--- a/system/libraries/Database_Mysqli.php
+++ b/system/libraries/Database_Mysqli.php
@@ -2,7 +2,7 @@
 /**
  * MySQL database connection.
  * 
- * $Id: Database_Mysqli.php 4679 2009-11-10 01:45:52Z isaiah $
+ * $Id: Database_Mysqli.php 4712 2009-12-10 21:47:09Z cbandy $
  * 
  * @package    Kohana
  * @author     Kohana Team
@@ -29,29 +29,29 @@ class Database_Mysqli_Core extends Database_Mysql {
 
 		$host = isset($host) ? $host : $socket;
 
-		if($this->connection = new mysqli($host, $user, $pass, $database, $port)) {
+		$mysqli = mysqli_init();
 			
-			if (isset($this->config['character_set']))
-			{
-				// Set the character set
-				$this->set_charset($this->config['character_set']);
-			}
+		if ( ! $mysqli->real_connect($host, $user, $pass, $database, $port, $socket, $params))
+			throw new Database_Exception('#:errno: :error',
+				array(':error' => $mysqli->connect_error, ':errno' => $mysqli->connect_errno));
 			
-			// Clear password after successful connect
-			$this->db_config['connection']['pass'] = NULL;
+		$this->connection = $mysqli;
 			
-			return $this->connection;
+		if (isset($this->config['character_set']))
+		{
+			// Set the character set
+			$this->set_charset($this->config['character_set']);
 		}
-
-		// Unable to connect to the database
-			throw new Database_Exception('#:errno: :error',
-				array(':error' => $this->connection->connect_error,
-				':errno' => $this->connection->connect_errno));
 	}
 
 	public function disconnect()
 	{
-		return is_object($this->connection) and $this->connection->close();
+		if (is_object($this->connection))
+		{
+			$this->connection->close();
+		}
+
+		$this->connection = NULL;
 	}
 
 	public function set_charset($charset)
diff --git a/system/libraries/Input.php b/system/libraries/Input.php
index 83f0ed17..04403854 100644
--- a/system/libraries/Input.php
+++ b/system/libraries/Input.php
@@ -2,7 +2,7 @@
 /**
  * Input library.
  *
- * $Id: Input.php 4680 2009-11-10 01:57:00Z isaiah $
+ * $Id: Input.php 4720 2009-12-17 21:15:03Z isaiah $
  *
  * @package    Core
  * @author     Kohana Team
@@ -54,7 +54,7 @@ class Input_Core {
 		$_COOKIE = Input::clean($_COOKIE);
 		$_SERVER = Input::clean($_SERVER);
 
-		if (PHP_SAPI == 'cli')
+		if (Kohana::$server_api === 'cli')
 		{
 			// Convert command line arguments
 			$_SERVER['argv'] = Input::clean($_SERVER['argv']);
@@ -311,7 +311,7 @@ class Input_Core {
 		if (trim($data) === '')
 			return $data;
 
-		if ($tool === TRUE)
+		if (is_bool($tool))
 		{
 			$tool = 'default';
 		}
@@ -371,7 +371,7 @@ class Input_Core {
 		$data = html_entity_decode($data, ENT_COMPAT, 'UTF-8');
 
 		// Remove any attribute starting with "on" or xmlns
-		$data = preg_replace('#(<[^>]+?[\x00-\x20"\'])(?:on|xmlns)[^>]*+>#iu', '$1>', $data);
+		$data = preg_replace('#(?:on[a-z]+|xmlns)\s*=\s*[\'"\x00-\x20]?[^\'>"]*[\'"\x00-\x20]?\s?#iu', '', $data);
 
 		// Remove javascript: and vbscript: protocols
 		$data = preg_replace('#([a-z]*)[\x00-\x20]*=[\x00-\x20]*([`\'"]*)[\x00-\x20]*j[\x00-\x20]*a[\x00-\x20]*v[\x00-\x20]*a[\x00-\x20]*s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:#iu', '$1=$2nojavascript...', $data);
diff --git a/system/libraries/Kohana_PHP_Exception.php b/system/libraries/Kohana_PHP_Exception.php
index fca5b30b..019c686b 100644
--- a/system/libraries/Kohana_PHP_Exception.php
+++ b/system/libraries/Kohana_PHP_Exception.php
@@ -2,7 +2,7 @@
 /**
  * Kohana PHP Error Exceptions
  *
- * $Id: Kohana_PHP_Exception.php 4679 2009-11-10 01:45:52Z isaiah $
+ * $Id: Kohana_PHP_Exception.php 4687 2009-11-30 21:59:26Z isaiah $
  *
  * @package    Core
  * @author     Kohana Team
@@ -89,7 +89,7 @@ class Kohana_PHP_Exception_Core extends Kohana_Exception {
 	 */
 	public static function shutdown_handler()
 	{
-		if (Kohana_PHP_Exception::$enabled AND $error = error_get_last())
+		if (Kohana_PHP_Exception::$enabled AND $error = error_get_last() AND (error_reporting() & $error['type']))
 		{
 			// Fake an exception for nice debugging
 			Kohana_Exception::handle(new Kohana_PHP_Exception($error['type'], $error['message'], $error['file'], $error['line']));
diff --git a/system/libraries/ORM.php b/system/libraries/ORM.php
index eff22fc0..2f2feed5 100644
--- a/system/libraries/ORM.php
+++ b/system/libraries/ORM.php
@@ -8,7 +8,7 @@
  * [ref-orm]: http://wikipedia.org/wiki/Object-relational_mapping
  * [ref-act]: http://wikipedia.org/wiki/Active_record
  *
- * $Id: ORM.php 4682 2009-11-11 20:53:23Z isaiah $
+ * $Id: ORM.php 4711 2009-12-10 20:40:52Z isaiah $
  *
  * @package    ORM
  * @author     Kohana Team
@@ -102,7 +102,7 @@ class ORM_Core {
 		$this->object_name   = strtolower(substr(get_class($this), 0, -6));
 		$this->object_plural = inflector::plural($this->object_name);
 
-		if (!isset($this->sorting))
+		if ( ! isset($this->sorting))
 		{
 			// Default sorting
 			$this->sorting = array($this->primary_key => 'asc');
@@ -119,7 +119,7 @@ class ORM_Core {
 			// Load an object
 			$this->_load_values((array) $id);
 		}
-		elseif (!empty($id))
+		elseif ( ! empty($id))
 		{
 			// Set the object's primary key, but don't load it until needed
 			$this->object[$this->primary_key] = $id;
@@ -234,7 +234,7 @@ class ORM_Core {
 				switch ($num_args)
 				{
 					case 0:
-						if (in_array($method, array('open', 'close', 'cache')))
+						if (in_array($method, array('open', 'and_open', 'or_open', 'close', 'cache')))
 						{
 							// Should return ORM, not Database
 							$this->db_builder->$method();
@@ -320,12 +320,12 @@ class ORM_Core {
 				}
 
 				// Foreign key lies in this table (this model belongs_to target model)
-				$where = array($model->foreign_key(TRUE) => $this->object[$this->foreign_key($column)]);
+				$where = array($model->foreign_key(TRUE), '=', $this->object[$this->foreign_key($column)]);
 			}
 			else
 			{
 				// Foreign key lies in the target table (this model has_one target model)
-				$where = array($this->foreign_key($column, $model->table_name) => $this->primary_key_value);
+				$where = array($this->foreign_key($column, $model->table_name), '=', $this->primary_key_value);
 			}
 
 			// one<>alias:one relationship
@@ -524,16 +524,6 @@ class ORM_Core {
 		unset($this->object[$column], $this->changed[$column], $this->related[$column]);
 	}
 
-	/**
-	 * Displays the primary key of a model when it is converted to a string.
-	 *
-	 * @return  string
-	 */
-	public function __toString()
-	{
-		return (string) $this->primary_key_value;
-	}
-
 	/**
 	 * Returns the values of this object as an array.
 	 *
@@ -665,7 +655,7 @@ class ORM_Core {
 			if (is_array($id))
 			{
 				// Search for all clauses
-				$this->db_builder->where($id);
+				$this->db_builder->where(array($id));
 			}
 			else
 			{
@@ -767,6 +757,9 @@ class ORM_Core {
 			ORM_Validation_Exception::handle_validation($this->table_name, $array);
 		}
 
+		// Fields may have been modified by filters
+		$this->object = array_merge($this->object, $array->getArrayCopy());
+
 		// Return validation status
 		return $this;
 	}
@@ -782,8 +775,10 @@ class ORM_Core {
 		if ( ! empty($this->changed))
 		{
 			// Require model validation before saving
-			if (!$this->_valid)
+			if ( ! $this->_valid)
+			{
 				$this->validate();
+			}
 
 			$data = array();
 			foreach ($this->changed as $column)
@@ -881,8 +876,8 @@ class ORM_Core {
 				}
 
 				// Foreign keys for the join table
-				$object_fk  = $this->foreign_key(NULL);
-				$related_fk = $model->foreign_key(NULL);
+				$object_fk  = $this->foreign_key($join_table);
+				$related_fk = $model->foreign_key($join_table);
 
 				if ( ! empty($added))
 				{
@@ -909,6 +904,12 @@ class ORM_Core {
 			}
 		}
 
+		if ($this->saved() === TRUE)
+		{
+			// Clear the per-request database cache
+			$this->db->clear_cache(NULL, Database::PER_REQUEST);
+		}
+
 		return $this;
 	}
 
@@ -933,6 +934,9 @@ class ORM_Core {
 			->where($this->primary_key, '=', $id)
 			->execute($this->db);
 
+		// Clear the per-request database cache
+		$this->db->clear_cache(NULL, Database::PER_REQUEST);
+
 		return $this->clear();
 	}
 
@@ -965,6 +969,9 @@ class ORM_Core {
 			return $this;
 		}
 
+		// Clear the per-request database cache
+		$this->db->clear_cache(NULL, Database::PER_REQUEST);
+
 		return $this->clear();
 	}
 
@@ -1154,12 +1161,13 @@ class ORM_Core {
 	 *
 	 * @chainable
 	 * @param   string  SQL query to clear
+	 * @param   integer  Type of cache to clear, Database::CROSS_REQUEST or Database::PER_REQUEST
 	 * @return  ORM
 	 */
-	public function clear_cache($sql = NULL)
+	public function clear_cache($sql = NULL, $type = NULL)
 	{
 		// Proxy to database
-		$this->db->clear_cache($sql);
+		$this->db->clear_cache($sql, $type);
 
 		ORM::$column_cache = array();
 
@@ -1550,9 +1558,9 @@ class ORM_Core {
 	 */
 	protected function load_relations($table, ORM $model)
 	{
-		$result = db::select(array('id' => $model->foreign_key(NULL)))
+		$result = db::select(array('id' => $model->foreign_key($table)))
 			->from($table)
-			->where($this->foreign_key(NULL, $table), '=', $this->primary_key_value)
+			->where($this->foreign_key($table, $table), '=', $this->primary_key_value)
 			->execute($this->db)
 			->as_object();
 
diff --git a/system/libraries/Profiler.php b/system/libraries/Profiler.php
index b7a5ecae..940e365d 100644
--- a/system/libraries/Profiler.php
+++ b/system/libraries/Profiler.php
@@ -8,7 +8,7 @@
  * POST Data    - The name and values of any POST data submitted to the current page.
  * Cookie Data  - All cookies sent for the current request.
  *
- * $Id: Profiler.php 4679 2009-11-10 01:45:52Z isaiah $
+ * $Id: Profiler.php 4719 2009-12-17 04:31:48Z isaiah $
  *
  * @package    Profiler
  * @author     Kohana Team
@@ -101,7 +101,7 @@ class Profiler_Core {
 
 		// Don't display if there's no profiles
 		if (empty(Profiler::$profiles))
-			return $output;
+			return Kohana::$output;
 
 		$styles = '';
 		foreach (Profiler::$profiles as $profile)
diff --git a/system/libraries/Router.php b/system/libraries/Router.php
index 82dbb9b5..18e01af2 100644
--- a/system/libraries/Router.php
+++ b/system/libraries/Router.php
@@ -2,7 +2,7 @@
 /**
  * Router
  *
- * $Id: Router.php 4679 2009-11-10 01:45:52Z isaiah $
+ * $Id: Router.php 4693 2009-12-04 17:11:16Z cbandy $
  *
  * @package    Core
  * @author     Kohana Team
@@ -38,7 +38,7 @@ class Router_Core {
 		if ( ! empty($_SERVER['QUERY_STRING']))
 		{
 			// Set the query string to the current query string
-			Router::$query_string = '?'.trim(urldecode($_SERVER['QUERY_STRING']), '&/');
+			Router::$query_string = '?'.urldecode(trim($_SERVER['QUERY_STRING'], '&'));
 		}
 
 		if (Router::$routes === NULL)
@@ -173,7 +173,7 @@ class Router_Core {
 	 */
 	public static function find_uri()
 	{
-		if (PHP_SAPI === 'cli')
+		if (Kohana::$server_api === 'cli')
 		{
 			// Command line requires a bit of hacking
 			if (isset($_SERVER['argv'][1]))
@@ -181,9 +181,9 @@ class Router_Core {
 				Router::$current_uri = $_SERVER['argv'][1];
 
 				// Remove GET string from segments
-				if (($query = strpos(Router::$current_uri, '?')) !== FALSE)
+				if (strpos(Router::$current_uri, '?') !== FALSE)
 				{
-					list (Router::$current_uri, $query) = explode('?', Router::$current_uri, 2);
+					list(Router::$current_uri, $query) = explode('?', Router::$current_uri, 2);
 
 					// Parse the query string into $_GET
 					parse_str($query, $_GET);
diff --git a/system/libraries/Validation.php b/system/libraries/Validation.php
index f340e63c..47f34584 100644
--- a/system/libraries/Validation.php
+++ b/system/libraries/Validation.php
@@ -2,7 +2,7 @@
 /**
  * Validation library.
  *
- * $Id: Validation.php 4679 2009-11-10 01:45:52Z isaiah $
+ * $Id: Validation.php 4713 2009-12-10 22:25:38Z isaiah $
  *
  * @package    Validation
  * @author     Kohana Team
@@ -26,12 +26,12 @@ class Validation_Core extends ArrayObject {
 	protected $errors = array();
 	protected $messages = array();
 
+	// Field labels
+	protected $labels = array();
+
 	// Fields that are expected to be arrays
 	protected $array_fields = array();
 
-	// Checks if there is data to validate.
-	protected $submitted;
-
 	/**
 	 * Creates a new Validation instance.
 	 *
@@ -52,9 +52,6 @@ class Validation_Core extends ArrayObject {
 	 */
 	public function __construct(array $array)
 	{
-		// The array is submitted if the array is not empty
-		$this->submitted = ! empty($array);
-
 		parent::__construct($array, ArrayObject::ARRAY_AS_PROPS | ArrayObject::STD_PROP_LIST);
 	}
 
@@ -85,21 +82,6 @@ class Validation_Core extends ArrayObject {
 		return $copy;
 	}
 
-	/**
-	 * Test if the data has been submitted.
-	 *
-	 * @return  boolean
-	 */
-	public function submitted($value = NULL)
-	{
-		if (is_bool($value))
-		{
-			$this->submitted = $value;
-		}
-
-		return $this->submitted;
-	}
-
 	/**
 	 * Returns an array of all the field names that have filters, rules, or callbacks.
 	 *
@@ -196,6 +178,42 @@ class Validation_Core extends ArrayObject {
 		return $this;
 	}
 
+	/**
+	* Sets or overwrites the label name for a field.
+	*
+	* @param string field name
+	* @param string label
+	* @return $this
+	*/
+	public function label($field, $label = NULL)
+	{
+		if ($label === NULL AND ($field !== TRUE OR $field !== '*') AND ! isset($this->labels[$field]))
+		{
+			// Set the field label to the field name
+			$this->labels[$field] = ucfirst(preg_replace('/[^\pL]+/u', ' ', $field));
+		}
+		elseif ($label !== NULL)
+		{
+			// Set the label for this field
+			$this->labels[$field] = $label;
+		}
+
+		return $this;
+	}
+
+	/**
+	* Sets labels using an array.
+	*
+	* @param array list of field => label names
+	* @return $this
+	*/
+	public function labels(array $labels)
+	{
+		$this->labels = $labels + $this->labels;
+
+		return $this;
+	}
+
 	/**
 	 * Converts a filter, rule, or callback into a fully-qualified callback array.
 	 *
@@ -338,6 +356,9 @@ class Validation_Core extends ArrayObject {
 		$rules = func_get_args();
 		$rules = array_slice($rules, 1);
 
+		// Set a default field label
+		$this->label($field);
+
 		if ($field === TRUE)
 		{
 			// Use wildcard
@@ -412,6 +433,9 @@ class Validation_Core extends ArrayObject {
 		$callbacks = func_get_args();
 		$callbacks = array_slice($callbacks, 1);
 
+		// Set a default field label
+		$this->label($field);
+
 		if ($field === TRUE)
 		{
 			// Use wildcard
@@ -471,9 +495,6 @@ class Validation_Core extends ArrayObject {
 			}
 		}
 
-		if ($this->submitted === FALSE)
-			return FALSE;
-
 		foreach ($this->rules as $field => $callbacks)
 		{
 			foreach ($callbacks as $callback)
@@ -534,6 +555,7 @@ class Validation_Core extends ArrayObject {
 
 					if (($result == $is_false))
 					{
+						$rule = $is_false ? '!'.$rule : $rule;
 						$this->add_error($field, $rule, $args);
 
 						// Stop validating this field when an error is found
@@ -618,46 +640,6 @@ class Validation_Core extends ArrayObject {
 		return $this;
 	}
 
-	/**
-	 * Sets or returns the message for an input.
-	 *
-	 * @chainable
-	 * @param   string   input key
-	 * @param   string   message to set
-	 * @return  string|object
-	 */
-	public function message($input = NULL, $message = NULL)
-	{
-		if ($message === NULL)
-		{
-			if ($input === NULL)
-			{
-				$messages = array();
-				$keys     = array_keys($this->messages);
-
-				foreach ($keys as $input)
-				{
-					$messages[] = $this->message($input);
-				}
-
-				return implode("\n", $messages);
-			}
-
-			// Return nothing if no message exists
-			if (empty($this->messages[$input]))
-				return '';
-
-			// Return the HTML message string
-			return $this->messages[$input];
-		}
-		else
-		{
-			$this->messages[$input] = $message;
-		}
-
-		return $this;
-	}
-
 	/**
 	 * Return the errors array.
 	 *
@@ -677,18 +659,49 @@ class Validation_Core extends ArrayObject {
 		}
 		else
 		{
-
 			$errors = array();
 			foreach ($this->errors as $input => $error)
 			{
-				// Key for this input error
-				$key = "$file.$input.$error[0]";
+				// Locations to check for error messages
+				$error_locations = array
+				(
+					"validation/{$file}.{$input}.{$error[0]}",
+					"validation/{$file}.{$input}.default",
+					"validation/default.{$error[0]}"
+				);
+
+				if (($message = Kohana::message($error_locations[0])) !== $error_locations[0])
+				{
+					// Found a message for this field and error
+				}
+				elseif (($message = Kohana::message($error_locations[1])) !== $error_locations[1])
+				{
+					// Found a default message for this field
+				}
+				elseif (($message = Kohana::message($error_locations[2])) !== $error_locations[2])
+				{
+					// Found a default message for this error
+				}
+				else
+				{
+					// No message exists, display the path expected
+					$message = "validation/{$file}.{$input}.{$error[0]}";
+				}
 
-				if (($errors[$input] = Kohana::message('validation/'.$key, $error[1])) === $key)
+				// Start the translation values list
+				$values = array(':field' => __($this->labels[$input]));
+
+				if ( ! empty($error[1]))
 				{
-					// Get the default error message
-					$errors[$input] = Kohana::message("$file.$input.default");
+					foreach ($error[1] as $key => $value)
+					{
+						// Add each parameter as a numbered value, starting from 1
+						$values[':param'.($key + 1)] = __($value);
+					}
 				}
+
+				// Translate the message using the default language
+				$errors[$input] = __($message, $values);
 			}
 
 			return $errors;
diff --git a/system/libraries/drivers/Cache/File.php b/system/libraries/drivers/Cache/File.php
index fc20c22d..d6ec0378 100644
--- a/system/libraries/drivers/Cache/File.php
+++ b/system/libraries/drivers/Cache/File.php
@@ -183,7 +183,7 @@ class Cache_File_Driver extends Cache_Driver {
 				// Get the id from the filename
 				list($key, $junk) = explode('~', basename($path), 2);
 
-				if (($data = $this->get($key)) !== FALSE)
+				if (($data = $this->get($key, TRUE)) !== FALSE)
 				{
 					// Add the result to the array
 					$result[$key] = $data;
@@ -211,7 +211,7 @@ class Cache_File_Driver extends Cache_Driver {
 			// Remove the cache file
 			if ( ! unlink($path))
 			{
-				Kohana::log('error', 'Cache: Unable to delete cache file: '.$path);
+				Kohana_Log::add('error', 'Cache: Unable to delete cache file: '.$path);
 				$success = FALSE;
 			}
 		}
diff --git a/system/libraries/drivers/Cache/Memcache.php b/system/libraries/drivers/Cache/Memcache.php
index 636191d4..13d61d82 100644
--- a/system/libraries/drivers/Cache/Memcache.php
+++ b/system/libraries/drivers/Cache/Memcache.php
@@ -17,7 +17,7 @@ class Cache_Memcache_Driver extends Cache_Driver {
 	public function __construct($config)
 	{
 		if ( ! extension_loaded('memcache'))
-			throw new Kohana_Exception('The memcache PHP extension must be loaded to use this driver.');
+			throw new Cache_Exception('The memcache PHP extension must be loaded to use this driver.');
 
 		ini_set('memcache.allow_failover', (isset($config['allow_failover']) AND $config['allow_failover']) ? TRUE : FALSE);
 
@@ -79,7 +79,10 @@ class Cache_Memcache_Driver extends Cache_Driver {
 
 		if ($single)
 		{
-			return ($items === FALSE OR count($items) > 0) ? current($items) : NULL;
+			if ($items === FALSE)
+			    return NULL;
+
+			return (count($items) > 0) ? current($items) : NULL;
 		}
 		else
 		{
diff --git a/system/libraries/drivers/Cache/Xcache.php b/system/libraries/drivers/Cache/Xcache.php
index ad11e6d7..4c08405e 100644
--- a/system/libraries/drivers/Cache/Xcache.php
+++ b/system/libraries/drivers/Cache/Xcache.php
@@ -16,7 +16,7 @@ class Cache_Xcache_Driver extends Cache_Driver {
 	public function __construct($config)
 	{
 		if ( ! extension_loaded('xcache'))
-			throw new Kohana_Exception('The xcache PHP extension must be loaded to use this driver.');
+			throw new Cache_Exception('The xcache PHP extension must be loaded to use this driver.');
 
 		$this->config = $config;
 	}
diff --git a/system/messages/core.php b/system/messages/core.php
index 4bf6ee8c..64f897e8 100644
--- a/system/messages/core.php
+++ b/system/messages/core.php
@@ -8,7 +8,6 @@ $messages = array
 		E_PAGE_NOT_FOUND     => __('Page Not Found'),    // __('The requested page was not found. It may have moved, been deleted, or archived.'),
 		E_DATABASE_ERROR     => __('Database Error'),    // __('A database error occurred while performing the requested procedure. Please review the database error below for more information.'),
 		E_RECOVERABLE_ERROR  => __('Recoverable Error'), // __('An error was detected which prevented the loading of this page. If this problem persists, please contact the website administrator.'),
-
 		E_ERROR              => __('Fatal Error'),
 		E_COMPILE_ERROR      => __('Fatal Error'),
 		E_CORE_ERROR         => __('Fatal Error'),
@@ -29,4 +28,10 @@ $messages = array
 	'driver'             => 'driver',
 	'model'              => 'model',
 	'view'               => 'view',
-);
\ No newline at end of file
+);
+
+// E_DEPRECATED is only defined in PHP >= 5.3.0
+if (defined('E_DEPRECATED'))
+{
+	$messages['errors'][E_DEPRECATED] = __('Deprecated');
+}
\ No newline at end of file
diff --git a/system/messages/validation/default.php b/system/messages/validation/default.php
new file mode 100644
index 00000000..2c59fa06
--- /dev/null
+++ b/system/messages/validation/default.php
@@ -0,0 +1,17 @@
+ 'The :field field is required',
+	'length'        => 'The :field field must be between :param1 and :param2 characters long',
+	'depends_on'    => 'The :field field requires the :param1 field',
+	'matches'       => 'The :field field must be the same as :param1',
+	'email'         => 'The :field field must be a valid email address',
+	'decimal'       => 'The :field field must be a decimal with :param1 places',
+	'digit'         => 'The :field field must be a digit',
+	'in_array'      => 'The :field field must be one of the available options',
+	'alpha_numeric' => 'The :field field must consist only of alphabetical or numeric characters',
+	'alpha_dash '   => 'The :field field must consist only of alphabetical, numeric, underscore and dash characters',
+	'numeric '      => 'The :field field must be a valid number',
+	'url'           => 'The :field field must be a valid url',
+	'phone'         => 'The :field field must be a valid phone number',
+);
diff --git a/system/vendor/Markdown.php b/system/vendor/Markdown.php
deleted file mode 100644
index b649f6c1..00000000
--- a/system/vendor/Markdown.php
+++ /dev/null
@@ -1,2909 +0,0 @@
-
-#
-# Original Markdown
-# Copyright (c) 2004-2006 John Gruber  
-# 
 
  
 
", $text); - } - return $text; - } - - function mdwp_strip_p($t) { return preg_replace('{?p>}i', '', $t); } - - function mdwp_hide_tags($text) { - global $mdwp_hidden_tags, $mdwp_placeholders; - return str_replace($mdwp_hidden_tags, $mdwp_placeholders, $text); - } - function mdwp_show_tags($text) { - global $mdwp_hidden_tags, $mdwp_placeholders; - return str_replace($mdwp_placeholders, $mdwp_hidden_tags, $text); - } -} - - -### bBlog Plugin Info ### - -function identify_modifier_markdown() { - return array( - 'name' => 'markdown', - 'type' => 'modifier', - 'nicename' => 'PHP Markdown Extra', - 'description' => 'A text-to-HTML conversion tool for web writers', - 'authors' => 'Michel Fortin and John Gruber', - 'licence' => 'GPL', - 'version' => MARKDOWNEXTRA_VERSION, - 'help' => 'Markdown syntax allows you to write using an easy-to-read, easy-to-write plain text format. Based on the original Perl version by John Gruber. More...', - ); -} - - -### Smarty Modifier Interface ### - -function smarty_modifier_markdown($text) { - return Markdown($text); -} - - -### Textile Compatibility Mode ### - -# Rename this file to "classTextile.php" and it can replace Textile everywhere. - -if (strcasecmp(substr(__FILE__, -16), "classTextile.php") == 0) { - # Try to include PHP SmartyPants. Should be in the same directory. - @include_once 'smartypants.php'; - # Fake Textile class. It calls Markdown instead. - class Textile { - function TextileThis($text, $lite='', $encode='') { - if ($lite == '' && $encode == '') $text = Markdown($text); - if (function_exists('SmartyPants')) $text = SmartyPants($text); - return $text; - } - # Fake restricted version: restrictions are not supported for now. - function TextileRestricted($text, $lite='', $noimage='') { - return $this->TextileThis($text, $lite); - } - # Workaround to ensure compatibility with TextPattern 4.0.3. - function blockLite($text) { return $text; } - } -} - - - -# -# Markdown Parser Class -# - -class Markdown_Parser { - - # Regex to match balanced [brackets]. - # Needed to insert a maximum bracked depth while converting to PHP. - var $nested_brackets_depth = 6; - var $nested_brackets_re; - - var $nested_url_parenthesis_depth = 4; - var $nested_url_parenthesis_re; - - # Table of hash values for escaped characters: - var $escape_chars = '\`*_{}[]()>#+-.!'; - var $escape_chars_re; - - # Change to ">" for HTML output. - var $empty_element_suffix = MARKDOWN_EMPTY_ELEMENT_SUFFIX; - var $tab_width = MARKDOWN_TAB_WIDTH; - - # Change to `true` to disallow markup or entities. - var $no_markup = false; - var $no_entities = false; - - # Predefined urls and titles for reference links and images. - var $predef_urls = array(); - var $predef_titles = array(); - - - function Markdown_Parser() { - # - # Constructor function. Initialize appropriate member variables. - # - $this->_initDetab(); - $this->prepareItalicsAndBold(); - - $this->nested_brackets_re = - str_repeat('(?>[^\[\]]+|\[', $this->nested_brackets_depth). - str_repeat('\])*', $this->nested_brackets_depth); - - $this->nested_url_parenthesis_re = - str_repeat('(?>[^()\s]+|\(', $this->nested_url_parenthesis_depth). - str_repeat('(?>\)))*', $this->nested_url_parenthesis_depth); - - $this->escape_chars_re = '['.preg_quote($this->escape_chars).']'; - - # Sort document, block, and span gamut in ascendent priority order. - asort($this->document_gamut); - asort($this->block_gamut); - asort($this->span_gamut); - } - - - # Internal hashes used during transformation. - var $urls = array(); - var $titles = array(); - var $html_hashes = array(); - - # Status flag to avoid invalid nesting. - var $in_anchor = false; - - - function setup() { - # - # Called before the transformation process starts to setup parser - # states. - # - # Clear global hashes. - $this->urls = $this->predef_urls; - $this->titles = $this->predef_titles; - $this->html_hashes = array(); - - $in_anchor = false; - } - - function teardown() { - # - # Called after the transformation process to clear any variable - # which may be taking up memory unnecessarly. - # - $this->urls = array(); - $this->titles = array(); - $this->html_hashes = array(); - } - - - function transform($text) { - # - # Main function. Performs some preprocessing on the input text - # and pass it through the document gamut. - # - $this->setup(); - - # Remove UTF-8 BOM and marker character in input, if present. - $text = preg_replace('{^\xEF\xBB\xBF|\x1A}', '', $text); - - # Standardize line endings: - # DOS to Unix and Mac to Unix - $text = preg_replace('{\r\n?}', "\n", $text); - - # Make sure $text ends with a couple of newlines: - $text .= "\n\n"; - - # Convert all tabs to spaces. - $text = $this->detab($text); - - # Turn block-level HTML blocks into hash entries - $text = $this->hashHTMLBlocks($text); - - # Strip any lines consisting only of spaces and tabs. - # This makes subsequent regexen easier to write, because we can - # match consecutive blank lines with /\n+/ instead of something - # contorted like /[ ]*\n+/ . - $text = preg_replace('/^[ ]+$/m', '', $text); - - # Run document gamut methods. - foreach ($this->document_gamut as $method => $priority) { - $text = $this->$method($text); - } - - $this->teardown(); - - return $text . "\n"; - } - - var $document_gamut = array( - # Strip link definitions, store in hashes. - "stripLinkDefinitions" => 20, - - "runBasicBlockGamut" => 30, - ); - - - function stripLinkDefinitions($text) { - # - # Strips link definitions from text, stores the URLs and titles in - # hash references. - # - $less_than_tab = $this->tab_width - 1; - - # Link defs are in the form: ^[id]: url "optional title" - $text = preg_replace_callback('{ - ^[ ]{0,'.$less_than_tab.'}\[(.+)\][ ]?: # id = $1 - [ ]* - \n? # maybe *one* newline - [ ]* - (\S+?)>? # url = $2 - [ ]* - \n? # maybe one newline - [ ]* - (?: - (?<=\s) # lookbehind for whitespace - ["(] - (.*?) # title = $3 - [")] - [ ]* - )? # title is optional - (?:\n+|\Z) - }xm', - array(&$this, '_stripLinkDefinitions_callback'), - $text); - return $text; - } - function _stripLinkDefinitions_callback($matches) { - $link_id = strtolower($matches[1]); - $this->urls[$link_id] = $matches[2]; - $this->titles[$link_id] =& $matches[3]; - return ''; # String that will replace the block - } - - - function hashHTMLBlocks($text) { - if ($this->no_markup) return $text; - - $less_than_tab = $this->tab_width - 1; - - # Hashify HTML blocks: - # We only want to do this for block-level HTML tags, such as headers, - # lists, and tables. That's because we still want to wrap
s around - # "paragraphs" that are wrapped in non-block-level tags, such as anchors, - # phrase emphasis, and spans. The list of tags we're looking for is - # hard-coded: - # - # * List "a" is made of tags which can be both inline or block-level. - # These will be treated block-level when the start tag is alone on - # its line, otherwise they're not matched here and will be taken as - # inline later. - # * List "b" is made of tags which are always block-level; - # - $block_tags_a_re = 'ins|del'; - $block_tags_b_re = 'p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|address|'. - 'script|noscript|form|fieldset|iframe|math'; - - # Regular expression for the content of a block tag. - $nested_tags_level = 4; - $attr = ' - (?> # optional tag attributes - \s # starts with whitespace - (?> - [^>"/]+ # text outside quotes - | - /+(?!>) # slash not followed by ">" - | - "[^"]*" # text inside double quotes (tolerate ">") - | - \'[^\']*\' # text inside single quotes (tolerate ">") - )* - )? - '; - $content = - str_repeat(' - (?> - [^<]+ # content without tag - | - <\2 # nested opening tag - '.$attr.' # attributes - (?> - /> - | - >', $nested_tags_level). # end of opening tag - '.*?'. # last level nested tag content - str_repeat(' - \2\s*> # closing nested tag - ) - | - <(?!/\2\s*> # other tags with a different name - ) - )*', - $nested_tags_level); - $content2 = str_replace('\2', '\3', $content); - - # First, look for nested blocks, e.g.: - #
` blocks.
-	#
-		$text = preg_replace_callback('{
-				(?:\n\n|\A\n?)
-				(	            # $1 = the code block -- one or more lines, starting with a space/tab
-				  (?>
-					[ ]{'.$this->tab_width.'}  # Lines must start with a tab or a tab-width of spaces
-					.*\n+
-				  )+
-				)
-				((?=^[ ]{0,'.$this->tab_width.'}\S)|\Z)	# Lookahead for non-space at line-start, or end of doc
-			}xm',
-			array(&$this, '_doCodeBlocks_callback'), $text);
-
-		return $text;
-	}
-	function _doCodeBlocks_callback($matches) {
-		$codeblock = $matches[1];
-
-		$codeblock = $this->outdent($codeblock);
-		$codeblock = htmlspecialchars($codeblock, ENT_NOQUOTES);
-
-		# trim leading newlines and trailing newlines
-		$codeblock = preg_replace('/\A\n+|\n+\z/', '', $codeblock);
-
-		$codeblock = "$codeblock\n
";
-		return "\n\n".$this->hashBlock($codeblock)."\n\n";
-	}
-
-
-	function makeCodeSpan($code) {
-	#
-	# Create a code span markup for $code. Called from handleSpanToken.
-	#
-		$code = htmlspecialchars(trim($code), ENT_NOQUOTES);
-		return $this->hashPart("$code");
-	}
-
-
-	var $em_relist = array(
-		''  => '(?:(? '(?<=\S)(? '(?<=\S)(? '(?:(? '(?<=\S)(? '(?<=\S)(? '(?:(? '(?<=\S)(? '(?<=\S)(?em_relist as $em => $em_re) {
-			foreach ($this->strong_relist as $strong => $strong_re) {
-				# Construct list of allowed token expressions.
-				$token_relist = array();
-				if (isset($this->em_strong_relist["$em$strong"])) {
-					$token_relist[] = $this->em_strong_relist["$em$strong"];
-				}
-				$token_relist[] = $em_re;
-				$token_relist[] = $strong_re;
-				
-				# Construct master expression from list.
-				$token_re = '{('. implode('|', $token_relist) .')}';
-				$this->em_strong_prepared_relist["$em$strong"] = $token_re;
-			}
-		}
-	}
-	
-	function doItalicsAndBold($text) {
-		$token_stack = array('');
-		$text_stack = array('');
-		$em = '';
-		$strong = '';
-		$tree_char_em = false;
-		
-		while (1) {
-			#
-			# Get prepared regular expression for seraching emphasis tokens
-			# in current context.
-			#
-			$token_re = $this->em_strong_prepared_relist["$em$strong"];
-			
-			#
-			# Each loop iteration seach for the next emphasis token. 
-			# Each token is then passed to handleSpanToken.
-			#
-			$parts = preg_split($token_re, $text, 2, PREG_SPLIT_DELIM_CAPTURE);
-			$text_stack[0] .= $parts[0];
-			$token =& $parts[1];
-			$text =& $parts[2];
-			
-			if (empty($token)) {
-				# Reached end of text span: empty stack without emitting.
-				# any more emphasis.
-				while ($token_stack[0]) {
-					$text_stack[1] .= array_shift($token_stack);
-					$text_stack[0] .= array_shift($text_stack);
-				}
-				break;
-			}
-			
-			$token_len = strlen($token);
-			if ($tree_char_em) {
-				# Reached closing marker while inside a three-char emphasis.
-				if ($token_len == 3) {
-					# Three-char closing marker, close em and strong.
-					array_shift($token_stack);
-					$span = array_shift($text_stack);
-					$span = $this->runSpanGamut($span);
-					$span = "$span";
-					$text_stack[0] .= $this->hashPart($span);
-					$em = '';
-					$strong = '';
-				} else {
-					# Other closing marker: close one em or strong and
-					# change current token state to match the other
-					$token_stack[0] = str_repeat($token{0}, 3-$token_len);
-					$tag = $token_len == 2 ? "strong" : "em";
-					$span = $text_stack[0];
-					$span = $this->runSpanGamut($span);
-					$span = "<$tag>$span$tag>";
-					$text_stack[0] = $this->hashPart($span);
-					$$tag = ''; # $$tag stands for $em or $strong
-				}
-				$tree_char_em = false;
-			} else if ($token_len == 3) {
-				if ($em) {
-					# Reached closing marker for both em and strong.
-					# Closing strong marker:
-					for ($i = 0; $i < 2; ++$i) {
-						$shifted_token = array_shift($token_stack);
-						$tag = strlen($shifted_token) == 2 ? "strong" : "em";
-						$span = array_shift($text_stack);
-						$span = $this->runSpanGamut($span);
-						$span = "<$tag>$span$tag>";
-						$text_stack[0] .= $this->hashPart($span);
-						$$tag = ''; # $$tag stands for $em or $strong
-					}
-				} else {
-					# Reached opening three-char emphasis marker. Push on token 
-					# stack; will be handled by the special condition above.
-					$em = $token{0};
-					$strong = "$em$em";
-					array_unshift($token_stack, $token);
-					array_unshift($text_stack, '');
-					$tree_char_em = true;
-				}
-			} else if ($token_len == 2) {
-				if ($strong) {
-					# Unwind any dangling emphasis marker:
-					if (strlen($token_stack[0]) == 1) {
-						$text_stack[1] .= array_shift($token_stack);
-						$text_stack[0] .= array_shift($text_stack);
-					}
-					# Closing strong marker:
-					array_shift($token_stack);
-					$span = array_shift($text_stack);
-					$span = $this->runSpanGamut($span);
-					$span = "$span";
-					$text_stack[0] .= $this->hashPart($span);
-					$strong = '';
-				} else {
-					array_unshift($token_stack, $token);
-					array_unshift($text_stack, '');
-					$strong = $token;
-				}
-			} else {
-				# Here $token_len == 1
-				if ($em) {
-					if (strlen($token_stack[0]) == 1) {
-						# Closing emphasis marker:
-						array_shift($token_stack);
-						$span = array_shift($text_stack);
-						$span = $this->runSpanGamut($span);
-						$span = "$span";
-						$text_stack[0] .= $this->hashPart($span);
-						$em = '';
-					} else {
-						$text_stack[0] .= $token;
-					}
-				} else {
-					array_unshift($token_stack, $token);
-					array_unshift($text_stack, '');
-					$em = $token;
-				}
-			}
-		}
-		return $text_stack[0];
-	}
-
-
-	function doBlockQuotes($text) {
-		$text = preg_replace_callback('/
-			  (								# Wrap whole match in $1
-				(?>
-				  ^[ ]*>[ ]?			# ">" at the start of a line
-					.+\n					# rest of the first line
-				  (.+\n)*					# subsequent consecutive lines
-				  \n*						# blanks
-				)+
-			  )
-			/xm',
-			array(&$this, '_doBlockQuotes_callback'), $text);
-
-		return $text;
-	}
-	function _doBlockQuotes_callback($matches) {
-		$bq = $matches[1];
-		# trim one level of quoting - trim whitespace-only lines
-		$bq = preg_replace('/^[ ]*>[ ]?|^[ ]+$/m', '', $bq);
-		$bq = $this->runBlockGamut($bq);		# recurse
-
-		$bq = preg_replace('/^/m', "  ", $bq);
-		# These leading spaces cause problem with  content, 
-		# so we need to fix that:
-		$bq = preg_replace_callback('{(\s*.+?
)}sx', 
-			array(&$this, '_DoBlockQuotes_callback2'), $bq);
-
-		return "\n". $this->hashBlock("\n$bq\n
")."\n\n";
-	}
-	function _doBlockQuotes_callback2($matches) {
-		$pre = $matches[1];
-		$pre = preg_replace('/^  /m', '', $pre);
-		return $pre;
-	}
-
-
-	function formParagraphs($text) {
-	#
-	#	Params:
-	#		$text - string to process with html  tags
-	#
-		# Strip leading and trailing lines:
-		$text = preg_replace('/\A\n+|\n+\z/', '', $text);
-
-		$grafs = preg_split('/\n{2,}/', $text, -1, PREG_SPLIT_NO_EMPTY);
-
-		#
-		# Wrap 
 tags and unhashify HTML blocks
-		#
-		foreach ($grafs as $key => $value) {
-			if (!preg_match('/^B\x1A[0-9]+B$/', $value)) {
-				# Is a paragraph.
-				$value = $this->runSpanGamut($value);
-				$value = preg_replace('/^([ ]*)/', "
", $value);
-				$value .= "
";
-				$grafs[$key] = $this->unhash($value);
-			}
-			else {
-				# Is a block.
-				# Modify elements of @grafs in-place...
-				$graf = $value;
-				$block = $this->html_hashes[$graf];
-				$graf = $block;
-//				if (preg_match('{
-//					\A
-//					(							# $1 =  tag
-//					  ]*
-//					  \b
-//					  markdown\s*=\s*  ([\'"])	#	$2 = attr quote char
-//					  1
-//					  \2
-//					  [^>]*
-//					  >
-//					)
-//					(							# $3 = contents
-//					.*
-//					)
-//					()					# $4 = closing tag
-//					\z
-//					}xs', $block, $matches))
-//				{
-//					list(, $div_open, , $div_content, $div_close) = $matches;
-//
-//					# We can't call Markdown(), because that resets the hash;
-//					# that initialization code should be pulled into its own sub, though.
-//					$div_content = $this->hashHTMLBlocks($div_content);
-//					
-//					# Run document gamut methods on the content.
-//					foreach ($this->document_gamut as $method => $priority) {
-//						$div_content = $this->$method($div_content);
-//					}
-//
-//					$div_open = preg_replace(
-//						'{\smarkdown\s*=\s*([\'"]).+?\1}', '', $div_open);
-//
-//					$graf = $div_open . "\n" . $div_content . "\n" . $div_close;
-//				}
-				$grafs[$key] = $graf;
-			}
-		}
-
-		return implode("\n\n", $grafs);
-	}
-
-
-	function encodeAttribute($text) {
-	#
-	# Encode text for a double-quoted HTML attribute. This function
-	# is *not* suitable for attributes enclosed in single quotes.
-	#
-		$text = $this->encodeAmpsAndAngles($text);
-		$text = str_replace('"', '"', $text);
-		return $text;
-	}
-	
-	
-	function encodeAmpsAndAngles($text) {
-	#
-	# Smart processing for ampersands and angle brackets that need to 
-	# be encoded. Valid character entities are left alone unless the
-	# no-entities mode is set.
-	#
-		if ($this->no_entities) {
-			$text = str_replace('&', '&', $text);
-		} else {
-			# Ampersand-encoding based entirely on Nat Irons's Amputator
-			# MT plugin: s around
-	# "paragraphs" that are wrapped in non-block-level tags, such as anchors,
-	# phrase emphasis, and spans. The list of tags we're looking for is
-	# hard-coded.
-	#
-	# This works by calling _HashHTMLBlocks_InMarkdown, which then calls
-	# _HashHTMLBlocks_InHTML when it encounter block tags. When the markdown="1" 
-	# attribute is found whitin a tag, _HashHTMLBlocks_InHTML calls back
-	#  _HashHTMLBlocks_InMarkdown to handle the Markdown syntax within the tag.
-	# These two functions are calling each other. It's recursive!
-	#
-		#
-		# Call the HTML-in-Markdown hasher.
-		#
-		list($text, ) = $this->_hashHTMLBlocks_inMarkdown($text);
-		
-		return $text;
-	}
-	function _hashHTMLBlocks_inMarkdown($text, $indent = 0, 
-										$enclosing_tag_re = '', $span = false)
-	{
-	#
-	# Parse markdown text, calling _HashHTMLBlocks_InHTML for block tags.
-	#
-	# *   $indent is the number of space to be ignored when checking for code 
-	#     blocks. This is important because if we don't take the indent into 
-	#     account, something like this (which looks right) won't work as expected:
-	#
-	#     
-	#         
-	#         Hello World.  <-- Is this a Markdown code block or text?
-	#           <-- Is this a Markdown code block or a real tag?
-	#     
-	#
-	#     If you don't like this, just don't indent the tag on which
-	#     you apply the markdown="1" attribute.
-	#
-	# *   If $enclosing_tag_re is not empty, stops at the first unmatched closing 
-	#     tag with that name. Nested tags supported.
-	#
-	# *   If $span is true, text inside must treated as span. So any double 
-	#     newline will be replaced by a single newline so that it does not create 
-	#     paragraphs.
-	#
-	# Returns an array of that form: ( processed text , remaining text )
-	#
-		if ($text === '') return array('', '');
-
-		# Regex to check for the presense of newlines around a block tag.
-		$newline_before_re = '/(?:^\n?|\n\n)*$/';
-		$newline_after_re = 
-			'{
-				^						# Start of text following the tag.
-				(?>[ ]*)?		# Optional comment.
-				[ ]*\n					# Must be followed by newline.
-			}xs';
-		
-		# Regex to match any tag.
-		$block_tag_re =
-			'{
-				(					# $2: Capture hole tag.
-					?					# Any opening or closing tag.
-						(?>				# Tag name.
-							'.$this->block_tags_re.'			|
-							'.$this->context_block_tags_re.'	|
-							'.$this->clean_tags_re.'        	|
-							(?!\s)'.$enclosing_tag_re.'
-						)
-						(?:
-							(?=[\s"\'/a-zA-Z0-9])	# Allowed characters after tag name.
-							(?>
-								".*?"		|	# Double quotes (can contain `>`)
-								\'.*?\'   	|	# Single quotes (can contain `>`)
-								.+?				# Anything but quotes and `>`.
-							)*?
-						)?
-					>					# End of tag.
-				|
-						# HTML Comment
-				|
-					<\?.*?\?> | <%.*?%>	# Processing instruction
-				|
-						# CData Block
-				|
-					# Code span marker
-					`+
-				'. ( !$span ? ' # If not in span.
-				|
-					# Indented code block
-					(?> ^[ ]*\n? | \n[ ]*\n )
-					[ ]{'.($indent+4).'}[^\n]* \n
-					(?>
-						(?: [ ]{'.($indent+4).'}[^\n]* | [ ]* ) \n
-					)*
-				|
-					# Fenced code block marker
-					(?> ^ | \n )
-					[ ]{'.($indent).'}~~~+[ ]*\n
-				' : '' ). ' # End (if not is span).
-				)
-			}xs';
-
-		
-		$depth = 0;		# Current depth inside the tag tree.
-		$parsed = "";	# Parsed text that will be returned.
-
-		#
-		# Loop through every tag until we find the closing tag of the parent
-		# or loop until reaching the end of text if no parent tag specified.
-		#
-		do {
-			#
-			# Split the text using the first $tag_match pattern found.
-			# Text before  pattern will be first in the array, text after
-			# pattern will be at the end, and between will be any catches made 
-			# by the pattern.
-			#
-			$parts = preg_split($block_tag_re, $text, 2, 
-								PREG_SPLIT_DELIM_CAPTURE);
-			
-			# If in Markdown span mode, add a empty-string span-level hash 
-			# after each newline to prevent triggering any block element.
-			if ($span) {
-				$void = $this->hashPart("", ':');
-				$newline = "$void\n";
-				$parts[0] = $void . str_replace("\n", $newline, $parts[0]) . $void;
-			}
-			
-			$parsed .= $parts[0]; # Text before current tag.
-			
-			# If end of $text has been reached. Stop loop.
-			if (count($parts) < 3) {
-				$text = "";
-				break;
-			}
-			
-			$tag  = $parts[1]; # Tag to handle.
-			$text = $parts[2]; # Remaining text after current tag.
-			$tag_re = preg_quote($tag); # For use in a regular expression.
-			
-			#
-			# Check for: Code span marker
-			#
-			if ($tag{0} == "`") {
-				# Find corresponding end marker.
-				$tag_re = preg_quote($tag);
-				if (preg_match('{^(?>.+?|\n(?!\n))*?(?.*\n)+?'.$tag_re.' *\n}', $text, 
-						$matches)) 
-					{
-						# End marker found: pass text unchanged until marker.
-						$parsed .= $tag . $matches[0];
-						$text = substr($text, strlen($matches[0]));
-					}
-					else {
-						# No end marker: just skip it.
-						$parsed .= $tag;
-					}
-				}
-			}
-			#
-			# Check for: Opening Block level tag or
-			#            Opening Context Block tag (like ins and del) 
-			#               used as a block tag (tag is alone on it's line).
-			#
-			else if (preg_match('{^<(?:'.$this->block_tags_re.')\b}', $tag) ||
-				(	preg_match('{^<(?:'.$this->context_block_tags_re.')\b}', $tag) &&
-					preg_match($newline_before_re, $parsed) &&
-					preg_match($newline_after_re, $text)	)
-				)
-			{
-				# Need to parse tag and following text using the HTML parser.
-				list($block_text, $text) = 
-					$this->_hashHTMLBlocks_inHTML($tag . $text, "hashBlock", true);
-				
-				# Make sure it stays outside of any paragraph by adding newlines.
-				$parsed .= "\n\n$block_text\n\n";
-			}
-			#
-			# Check for: Clean tag (like script, math)
-			#            HTML Comments, processing instructions.
-			#
-			else if (preg_match('{^<(?:'.$this->clean_tags_re.')\b}', $tag) ||
-				$tag{1} == '!' || $tag{1} == '?')
-			{
-				# Need to parse tag and following text using the HTML parser.
-				# (don't check for markdown attribute)
-				list($block_text, $text) = 
-					$this->_hashHTMLBlocks_inHTML($tag . $text, "hashClean", false);
-				
-				$parsed .= $block_text;
-			}
-			#
-			# Check for: Tag with same name as enclosing tag.
-			#
-			else if ($enclosing_tag_re !== '' &&
-				# Same name as enclosing tag.
-				preg_match('{^?(?:'.$enclosing_tag_re.')\b}', $tag))
-			{
-				#
-				# Increase/decrease nested tag count.
-				#
-				if ($tag{1} == '/')						$depth--;
-				else if ($tag{strlen($tag)-2} != '/')	$depth++;
-
-				if ($depth < 0) {
-					#
-					# Going out of parent element. Clean up and break so we
-					# return to the calling function.
-					#
-					$text = $tag . $text;
-					break;
-				}
-				
-				$parsed .= $tag;
-			}
-			else {
-				$parsed .= $tag;
-			}
-		} while ($depth >= 0);
-		
-		return array($parsed, $text);
-	}
-	function _hashHTMLBlocks_inHTML($text, $hash_method, $md_attr) {
-	#
-	# Parse HTML, calling _HashHTMLBlocks_InMarkdown for block tags.
-	#
-	# *   Calls $hash_method to convert any blocks.
-	# *   Stops when the first opening tag closes.
-	# *   $md_attr indicate if the use of the `markdown="1"` attribute is allowed.
-	#     (it is not inside clean tags)
-	#
-	# Returns an array of that form: ( processed text , remaining text )
-	#
-		if ($text === '') return array('', '');
-		
-		# Regex to match `markdown` attribute inside of a tag.
-		$markdown_attr_re = '
-			{
-				\s*			# Eat whitespace before the `markdown` attribute
-				markdown
-				\s*=\s*
-				(?>
-					(["\'])		# $1: quote delimiter		
-					(.*?)		# $2: attribute value
-					\1			# matching delimiter	
-				|
-					([^\s>]*)	# $3: unquoted attribute value
-				)
-				()				# $4: make $3 always defined (avoid warnings)
-			}xs';
-		
-		# Regex to match any tag.
-		$tag_re = '{
-				(					# $2: Capture hole tag.
-					?					# Any opening or closing tag.
-						[\w:$]+			# Tag name.
-						(?:
-							(?=[\s"\'/a-zA-Z0-9])	# Allowed characters after tag name.
-							(?>
-								".*?"		|	# Double quotes (can contain `>`)
-								\'.*?\'   	|	# Single quotes (can contain `>`)
-								.+?				# Anything but quotes and `>`.
-							)*?
-						)?
-					>					# End of tag.
-				|
-						# HTML Comment
-				|
-					<\?.*?\?> | <%.*?%>	# Processing instruction
-				|
-						# CData Block
-				)
-			}xs';
-		
-		$original_text = $text;		# Save original text in case of faliure.
-		
-		$depth		= 0;	# Current depth inside the tag tree.
-		$block_text	= "";	# Temporary text holder for current text.
-		$parsed		= "";	# Parsed text that will be returned.
-
-		#
-		# Get the name of the starting tag.
-		# (This pattern makes $base_tag_name_re safe without quoting.)
-		#
-		if (preg_match('/^<([\w:$]*)\b/', $text, $matches))
-			$base_tag_name_re = $matches[1];
-
-		#
-		# Loop through every tag until we find the corresponding closing tag.
-		#
-		do {
-			#
-			# Split the text using the first $tag_match pattern found.
-			# Text before  pattern will be first in the array, text after
-			# pattern will be at the end, and between will be any catches made 
-			# by the pattern.
-			#
-			$parts = preg_split($tag_re, $text, 2, PREG_SPLIT_DELIM_CAPTURE);
-			
-			if (count($parts) < 3) {
-				#
-				# End of $text reached with unbalenced tag(s).
-				# In that case, we return original text unchanged and pass the
-				# first character as filtered to prevent an infinite loop in the 
-				# parent function.
-				#
-				return array($original_text{0}, substr($original_text, 1));
-			}
-			
-			$block_text .= $parts[0]; # Text before current tag.
-			$tag         = $parts[1]; # Tag to handle.
-			$text        = $parts[2]; # Remaining text after current tag.
-			
-			#
-			# Check for: Auto-close tag (like 
)
-			#			 Comments and Processing Instructions.
-			#
-			if (preg_match('{^?(?:'.$this->auto_close_tags_re.')\b}', $tag) ||
-				$tag{1} == '!' || $tag{1} == '?')
-			{
-				# Just add the tag to the block as if it was text.
-				$block_text .= $tag;
-			}
-			else {
-				#
-				# Increase/decrease nested tag count. Only do so if
-				# the tag's name match base tag's.
-				#
-				if (preg_match('{^?'.$base_tag_name_re.'\b}', $tag)) {
-					if ($tag{1} == '/')						$depth--;
-					else if ($tag{strlen($tag)-2} != '/')	$depth++;
-				}
-				
-				#
-				# Check for `markdown="1"` attribute and handle it.
-				#
-				if ($md_attr && 
-					preg_match($markdown_attr_re, $tag, $attr_m) &&
-					preg_match('/^1|block|span$/', $attr_m[2] . $attr_m[3]))
-				{
-					# Remove `markdown` attribute from opening tag.
-					$tag = preg_replace($markdown_attr_re, '', $tag);
-					
-					# Check if text inside this tag must be parsed in span mode.
-					$this->mode = $attr_m[2] . $attr_m[3];
-					$span_mode = $this->mode == 'span' || $this->mode != 'block' &&
-						preg_match('{^<(?:'.$this->contain_span_tags_re.')\b}', $tag);
-					
-					# Calculate indent before tag.
-					if (preg_match('/(?:^|\n)( *?)(?! ).*?$/', $block_text, $matches)) {
-						$strlen = $this->utf8_strlen;
-						$indent = $strlen($matches[1], 'UTF-8');
-					} else {
-						$indent = 0;
-					}
-					
-					# End preceding block with this tag.
-					$block_text .= $tag;
-					$parsed .= $this->$hash_method($block_text);
-					
-					# Get enclosing tag name for the ParseMarkdown function.
-					# (This pattern makes $tag_name_re safe without quoting.)
-					preg_match('/^<([\w:$]*)\b/', $tag, $matches);
-					$tag_name_re = $matches[1];
-					
-					# Parse the content using the HTML-in-Markdown parser.
-					list ($block_text, $text)
-						= $this->_hashHTMLBlocks_inMarkdown($text, $indent, 
-							$tag_name_re, $span_mode);
-					
-					# Outdent markdown text.
-					if ($indent > 0) {
-						$block_text = preg_replace("/^[ ]{1,$indent}/m", "", 
-													$block_text);
-					}
-					
-					# Append tag content to parsed text.
-					if (!$span_mode)	$parsed .= "\n\n$block_text\n\n";
-					else				$parsed .= "$block_text";
-					
-					# Start over a new block.
-					$block_text = "";
-				}
-				else $block_text .= $tag;
-			}
-			
-		} while ($depth > 0);
-		
-		#
-		# Hash last block text that wasn't processed inside the loop.
-		#
-		$parsed .= $this->$hash_method($block_text);
-		
-		return array($parsed, $text);
-	}
-
-
-	function hashClean($text) {
-	#
-	# Called whenever a tag must be hashed when a function insert a "clean" tag
-	# in $text, it pass through this function and is automaticaly escaped, 
-	# blocking invalid nested overlap.
-	#
-		return $this->hashPart($text, 'C');
-	}
-
-
-	function doHeaders($text) {
-	#
-	# Redefined to add id attribute support.
-	#
-		# Setext-style headers:
-		#	  Header 1  {#header1}
-		#	  ========
-		#  
-		#	  Header 2  {#header2}
-		#	  --------
-		#
-		$text = preg_replace_callback(
-			'{
-				(^.+?)								# $1: Header text
-				(?:[ ]+\{\#([-_:a-zA-Z0-9]+)\})?	# $2: Id attribute
-				[ ]*\n(=+|-+)[ ]*\n+				# $3: Header footer
-			}mx',
-			array(&$this, '_doHeaders_callback_setext'), $text);
-
-		# atx-style headers:
-		#	# Header 1        {#header1}
-		#	## Header 2       {#header2}
-		#	## Header 2 with closing hashes ##  {#header3}
-		#	...
-		#	###### Header 6   {#header2}
-		#
-		$text = preg_replace_callback('{
-				^(\#{1,6})	# $1 = string of #\'s
-				[ ]*
-				(.+?)		# $2 = Header text
-				[ ]*
-				\#*			# optional closing #\'s (not counted)
-				(?:[ ]+\{\#([-_:a-zA-Z0-9]+)\})? # id attribute
-				[ ]*
-				\n+
-			}xm',
-			array(&$this, '_doHeaders_callback_atx'), $text);
-
-		return $text;
-	}
-	function _doHeaders_attr($attr) {
-		if (empty($attr))  return "";
-		return " id=\"$attr\"";
-	}
-	function _doHeaders_callback_setext($matches) {
-		if ($matches[3] == '-' && preg_match('{^- }', $matches[1]))
-			return $matches[0];
-		$level = $matches[3]{0} == '=' ? 1 : 2;
-		$attr  = $this->_doHeaders_attr($id =& $matches[2]);
-		$block = "".$this->runSpanGamut($matches[1])." ";
-		return "\n" . $this->hashBlock($block) . "\n\n";
-	}
-	function _doHeaders_callback_atx($matches) {
-		$level = strlen($matches[1]);
-		$attr  = $this->_doHeaders_attr($id =& $matches[3]);
-		$block = "".$this->runSpanGamut($matches[2])." ";
-		return "\n" . $this->hashBlock($block) . "\n\n";
-	}
-
-
-	function doTables($text) {
-	#
-	# Form HTML tables.
-	#
-		$less_than_tab = $this->tab_width - 1;
-		#
-		# Find tables with leading pipe.
-		#
-		#	| Header 1 | Header 2
-		#	| -------- | --------
-		#	| Cell 1   | Cell 2
-		#	| Cell 3   | Cell 4
-		#
-		$text = preg_replace_callback('
-			{
-				^							# Start of a line
-				[ ]{0,'.$less_than_tab.'}	# Allowed whitespace.
-				[|]							# Optional leading pipe (present)
-				(.+) \n						# $1: Header row (at least one pipe)
-				
-				[ ]{0,'.$less_than_tab.'}	# Allowed whitespace.
-				[|] ([ ]*[-:]+[-| :]*) \n	# $2: Header underline
-				
-				(							# $3: Cells
-					(?>
-						[ ]*				# Allowed whitespace.
-						[|] .* \n			# Row content.
-					)*
-				)
-				(?=\n|\Z)					# Stop at final double newline.
-			}xm',
-			array(&$this, '_doTable_leadingPipe_callback'), $text);
-		
-		#
-		# Find tables without leading pipe.
-		#
-		#	Header 1 | Header 2
-		#	-------- | --------
-		#	Cell 1   | Cell 2
-		#	Cell 3   | Cell 4
-		#
-		$text = preg_replace_callback('
-			{
-				^							# Start of a line
-				[ ]{0,'.$less_than_tab.'}	# Allowed whitespace.
-				(\S.*[|].*) \n				# $1: Header row (at least one pipe)
-				
-				[ ]{0,'.$less_than_tab.'}	# Allowed whitespace.
-				([-:]+[ ]*[|][-| :]*) \n	# $2: Header underline
-				
-				(							# $3: Cells
-					(?>
-						.* [|] .* \n		# Row content
-					)*
-				)
-				(?=\n|\Z)					# Stop at final double newline.
-			}xm',
-			array(&$this, '_DoTable_callback'), $text);
-
-		return $text;
-	}
-	function _doTable_leadingPipe_callback($matches) {
-		$head		= $matches[1];
-		$underline	= $matches[2];
-		$content	= $matches[3];
-		
-		# Remove leading pipe for each row.
-		$content	= preg_replace('/^ *[|]/m', '', $content);
-		
-		return $this->_doTable_callback(array($matches[0], $head, $underline, $content));
-	}
-	function _doTable_callback($matches) {
-		$head		= $matches[1];
-		$underline	= $matches[2];
-		$content	= $matches[3];
-
-		# Remove any tailing pipes for each line.
-		$head		= preg_replace('/[|] *$/m', '', $head);
-		$underline	= preg_replace('/[|] *$/m', '', $underline);
-		$content	= preg_replace('/[|] *$/m', '', $content);
-		
-		# Reading alignement from header underline.
-		$separators	= preg_split('/ *[|] */', $underline);
-		foreach ($separators as $n => $s) {
-			if (preg_match('/^ *-+: *$/', $s))		$attr[$n] = ' align="right"';
-			else if (preg_match('/^ *:-+: *$/', $s))$attr[$n] = ' align="center"';
-			else if (preg_match('/^ *:-+ *$/', $s))	$attr[$n] = ' align="left"';
-			else									$attr[$n] = '';
-		}
-		
-		# Parsing span elements, including code spans, character escapes, 
-		# and inline HTML tags, so that pipes inside those gets ignored.
-		$head		= $this->parseSpan($head);
-		$headers	= preg_split('/ *[|] */', $head);
-		$col_count	= count($headers);
-		
-		# Write column headers.
-		$text = "\n";
-		$text .= "\n";
-		$text .= "\n";
-		foreach ($headers as $n => $header)
-			$text .= "  ".$this->runSpanGamut(trim($header))." \n";
-		$text .= " \n";
-		$text .= "\n";
-		
-		# Split content by row.
-		$rows = explode("\n", trim($content, "\n"));
-		
-		$text .= "\n";
-		foreach ($rows as $row) {
-			# Parsing span elements, including code spans, character escapes, 
-			# and inline HTML tags, so that pipes inside those gets ignored.
-			$row = $this->parseSpan($row);
-			
-			# Split row by cell.
-			$row_cells = preg_split('/ *[|] */', $row, $col_count);
-			$row_cells = array_pad($row_cells, $col_count, '');
-			
-			$text .= "\n";
-			foreach ($row_cells as $n => $cell)
-				$text .= "  ".$this->runSpanGamut(trim($cell))." \n";
-			$text .= " \n";
-		}
-		$text .= "\n";
-		$text .= "
";
-		
-		return $this->hashBlock($text) . "\n";
-	}
-
-	
-	function doDefLists($text) {
-	#
-	# Form HTML definition lists.
-	#
-		$less_than_tab = $this->tab_width - 1;
-
-		# Re-usable pattern to match any entire dl list:
-		$whole_list_re = '(?>
-			(								# $1 = whole list
-			  (								# $2
-				[ ]{0,'.$less_than_tab.'}
-				((?>.*\S.*\n)+)				# $3 = defined term
-				\n?
-				[ ]{0,'.$less_than_tab.'}:[ ]+ # colon starting definition
-			  )
-			  (?s:.+?)
-			  (								# $4
-				  \z
-				|
-				  \n{2,}
-				  (?=\S)
-				  (?!						# Negative lookahead for another term
-					[ ]{0,'.$less_than_tab.'}
-					(?: \S.*\n )+?			# defined term
-					\n?
-					[ ]{0,'.$less_than_tab.'}:[ ]+ # colon starting definition
-				  )
-				  (?!						# Negative lookahead for another definition
-					[ ]{0,'.$less_than_tab.'}:[ ]+ # colon starting definition
-				  )
-			  )
-			)
-		)'; // mx
-
-		$text = preg_replace_callback('{
-				(?>\A\n?|(?<=\n\n))
-				'.$whole_list_re.'
-			}mx',
-			array(&$this, '_doDefLists_callback'), $text);
-
-		return $text;
-	}
-	function _doDefLists_callback($matches) {
-		# Re-usable patterns to match list item bullets and number markers:
-		$list = $matches[1];
-		
-		# Turn double returns into triple returns, so that we can make a
-		# paragraph for the last item in a list, if necessary:
-		$result = trim($this->processDefListItems($list));
-		$result = "\n" . $result . "\n
";
-		return $this->hashBlock($result) . "\n\n";
-	}
-
-
-	function processDefListItems($list_str) {
-	#
-	#	Process the contents of a single definition list, splitting it
-	#	into individual term and definition list items.
-	#
-		$less_than_tab = $this->tab_width - 1;
-		
-		# trim trailing blank lines:
-		$list_str = preg_replace("/\n{2,}\\z/", "\n", $list_str);
-
-		# Process definition terms.
-		$list_str = preg_replace_callback('{
-			(?>\A\n?|\n\n+)					# leading line
-			(								# definition terms = $1
-				[ ]{0,'.$less_than_tab.'}	# leading whitespace
-				(?![:][ ]|[ ])				# negative lookahead for a definition 
-											#   mark (colon) or more whitespace.
-				(?> \S.* \n)+?				# actual term (not whitespace).	
-			)			
-			(?=\n?[ ]{0,3}:[ ])				# lookahead for following line feed 
-											#   with a definition mark.
-			}xm',
-			array(&$this, '_processDefListItems_callback_dt'), $list_str);
-
-		# Process actual definitions.
-		$list_str = preg_replace_callback('{
-			\n(\n+)?						# leading line = $1
-			(								# marker space = $2
-				[ ]{0,'.$less_than_tab.'}	# whitespace before colon
-				[:][ ]+						# definition mark (colon)
-			)
-			((?s:.+?))						# definition text = $3
-			(?= \n+ 						# stop at next definition mark,
-				(?:							# next term or end of text
-					[ ]{0,'.$less_than_tab.'} [:][ ]	|
- | \z
-				)						
-			)					
-			}xm',
-			array(&$this, '_processDefListItems_callback_dd'), $list_str);
-
-		return $list_str;
-	}
-	function _processDefListItems_callback_dt($matches) {
-		$terms = explode("\n", trim($matches[1]));
-		$text = '';
-		foreach ($terms as $term) {
-			$term = $this->runSpanGamut(trim($term));
-			$text .= "\n" . $term . " ";
-		}
-		return $text . "\n";
-	}
-	function _processDefListItems_callback_dd($matches) {
-		$leading_line	= $matches[1];
-		$marker_space	= $matches[2];
-		$def			= $matches[3];
-
-		if ($leading_line || preg_match('/\n{2,}/', $def)) {
-			# Replace marker with the appropriate whitespace indentation
-			$def = str_repeat(' ', strlen($marker_space)) . $def;
-			$def = $this->runBlockGamut($this->outdent($def . "\n\n"));
-			$def = "\n". $def ."\n";
-		}
-		else {
-			$def = rtrim($def);
-			$def = $this->runSpanGamut($this->outdent($def));
-		}
-
-		return "\n " . $def . " \n";
-	}
-
-
-	function doFencedCodeBlocks($text) {
-	#
-	# Adding the fenced code block syntax to regular Markdown:
-	#
-	# ~~~
-	# Code block
-	# ~~~
-	#
-		$less_than_tab = $this->tab_width;
-		
-		$text = preg_replace_callback('{
-				(?:\n|\A)
-				# 1: Opening marker
-				(
-					~{3,} # Marker: three tilde or more.
-				)
-				[ ]* \n # Whitespace and newline following marker.
-				
-				# 2: Content
-				(
-					(?>
-						(?!\1 [ ]* \n)	# Not a closing marker.
-						.*\n+
-					)+
-				)
-				
-				# Closing marker.
-				\1 [ ]* \n
-			}xm',
-			array(&$this, '_doFencedCodeBlocks_callback'), $text);
-
-		return $text;
-	}
-	function _doFencedCodeBlocks_callback($matches) {
-		$codeblock = $matches[2];
-		$codeblock = htmlspecialchars($codeblock, ENT_NOQUOTES);
-		$codeblock = preg_replace_callback('/^\n+/',
-			array(&$this, '_doFencedCodeBlocks_newlines'), $codeblock);
-		$codeblock = "$codeblock
";
-		return "\n\n".$this->hashBlock($codeblock)."\n\n";
-	}
-	function _doFencedCodeBlocks_newlines($matches) {
-		return str_repeat("
empty_element_suffix", 
-			strlen($matches[0]));
-	}
-
-
-	#
-	# Redefining emphasis markers so that emphasis by underscore does not
-	# work in the middle of a word.
-	#
-	var $em_relist = array(
-		''  => '(?:(? '(?<=\S)(? '(?<=\S)(? '(?:(? '(?<=\S)(? '(?<=\S)(? '(?:(? '(?<=\S)(? '(?<=\S)(? tags
-	#
-		# Strip leading and trailing lines:
-		$text = preg_replace('/\A\n+|\n+\z/', '', $text);
-		
-		$grafs = preg_split('/\n{2,}/', $text, -1, PREG_SPLIT_NO_EMPTY);
-
-		#
-		# Wrap  tags and unhashify HTML blocks
-		#
-		foreach ($grafs as $key => $value) {
-			$value = trim($this->runSpanGamut($value));
-			
-			# Check if this should be enclosed in a paragraph.
-			# Clean tag hashes & block tag hashes are left alone.
-			$is_p = !preg_match('/^B\x1A[0-9]+B|^C\x1A[0-9]+C$/', $value);
-			
-			if ($is_p) {
-				$value = "
$value
";
-			}
-			$grafs[$key] = $value;
-		}
-		
-		# Join grafs in one text, then unhash HTML tags. 
-		$text = implode("\n\n", $grafs);
-		
-		# Finish by removing any tag hashes still present in $text.
-		$text = $this->unhash($text);
-		
-		return $text;
-	}
-	
-	
-	### Footnotes
-	
-	function stripFootnotes($text) {
-	#
-	# Strips link definitions from text, stores the URLs and titles in
-	# hash references.
-	#
-		$less_than_tab = $this->tab_width - 1;
-
-		# Link defs are in the form: [^id]: url "optional title"
-		$text = preg_replace_callback('{
-			^[ ]{0,'.$less_than_tab.'}\[\^(.+?)\][ ]?:	# note_id = $1
-			  [ ]*
-			  \n?					# maybe *one* newline
-			(						# text = $2 (no blank lines allowed)
-				(?:					
-					.+				# actual text
-				|
-					\n				# newlines but 
-					(?!\[\^.+?\]:\s)# negative lookahead for footnote marker.
-					(?!\n+[ ]{0,3}\S)# ensure line is not blank and followed 
-									# by non-indented content
-				)*
-			)		
-			}xm',
-			array(&$this, '_stripFootnotes_callback'),
-			$text);
-		return $text;
-	}
-	function _stripFootnotes_callback($matches) {
-		$note_id = $this->fn_id_prefix . $matches[1];
-		$this->footnotes[$note_id] = $this->outdent($matches[2]);
-		return ''; # String that will replace the block
-	}
-
-
-	function doFootnotes($text) {
-	#
-	# Replace footnote references in $text [^id] with a special text-token 
-	# which will be replaced by the actual footnote marker in appendFootnotes.
-	#
-		if (!$this->in_anchor) {
-			$text = preg_replace('{\[\^(.+?)\]}', "F\x1Afn:\\1\x1A:", $text);
-		}
-		return $text;
-	}
-
-	
-	function appendFootnotes($text) {
-	#
-	# Append footnote list to text.
-	#
-		$text = preg_replace_callback('{F\x1Afn:(.*?)\x1A:}', 
-			array(&$this, '_appendFootnotes_callback'), $text);
-	
-		if (!empty($this->footnotes_ordered)) {
-			$text .= "\n\n";
-			$text .= "\n";
-			$text .= "
fn_backlink_class != "") {
-				$class = $this->fn_backlink_class;
-				$class = $this->encodeAttribute($class);
-				$attr .= " class=\"$class\"";
-			}
-			if ($this->fn_backlink_title != "") {
-				$title = $this->fn_backlink_title;
-				$title = $this->encodeAttribute($title);
-				$attr .= " title=\"$title\"";
-			}
-			$num = 0;
-			
-			while (!empty($this->footnotes_ordered)) {
-				$footnote = reset($this->footnotes_ordered);
-				$note_id = key($this->footnotes_ordered);
-				unset($this->footnotes_ordered[$note_id]);
-				
-				$footnote .= "\n"; # Need to append newline before parsing.
-				$footnote = $this->runBlockGamut("$footnote\n");				
-				$footnote = preg_replace_callback('{F\x1Afn:(.*?)\x1A:}', 
-					array(&$this, '_appendFootnotes_callback'), $footnote);
-				
-				$attr = str_replace("%%", ++$num, $attr);
-				$note_id = $this->encodeAttribute($note_id);
-				
-				# Add backlink to last paragraph; create new paragraph if needed.
-				$backlink = "↩";
-				if (preg_match('{$}', $footnote)) {
-					$footnote = substr($footnote, 0, -4) . " $backlink";
-				} else {
-					$footnote .= "\n\n$backlink
";
-				}
-				
-				$text .= "\n";
-				$text .= $footnote . "\n";
-				$text .= " \n\n";
-			}
-			
-			$text .= "\n";
-			$text .= "";
-		}
-		return $text;
-	}
-	function _appendFootnotes_callback($matches) {
-		$node_id = $this->fn_id_prefix . $matches[1];
-		
-		# Create footnote marker only if it has a corresponding footnote *and*
-		# the footnote hasn't been used by another marker.
-		if (isset($this->footnotes[$node_id])) {
-			# Transfert footnote content to the ordered list.
-			$this->footnotes_ordered[$node_id] = $this->footnotes[$node_id];
-			unset($this->footnotes[$node_id]);
-			
-			$num = $this->footnote_counter++;
-			$attr = " rel=\"footnote\"";
-			if ($this->fn_link_class != "") {
-				$class = $this->fn_link_class;
-				$class = $this->encodeAttribute($class);
-				$attr .= " class=\"$class\"";
-			}
-			if ($this->fn_link_title != "") {
-				$title = $this->fn_link_title;
-				$title = $this->encodeAttribute($title);
-				$attr .= " title=\"$title\"";
-			}
-			
-			$attr = str_replace("%%", $num, $attr);
-			$node_id = $this->encodeAttribute($node_id);
-			
-			return
-				"".
-				"$num".
-				"";
-		}
-		
-		return "[^".$matches[1]."]";
-	}
-		
-	
-	### Abbreviations ###
-	
-	function stripAbbreviations($text) {
-	#
-	# Strips abbreviations from text, stores titles in hash references.
-	#
-		$less_than_tab = $this->tab_width - 1;
-
-		# Link defs are in the form: [id]*: url "optional title"
-		$text = preg_replace_callback('{
-			^[ ]{0,'.$less_than_tab.'}\*\[(.+?)\][ ]?:	# abbr_id = $1
-			(.*)					# text = $2 (no blank lines allowed)	
-			}xm',
-			array(&$this, '_stripAbbreviations_callback'),
-			$text);
-		return $text;
-	}
-	function _stripAbbreviations_callback($matches) {
-		$abbr_word = $matches[1];
-		$abbr_desc = $matches[2];
-		if ($this->abbr_word_re)
-			$this->abbr_word_re .= '|';
-		$this->abbr_word_re .= preg_quote($abbr_word);
-		$this->abbr_desciptions[$abbr_word] = trim($abbr_desc);
-		return ''; # String that will replace the block
-	}
-	
-	
-	function doAbbreviations($text) {
-	#
-	# Find defined abbreviations in text and wrap them in  elements.
-	#
-		if ($this->abbr_word_re) {
-			// cannot use the /x modifier because abbr_word_re may 
-			// contain significant spaces:
-			$text = preg_replace_callback('{'.
-				'(?abbr_word_re.')'.
-				'(?![\w\x1A])'.
-				'}', 
-				array(&$this, '_doAbbreviations_callback'), $text);
-		}
-		return $text;
-	}
-	function _doAbbreviations_callback($matches) {
-		$abbr = $matches[0];
-		if (isset($this->abbr_desciptions[$abbr])) {
-			$desc = $this->abbr_desciptions[$abbr];
-			if (empty($desc)) {
-				return $this->hashPart("$abbr");
-			} else {
-				$desc = $this->encodeAttribute($desc);
-				return $this->hashPart("$abbr");
-			}
-		} else {
-			return $matches[0];
-		}
-	}
-
-}
-
-
-/*
-
-PHP Markdown Extra
-==================
-
-Description
------------
-
-This is a PHP port of the original Markdown formatter written in Perl 
-by John Gruber. This special "Extra" version of PHP Markdown features 
-further enhancements to the syntax for making additional constructs 
-such as tables and definition list.
-
-Markdown is a text-to-HTML filter; it translates an easy-to-read /
-easy-to-write structured text format into HTML. Markdown's text format
-is most similar to that of plain text email, and supports features such
-as headers, *emphasis*, code blocks, blockquotes, and links.
-
-Markdown's syntax is designed not as a generic markup language, but
-specifically to serve as a front-end to (X)HTML. You can use span-level
-HTML tags anywhere in a Markdown document, and you can use block level
-HTML tags (like  and  as well).
-
-For more information about Markdown's syntax, see:
-
-
-
-Please include with your report: (1) the example input; (2) the output you
-expected; (3) the output Markdown actually produced.
-
-
-Version History
---------------- 
-
-See the readme file for detailed release notes for this version.
-
-
-Copyright and License
----------------------
-
-PHP Markdown & Extra
-Copyright (c) 2004-2008 Michel Fortin  
-
Date: Wed, 23 Dec 2009 12:42:57 -0800
Subject: Updated Kohana to r4728
---
 system/core/Kohana.php                 |  7 ++---
 system/core/Kohana_Exception.php       | 26 ++++++++++--------
 system/libraries/Input.php             | 31 +--------------------
 system/messages/core.php               | 37 -------------------------
 system/messages/kohana/core.php        | 37 +++++++++++++++++++++++++
 system/messages/validation/default.php | 42 ++++++++++++++++------------
 system/views/kohana/error.php          | 50 +++++++++++++++++-----------------
 7 files changed, 104 insertions(+), 126 deletions(-)
 delete mode 100644 system/messages/core.php
 create mode 100644 system/messages/kohana/core.php
(limited to 'system/libraries/Input.php')
diff --git a/system/core/Kohana.php b/system/core/Kohana.php
index 740adb80..29ca708c 100644
--- a/system/core/Kohana.php
+++ b/system/core/Kohana.php
@@ -2,7 +2,7 @@
 /**
  * Provides Kohana-specific helper functions. This is where the magic happens!
  *
- * $Id: Kohana.php 4724 2009-12-21 16:28:54Z isaiah $
+ * $Id: Kohana.php 4726 2009-12-23 18:58:53Z isaiah $
  *
  * @package    Core
  * @author     Kohana Team
@@ -810,11 +810,8 @@ abstract class Kohana_Core {
 		{
 			if ($required === TRUE)
 			{
-				// Directory i18n key
-				$directory = 'core.'.inflector::singular($directory);
-
 				// If the file is required, throw an exception
-				throw new Kohana_Exception('The requested :resource:, :file:, could not be found', array(':resource:' => Kohana::message($directory), ':file:' =>$filename));
+				throw new Kohana_Exception('The requested :resource:, :file:, could not be found', array(':resource:' => __($directory), ':file:' =>$filename));
 			}
 			else
 			{
diff --git a/system/core/Kohana_Exception.php b/system/core/Kohana_Exception.php
index 2eb28f75..0cbc472c 100644
--- a/system/core/Kohana_Exception.php
+++ b/system/core/Kohana_Exception.php
@@ -2,7 +2,7 @@
 /**
  * Kohana Exceptions
  *
- * $Id: Kohana_Exception.php 4692 2009-12-04 15:59:44Z cbandy $
+ * $Id: Kohana_Exception.php 4726 2009-12-23 18:58:53Z isaiah $
  *
  * @package    Core
  * @author     Kohana Team
@@ -119,7 +119,7 @@ class Kohana_Exception_Core extends Exception {
 			// Manually save logs after exceptions
 			Kohana_Log::save();
 
-			if (Kohana::config('core.display_errors') === FALSE)
+			if (Kohana::config('kohana/core.display_errors') === FALSE)
 			{
 				// Do not show the details
 				$file = $line = NULL;
@@ -146,7 +146,7 @@ class Kohana_Exception_Core extends Exception {
 				}
 
 				// Use the human-readable error name
-				$code = Kohana::message('core.errors.'.$code);
+				$code = Kohana::message('kohana/core.errors.'.$code);
 			}
 			else
 			{
@@ -160,7 +160,7 @@ class Kohana_Exception_Core extends Exception {
 				if ($e instanceof ErrorException)
 				{
 					// Use the human-readable error name
-					$code = Kohana::message('core.errors.'.$e->getSeverity());
+					$code = Kohana::message('kohana/core.errors.'.$e->getSeverity());
 
 					if (version_compare(PHP_VERSION, '5.3', '<'))
 					{
@@ -233,11 +233,12 @@ class Kohana_Exception_Core extends Exception {
 	 *
 	 * @param   mixed    variable to dump
 	 * @param   integer  maximum length of strings
+	 * @param   integer  maximum levels of recursion
 	 * @return  string
 	 */
-	public static function dump($value, $length = 128)
+	public static function dump($value, $length = 128, $max_level = 5)
 	{
-		return Kohana_Exception::_dump($value, $length);
+		return Kohana_Exception::_dump($value, $length, $max_level);
 	}
 
 	/**
@@ -245,10 +246,11 @@ class Kohana_Exception_Core extends Exception {
 	 *
 	 * @param   mixed    variable to dump
 	 * @param   integer  maximum length of strings
-	 * @param   integer  recursion level (internal)
+	 * @param   integer  maximum levels of recursion
+	 * @param   integer  current recursion level (internal)
 	 * @return  string
 	 */
-	private static function _dump( & $var, $length = 128, $level = 0)
+	private static function _dump( & $var, $length = 128, $max_level = 5, $level = 0)
 	{
 		if ($var === NULL)
 		{
@@ -327,7 +329,7 @@ class Kohana_Exception_Core extends Exception {
 			{
 				$output[] = "(\n$space$s*RECURSION*\n$space)";
 			}
-			elseif ($level < 5)
+			elseif ($level <= $max_level)
 			{
 				$output[] = "(";
 
@@ -340,7 +342,7 @@ class Kohana_Exception_Core extends Exception {
 						$key = '"'.$key.'"';
 					}
 
-					$output[] = "$space$s$key => ".Kohana_Exception::_dump($val, $length, $level + 1);
+					$output[] = "$space$s$key => ".Kohana_Exception::_dump($val, $length, $max_level, $level + 1);
 				}
 				unset($var[$marker]);
 
@@ -377,7 +379,7 @@ class Kohana_Exception_Core extends Exception {
 			{
 				$output[] = "{\n$space$s*RECURSION*\n$space}";
 			}
-			elseif ($level < 5)
+			elseif ($level <= $max_level)
 			{
 				$output[] = "{";
 
@@ -397,7 +399,7 @@ class Kohana_Exception_Core extends Exception {
 						$access = 'public';
 					}
 
-					$output[] = "$space$s$access $key => ".Kohana_Exception::_dump($val, $length, $level + 1);
+					$output[] = "$space$s$access $key => ".Kohana_Exception::_dump($val, $length, $max_level, $level + 1);
 				}
 				unset($objects[$hash]);
 
diff --git a/system/libraries/Input.php b/system/libraries/Input.php
index 04403854..7a277317 100644
--- a/system/libraries/Input.php
+++ b/system/libraries/Input.php
@@ -2,7 +2,7 @@
 /**
  * Input library.
  *
- * $Id: Input.php 4720 2009-12-17 21:15:03Z isaiah $
+ * $Id: Input.php 4727 2009-12-23 19:03:05Z isaiah $
  *
  * @package    Core
  * @author     Kohana Team
@@ -79,35 +79,6 @@ class Input_Core {
 				Kohana_Log::add('debug', 'Disable magic_quotes_gpc! It is evil and deprecated: http://php.net/magic_quotes');
 			}
 
-			// register_globals is enabled
-			if (ini_get('register_globals'))
-			{
-				if (isset($_REQUEST['GLOBALS']))
-				{
-					// Prevent GLOBALS override attacks
-					exit('Global variable overload attack.');
-				}
-
-				// Destroy the REQUEST global
-				$_REQUEST = array();
-
-				// These globals are standard and should not be removed
-				$preserve = array('GLOBALS', '_REQUEST', '_GET', '_POST', '_FILES', '_COOKIE', '_SERVER', '_ENV', '_SESSION');
-
-				// This loop has the same effect as disabling register_globals
-				foreach (array_diff(array_keys($GLOBALS), $preserve) as $key)
-				{
-					global $$key;
-					$$key = NULL;
-
-					// Unset the global variable
-					unset($GLOBALS[$key], $$key);
-				}
-
-				// Warn the developer about register globals
-				Kohana_Log::add('debug', 'Disable register_globals! It is evil and deprecated: http://php.net/register_globals');
-			}
-
 			if (is_array($_GET))
 			{
 				foreach ($_GET as $key => $val)
diff --git a/system/messages/core.php b/system/messages/core.php
deleted file mode 100644
index 64f897e8..00000000
--- a/system/messages/core.php
+++ /dev/null
@@ -1,37 +0,0 @@
- array
-	(
-		E_KOHANA             => __('Framework Error'),   // __('Please check the Kohana documentation for information about the following error.'),
-		E_PAGE_NOT_FOUND     => __('Page Not Found'),    // __('The requested page was not found. It may have moved, been deleted, or archived.'),
-		E_DATABASE_ERROR     => __('Database Error'),    // __('A database error occurred while performing the requested procedure. Please review the database error below for more information.'),
-		E_RECOVERABLE_ERROR  => __('Recoverable Error'), // __('An error was detected which prevented the loading of this page. If this problem persists, please contact the website administrator.'),
-		E_ERROR              => __('Fatal Error'),
-		E_COMPILE_ERROR      => __('Fatal Error'),
-		E_CORE_ERROR         => __('Fatal Error'),
-		E_USER_ERROR         => __('Fatal Error'),
-		E_PARSE              => __('Syntax Error'),
-		E_WARNING            => __('Warning Message'),
-		E_COMPILE_WARNING    => __('Warning Message'),
-		E_CORE_WARNING       => __('Warning Message'),
-		E_USER_WARNING       => __('Warning Message'),
-		E_STRICT             => __('Strict Mode Error'),
-		E_NOTICE             => __('Runtime Message'),
-		E_USER_NOTICE        => __('Runtime Message'),
-	),
-	'config'             => 'config file',
-	'controller'         => 'controller',
-	'helper'             => 'helper',
-	'library'            => 'library',
-	'driver'             => 'driver',
-	'model'              => 'model',
-	'view'               => 'view',
-);
-
-// E_DEPRECATED is only defined in PHP >= 5.3.0
-if (defined('E_DEPRECATED'))
-{
-	$messages['errors'][E_DEPRECATED] = __('Deprecated');
-}
\ No newline at end of file
diff --git a/system/messages/kohana/core.php b/system/messages/kohana/core.php
new file mode 100644
index 00000000..1361809b
--- /dev/null
+++ b/system/messages/kohana/core.php
@@ -0,0 +1,37 @@
+ array
+	(
+		E_KOHANA             => 'Framework Error',
+		E_PAGE_NOT_FOUND     => 'Page Not Found',
+		E_DATABASE_ERROR     => 'Database Error',
+		E_RECOVERABLE_ERROR  => 'Recoverable Error',
+		E_ERROR              => 'Fatal Error',
+		E_COMPILE_ERROR      => 'Fatal Error',
+		E_CORE_ERROR         => 'Fatal Error',
+		E_USER_ERROR         => 'Fatal Error',
+		E_PARSE              => 'Syntax Error',
+		E_WARNING            => 'Warning Message',
+		E_COMPILE_WARNING    => 'Warning Message',
+		E_CORE_WARNING       => 'Warning Message',
+		E_USER_WARNING       => 'Warning Message',
+		E_STRICT             => 'Strict Mode Error',
+		E_NOTICE             => 'Runtime Message',
+		E_USER_NOTICE        => 'Runtime Message',
+	),
+);
+
+// E_DEPRECATED is only defined in PHP >= 5.3.0
+if (defined('E_DEPRECATED'))
+{
+	$messages['errors'][E_DEPRECATED] = 'Deprecated';
+}
\ No newline at end of file
diff --git a/system/messages/validation/default.php b/system/messages/validation/default.php
index 2c59fa06..88580a6b 100644
--- a/system/messages/validation/default.php
+++ b/system/messages/validation/default.php
@@ -1,17 +1,25 @@
- 'The :field field is required',
-	'length'        => 'The :field field must be between :param1 and :param2 characters long',
-	'depends_on'    => 'The :field field requires the :param1 field',
-	'matches'       => 'The :field field must be the same as :param1',
-	'email'         => 'The :field field must be a valid email address',
-	'decimal'       => 'The :field field must be a decimal with :param1 places',
-	'digit'         => 'The :field field must be a digit',
-	'in_array'      => 'The :field field must be one of the available options',
-	'alpha_numeric' => 'The :field field must consist only of alphabetical or numeric characters',
-	'alpha_dash '   => 'The :field field must consist only of alphabetical, numeric, underscore and dash characters',
-	'numeric '      => 'The :field field must be a valid number',
-	'url'           => 'The :field field must be a valid url',
-	'phone'         => 'The :field field must be a valid phone number',
-);
+ 'The :field field is required',
+	'length'        => 'The :field field must be between :param1 and :param2 characters long',
+	'depends_on'    => 'The :field field requires the :param1 field',
+	'matches'       => 'The :field field must be the same as :param1',
+	'email'         => 'The :field field must be a valid email address',
+	'decimal'       => 'The :field field must be a decimal with :param1 places',
+	'digit'         => 'The :field field must be a digit',
+	'in_array'      => 'The :field field must be one of the available options',
+	'alpha_numeric' => 'The :field field must consist only of alphabetical or numeric characters',
+	'alpha_dash '   => 'The :field field must consist only of alphabetical, numeric, underscore and dash characters',
+	'numeric '      => 'The :field field must be a valid number',
+	'url'           => 'The :field field must be a valid url',
+	'phone'         => 'The :field field must be a valid phone number',
+);
diff --git a/system/views/kohana/error.php b/system/views/kohana/error.php
index b40c0f8a..aa6770c4 100644
--- a/system/views/kohana/error.php
+++ b/system/views/kohana/error.php
@@ -3,7 +3,7 @@
 $error_id = uniqid('error');
 ?>