Browse Source

Remove more fuel package source

Hamilton Turner 10 years ago
parent
commit
a4beca446e
35 changed files with 0 additions and 10789 deletions
  1. 0 12
      frameworks/PHP/php-fuel/fuel/packages/orm/.gitignore
  2. 0 41
      frameworks/PHP/php-fuel/fuel/packages/orm/bootstrap.php
  3. 0 221
      frameworks/PHP/php-fuel/fuel/packages/orm/classes/belongsto.php
  4. 0 272
      frameworks/PHP/php-fuel/fuel/packages/orm/classes/hasmany.php
  5. 0 230
      frameworks/PHP/php-fuel/fuel/packages/orm/classes/hasone.php
  6. 0 353
      frameworks/PHP/php-fuel/fuel/packages/orm/classes/manymany.php
  7. 0 1909
      frameworks/PHP/php-fuel/fuel/packages/orm/classes/model.php
  8. 0 303
      frameworks/PHP/php-fuel/fuel/packages/orm/classes/model/soft.php
  9. 0 55
      frameworks/PHP/php-fuel/fuel/packages/orm/classes/observer.php
  10. 0 63
      frameworks/PHP/php-fuel/fuel/packages/orm/classes/observer/createdat.php
  11. 0 34
      frameworks/PHP/php-fuel/fuel/packages/orm/classes/observer/self.php
  12. 0 111
      frameworks/PHP/php-fuel/fuel/packages/orm/classes/observer/slug.php
  13. 0 445
      frameworks/PHP/php-fuel/fuel/packages/orm/classes/observer/typing.php
  14. 0 66
      frameworks/PHP/php-fuel/fuel/packages/orm/classes/observer/updatedat.php
  15. 0 219
      frameworks/PHP/php-fuel/fuel/packages/orm/classes/observer/validation.php
  16. 0 1330
      frameworks/PHP/php-fuel/fuel/packages/orm/classes/query.php
  17. 0 145
      frameworks/PHP/php-fuel/fuel/packages/orm/classes/relation.php
  18. 0 15
      frameworks/PHP/php-fuel/fuel/packages/parser/.gitignore
  19. 0 53
      frameworks/PHP/php-fuel/fuel/packages/parser/README.md
  20. 0 32
      frameworks/PHP/php-fuel/fuel/packages/parser/bootstrap.php
  21. 0 93
      frameworks/PHP/php-fuel/fuel/packages/parser/classes/twig/fuel/extension.php
  22. 0 112
      frameworks/PHP/php-fuel/fuel/packages/parser/classes/view.php
  23. 0 85
      frameworks/PHP/php-fuel/fuel/packages/parser/classes/view/dwoo.php
  24. 0 75
      frameworks/PHP/php-fuel/fuel/packages/parser/classes/view/haml.php
  25. 0 81
      frameworks/PHP/php-fuel/fuel/packages/parser/classes/view/jade.php
  26. 0 89
      frameworks/PHP/php-fuel/fuel/packages/parser/classes/view/markdown.php
  27. 0 66
      frameworks/PHP/php-fuel/fuel/packages/parser/classes/view/mustache.php
  28. 0 65
      frameworks/PHP/php-fuel/fuel/packages/parser/classes/view/phptal.php
  29. 0 81
      frameworks/PHP/php-fuel/fuel/packages/parser/classes/view/smarty.php
  30. 0 117
      frameworks/PHP/php-fuel/fuel/packages/parser/classes/view/twig.php
  31. 0 166
      frameworks/PHP/php-fuel/fuel/packages/parser/config/parser.php
  32. 0 22
      frameworks/PHP/php-fuel/fuel/packages/parser/vendor/Mustache/LICENSE
  33. 0 861
      frameworks/PHP/php-fuel/fuel/packages/parser/vendor/Mustache/Mustache.php
  34. 0 36
      frameworks/PHP/php-fuel/fuel/packages/parser/vendor/markdown/License.text
  35. 0 2931
      frameworks/PHP/php-fuel/fuel/packages/parser/vendor/markdown/markdown.php

+ 0 - 12
frameworks/PHP/php-fuel/fuel/packages/orm/.gitignore

@@ -1,12 +0,0 @@
-*~
-*.bak
-Thumbs.db
-desktop.ini
-.DS_Store
-.buildpath
-.project
-.settings
-fuel/app/logs/*/*/*
-fuel/app/cache/*/*
-nbproject/
-.idea

+ 0 - 41
frameworks/PHP/php-fuel/fuel/packages/orm/bootstrap.php

@@ -1,41 +0,0 @@
-<?php
-/**
- * Fuel is a fast, lightweight, community driven PHP5 framework.
- *
- * @package    Fuel
- * @version    1.5
- * @author     Fuel Development Team
- * @license    MIT License
- * @copyright  2010 - 2013 Fuel Development Team
- * @link       http://fuelphp.com
- */
-
-
-Autoloader::add_classes(array(
-	'Orm\\Model'        => __DIR__.'/classes/model.php',
-	'Orm\\Query'        => __DIR__.'/classes/query.php',
-	'Orm\\BelongsTo'    => __DIR__.'/classes/belongsto.php',
-	'Orm\\HasMany'      => __DIR__.'/classes/hasmany.php',
-	'Orm\\HasOne'       => __DIR__.'/classes/hasone.php',
-	'Orm\\ManyMany'     => __DIR__.'/classes/manymany.php',
-	'Orm\\Relation'     => __DIR__.'/classes/relation.php',
-
-	//Speclised models
-	'Orm\\Model_Soft'      => __DIR__.'/classes/model/soft.php',
-
-	// Observers
-	'Orm\\Observer'             => __DIR__.'/classes/observer.php',
-	'Orm\\Observer_CreatedAt'   => __DIR__.'/classes/observer/createdat.php',
-	'Orm\\Observer_Typing'      => __DIR__.'/classes/observer/typing.php',
-	'Orm\\Observer_UpdatedAt'   => __DIR__.'/classes/observer/updatedat.php',
-	'Orm\\Observer_Validation'  => __DIR__.'/classes/observer/validation.php',
-	'Orm\\Observer_Self'        => __DIR__.'/classes/observer/self.php',
-	'Orm\\Observer_Slug'        => __DIR__.'/classes/observer/slug.php',
-
-	// Exceptions
-	'Orm\\RecordNotFound'      => __DIR__.'/classes/model.php',
-	'Orm\\FrozenObject'        => __DIR__.'/classes/model.php',
-	'Orm\\InvalidContentType'  => __DIR__.'/classes/observer/typing.php',
-	'Orm\\ValidationFailed'    => __DIR__.'/classes/observer/validation.php',
-	'Orm\\RelationNotSoft' => __DIR__.'/classes/model/soft.php',
-));

+ 0 - 221
frameworks/PHP/php-fuel/fuel/packages/orm/classes/belongsto.php

@@ -1,221 +0,0 @@
-<?php
-/**
- * Fuel is a fast, lightweight, community driven PHP5 framework.
- *
- * @package    Fuel
- * @version    1.5
- * @author     Fuel Development Team
- * @license    MIT License
- * @copyright  2010 - 2013 Fuel Development Team
- * @link       http://fuelphp.com
- */
-
-namespace Orm;
-
-class BelongsTo extends Relation
-{
-	protected $singular = true;
-
-	protected $key_from = array();
-
-	protected $key_to = array('id');
-
-	public function __construct($from, $name, array $config)
-	{
-		$this->name        = $name;
-		$this->model_from  = $from;
-		$this->model_to    = array_key_exists('model_to', $config)
-			? $config['model_to'] : \Inflector::get_namespace($from).'Model_'.\Inflector::classify($name);
-		$this->key_from    = array_key_exists('key_from', $config)
-			? (array) $config['key_from'] : (array) \Inflector::foreign_key($this->model_to);
-		$this->key_to      = array_key_exists('key_to', $config)
-			? (array) $config['key_to'] : $this->key_to;
-		$this->conditions  = array_key_exists('conditions', $config)
-			? (array) $config['conditions'] : array();
-
-		$this->cascade_save    = array_key_exists('cascade_save', $config)
-			? $config['cascade_save'] : $this->cascade_save;
-		$this->cascade_delete  = array_key_exists('cascade_delete', $config)
-			? $config['cascade_delete'] : $this->cascade_delete;
-
-		if ( ! class_exists($this->model_to))
-		{
-			throw new \FuelException('Related model not found by Belongs_To relation "'.$this->name.'": '.$this->model_to);
-		}
-		$this->model_to = get_real_class($this->model_to);
-	}
-
-	public function get(Model $from)
-	{
-		$query = call_user_func(array($this->model_to, 'query'));
-		reset($this->key_to);
-		foreach ($this->key_from as $key)
-		{
-			// no point running a query when a key value is null
-			if ($from->{$key} === null)
-			{
-				return null;
-			}
-			$query->where(current($this->key_to), $from->{$key});
-			next($this->key_to);
-		}
-
-		foreach (\Arr::get($this->conditions, 'where', array()) as $key => $condition)
-		{
-			is_array($condition) or $condition = array($key, '=', $condition);
-			$query->where($condition);
-		}
-		return $query->get_one();
-	}
-
-	public function join($alias_from, $rel_name, $alias_to_nr, $conditions = array())
-	{
-		$alias_to = 't'.$alias_to_nr;
-		$model = array(
-			'model'        => $this->model_to,
-			'connection'   => call_user_func(array($this->model_to, 'connection')),
-			'table'        => array(call_user_func(array($this->model_to, 'table')), $alias_to),
-			'primary_key'  => call_user_func(array($this->model_to, 'primary_key')),
-			'join_type'    => \Arr::get($conditions, 'join_type') ?: \Arr::get($this->conditions, 'join_type', 'left'),
-			'join_on'      => array(),
-			'columns'      => $this->select($alias_to),
-			'rel_name'     => strpos($rel_name, '.') ? substr($rel_name, strrpos($rel_name, '.') + 1) : $rel_name,
-			'relation'     => $this,
-			'where'        => \Arr::get($conditions, 'where', array()),
-			'order_by'     => \Arr::get($conditions, 'order_by') ?: \Arr::get($this->conditions, 'order_by', array()),
-		);
-
-		reset($this->key_to);
-		foreach ($this->key_from as $key)
-		{
-			$model['join_on'][] = array($alias_from.'.'.$key, '=', $alias_to.'.'.current($this->key_to));
-			next($this->key_to);
-		}
-		foreach (\Arr::get($this->conditions, 'where', array()) as $key => $condition)
-		{
-			! is_array($condition) and $condition = array($key, '=', $condition);
-			if ( ! $condition[0] instanceof \Fuel\Core\Database_Expression and strpos($condition[0], '.') === false)
-			{
-				$condition[0] = $alias_to.'.'.$condition[0];
-			}
-			is_string($condition[2]) and $condition[2] = \Db::quote($condition[2], $model['connection']);
-
-			$model['join_on'][] = $condition;
-		}
-
-		return array($rel_name => $model);
-	}
-
-	public function save($model_from, $model_to, $original_model_id, $parent_saved, $cascade)
-	{
-		if ($parent_saved)
-		{
-			return;
-		}
-
-		if ( ! $model_to instanceof $this->model_to and $model_to !== null)
-		{
-			throw new \FuelException('Invalid Model instance added to relations in this model.');
-		}
-
-		// Save if it's a yet unsaved object
-		if ($model_to and $model_to->is_new())
-		{
-			$model_to->save(false);
-		}
-
-		$current_model_id = $model_to ? $model_to->implode_pk($model_to) : null;
-		// Check if there was another model assigned (this supersedes any change to the foreign key(s))
-		if ($current_model_id != $original_model_id)
-		{
-			// change the foreign keys in the model_from to point to the new relation
-			reset($this->key_from);
-			$model_from->unfreeze();
-			foreach ($this->key_to as $pk)
-			{
-				$model_from->{current($this->key_from)} = $model_to ? $model_to->{$pk} : null;
-				next($this->key_from);
-			}
-			$model_from->freeze();
-		}
-		// if not check the model_from's foreign_keys
-		else
-		{
-			$foreign_keys = count($this->key_to) == 1 ? array($original_model_id) : explode('][', substr($original_model_id, 1, -1));
-			$changed      = false;
-			$new_rel_id   = array();
-			reset($foreign_keys);
-			foreach ($this->key_from as $fk)
-			{
-				if (is_null($model_from->{$fk}))
-				{
-					$changed = true;
-					$new_rel_id = null;
-					break;
-				}
-				elseif ($model_from->{$fk} != current($foreign_keys))
-				{
-					$changed = true;
-				}
-				$new_rel_id[] = $model_from->{$fk};
-				next($foreign_keys);
-			}
-
-			// if any of the keys changed, reload the relationship - saving the object will save those keys
-			if ($changed)
-			{
-				// Attempt to load the new related object
-				if ( ! is_null($new_rel_id))
-				{
-					$rel_obj = call_user_func(array($this->model_to, 'find'), $new_rel_id);
-					if (empty($rel_obj))
-					{
-						throw new \FuelException('New relation set on '.$this->model_from.' object wasn\'t found.');
-					}
-				}
-				else
-				{
-					$rel_obj = null;
-				}
-
-				// Add the new relation to the model_from
-				$model_from->unfreeze();
-				$rel = $model_from->_relate();
-				$rel[$this->name] = $rel_obj;
-				$model_from->_relate($rel);
-				$model_from->freeze();
-			}
-		}
-
-		$cascade = is_null($cascade) ? $this->cascade_save : (bool) $cascade;
-		if ($cascade and ! empty($model_to))
-		{
-			$model_to->save();
-		}
-	}
-
-	public function delete($model_from, $model_to, $parent_deleted, $cascade)
-	{
-		if ($parent_deleted)
-		{
-			return;
-		}
-
-		// break current relations
-		$model_from->unfreeze();
-		$rels = $model_from->_relate();
-		$rels[$this->name] = null;
-		$model_from->_relate($rels);
-		foreach ($this->key_from as $fk)
-		{
-			$model_from->{$fk} = null;
-		}
-		$model_from->freeze();
-
-		$cascade = is_null($cascade) ? $this->cascade_delete : (bool) $cascade;
-		if ($cascade and ! empty($model_to))
-		{
-			$model_to->delete();
-		}
-	}
-}

+ 0 - 272
frameworks/PHP/php-fuel/fuel/packages/orm/classes/hasmany.php

@@ -1,272 +0,0 @@
-<?php
-/**
- * Fuel is a fast, lightweight, community driven PHP5 framework.
- *
- * @package    Fuel
- * @version    1.5
- * @author     Fuel Development Team
- * @license    MIT License
- * @copyright  2010 - 2013 Fuel Development Team
- * @link       http://fuelphp.com
- */
-
-namespace Orm;
-
-class HasMany extends Relation
-{
-	public function __construct($from, $name, array $config)
-	{
-		$this->name        = $name;
-		$this->model_from  = $from;
-		$this->model_to    = array_key_exists('model_to', $config)
-			? $config['model_to'] : \Inflector::get_namespace($from).'Model_'.\Inflector::classify($name);
-		$this->key_from    = array_key_exists('key_from', $config)
-			? (array) $config['key_from'] : $this->key_from;
-		$this->key_to      = array_key_exists('key_to', $config)
-			? (array) $config['key_to'] : (array) \Inflector::foreign_key($this->model_from);
-		$this->conditions  = array_key_exists('conditions', $config)
-			? (array) $config['conditions'] : array();
-
-		$this->cascade_save    = array_key_exists('cascade_save', $config)
-			? $config['cascade_save'] : $this->cascade_save;
-		$this->cascade_delete  = array_key_exists('cascade_delete', $config)
-			? $config['cascade_delete'] : $this->cascade_delete;
-
-		if ( ! class_exists($this->model_to))
-		{
-			throw new \FuelException('Related model not found by Has_Many relation "'.$this->name.'": '.$this->model_to);
-		}
-		$this->model_to = get_real_class($this->model_to);
-	}
-
-	public function get(Model $from)
-	{
-		$query = call_user_func(array($this->model_to, 'query'));
-		reset($this->key_to);
-		foreach ($this->key_from as $key)
-		{
-			// no point running a query when a key value is null
-			if ($from->{$key} === null)
-			{
-				return array();
-			}
-			$query->where(current($this->key_to), $from->{$key});
-			next($this->key_to);
-		}
-
-		foreach (\Arr::get($this->conditions, 'where', array()) as $key => $condition)
-		{
-			is_array($condition) or $condition = array($key, '=', $condition);
-			$query->where($condition);
-		}
-
-		foreach (\Arr::get($this->conditions, 'order_by', array()) as $field => $direction)
-		{
-			if (is_numeric($field))
-			{
-				$query->order_by($direction);
-			}
-			else
-			{
-				$query->order_by($field, $direction);
-			}
-		}
-
-		return $query->get();
-	}
-
-	public function join($alias_from, $rel_name, $alias_to_nr, $conditions = array())
-	{
-		$alias_to = 't'.$alias_to_nr;
-		$model = array(
-			'model'        => $this->model_to,
-			'connection'   => call_user_func(array($this->model_to, 'connection')),
-			'table'        => array(call_user_func(array($this->model_to, 'table')), $alias_to),
-			'primary_key'  => call_user_func(array($this->model_to, 'primary_key')),
-			'join_type'    => \Arr::get($conditions, 'join_type') ?: \Arr::get($this->conditions, 'join_type', 'left'),
-			'join_on'      => array(),
-			'columns'      => $this->select($alias_to),
-			'rel_name'     => strpos($rel_name, '.') ? substr($rel_name, strrpos($rel_name, '.') + 1) : $rel_name,
-			'relation'     => $this,
-			'where'        => \Arr::get($conditions, 'where', array()),
-			'order_by'     => \Arr::get($conditions, 'order_by') ?: \Arr::get($this->conditions, 'order_by', array()),
-		);
-
-		reset($this->key_to);
-		foreach ($this->key_from as $key)
-		{
-			$model['join_on'][] = array($alias_from.'.'.$key, '=', $alias_to.'.'.current($this->key_to));
-			next($this->key_to);
-		}
-		foreach (\Arr::get($this->conditions, 'where', array()) as $key => $condition)
-		{
-			! is_array($condition) and $condition = array($key, '=', $condition);
-			if ( ! $condition[0] instanceof \Fuel\Core\Database_Expression and strpos($condition[0], '.') === false)
-			{
-				$condition[0] = $alias_to.'.'.$condition[0];
-			}
-			is_string($condition[2]) and $condition[2] = \Db::quote($condition[2], $model['connection']);
-
-			$model['join_on'][] = $condition;
-		}
-
-		return array($rel_name => $model);
-	}
-
-	public function save($model_from, $models_to, $original_model_ids, $parent_saved, $cascade)
-	{
-		if ( ! $parent_saved)
-		{
-			return;
-		}
-
-		if ( ! is_array($models_to) and ($models_to = is_null($models_to) ? array() : $models_to) !== array())
-		{
-			throw new \FuelException('Assigned relationships must be an array or null, given relationship value for '.
-				$this->name.' is invalid.');
-		}
-		$original_model_ids === null and $original_model_ids = array();
-
-		foreach ($models_to as $key => $model_to)
-		{
-			if ( ! $model_to instanceof $this->model_to)
-			{
-				throw new \FuelException('Invalid Model instance added to relations in this model.');
-			}
-
-			$current_model_id = ($model_to and ! $model_to->is_new()) ? $model_to->implode_pk($model_to) : null;
-
-			// Check if the model was already assigned
-			if (($model_to and $model_to->is_new()) or ! in_array($current_model_id, $original_model_ids))
-			{
-				// assign this object to the new objects foreign keys
-				reset($this->key_to);
-				$frozen = $model_to->frozen(); // only unfreeze/refreeze when it was frozen
-				$frozen and $model_to->unfreeze();
-				foreach ($this->key_from as $pk)
-				{
-					$model_to->{current($this->key_to)} = $model_from->{$pk};
-					next($this->key_to);
-				}
-				$model_to->is_new() and $model_to->save(false);
-				$frozen and $model_to->freeze();
-			}
-			// check if the model_to's foreign_keys match the model_from's primary keys
-			else
-			{
-				// unset current model from from array
-				unset($original_model_ids[array_search($current_model_id, $original_model_ids)]);
-
-				// check if model_to still refers to this model_from
-				$changed = false;
-				reset($this->key_to);
-				foreach ($this->key_from as $pk)
-				{
-					if ($model_to->{current($this->key_to)} != $model_from->{$pk})
-					{
-						$changed = true;
-					}
-					next($this->key_to);
-				}
-
-				// if any of the keys changed, the relationship was broken - remove model_to from loaded objects
-				if ($changed)
-				{
-					$model_from->unfreeze();
-					$rel = $model_from->_relate();
-					unset($rel[$this->name][$key]);
-					$model_from->_relate($rel);
-					$model_from->freeze();
-
-					// cascading this change won't work here, save just the object with cascading switched off
-					$model_from->save(false);
-				}
-			}
-
-			// Fix it if key isn't an imploded PK
-			if ($key != ($current_model_id = $model_to->implode_pk($model_to)))
-			{
-				$model_from->unfreeze();
-				$rel = $model_from->_relate();
-				if ( ! empty($rel[$this->name][$key]) and $rel[$this->name][$key] === $model_to)
-				{
-					unset($rel[$this->name][$key]);
-				}
-				$rel[$this->name][$current_model_id] = $model_to;
-				$model_from->_relate($rel);
-				$model_from->freeze();
-			}
-		}
-
-		// if any original ids are left over in the array, they're no longer related - break them
-		foreach ($original_model_ids as $original_model_id)
-		{
-			// if still loaded set this object's old relation's foreign keys to null
-			if ($original_model_id and $obj = call_user_func(array($this->model_to, 'find'),
-				count($this->key_to) == 1 ? array($original_model_id) : explode('][', substr($original_model_id, 1, -1))))
-			{
-				$frozen = $obj->frozen(); // only unfreeze/refreeze when it was frozen
-				$frozen and $obj->unfreeze();
-				foreach ($this->key_to as $fk)
-				{
-					$obj->{$fk} = null;
-				}
-				$frozen and $obj->freeze();
-
-				// cascading this change won't work here, save just the object with cascading switched off
-				$obj->save(false);
-			}
-		}
-
-		$cascade = is_null($cascade) ? $this->cascade_save : (bool) $cascade;
-		if ($cascade and ! empty($models_to))
-		{
-			foreach ($models_to as $m)
-			{
-				$m->save();
-			}
-		}
-	}
-
-	public function delete($model_from, $models_to, $parent_deleted, $cascade)
-	{
-		if ( ! $parent_deleted)
-		{
-			return;
-		}
-
-		// break current relations
-		$model_from->unfreeze();
-		$rels = $model_from->_relate();
-		$rels[$this->name] = array();
-		$model_from->_relate($rels);
-		$model_from->freeze();
-
-		foreach ($models_to as $model_to)
-		{
-			if ( ! $model_to->frozen())
-			{
-				foreach ($this->key_to as $fk)
-				{
-					$model_to->{$fk} = null;
-				}
-			}
-		}
-
-		if ( ! empty($models_to))
-		{
-			$cascade = is_null($cascade) ? $this->cascade_delete : (bool) $cascade;
-			foreach ($models_to as $m)
-			{
-				if ($cascade)
-				{
-					$m->delete();
-				}
-				else
-				{
-					$m->is_changed() and $m->save();
-				}
-			}
-		}
-	}
-}

+ 0 - 230
frameworks/PHP/php-fuel/fuel/packages/orm/classes/hasone.php

@@ -1,230 +0,0 @@
-<?php
-/**
- * Fuel is a fast, lightweight, community driven PHP5 framework.
- *
- * @package    Fuel
- * @version    1.5
- * @author     Fuel Development Team
- * @license    MIT License
- * @copyright  2010 - 2013 Fuel Development Team
- * @link       http://fuelphp.com
- */
-
-namespace Orm;
-
-class HasOne extends Relation
-{
-	protected $singular = true;
-
-	public function __construct($from, $name, array $config)
-	{
-		$this->name        = $name;
-		$this->model_from  = $from;
-		$this->model_to    = array_key_exists('model_to', $config)
-			? $config['model_to'] : \Inflector::get_namespace($from).'Model_'.\Inflector::classify($name);
-		$this->key_from    = array_key_exists('key_from', $config)
-			? (array) $config['key_from'] : $this->key_from;
-		$this->key_to      = array_key_exists('key_to', $config)
-			? (array) $config['key_to'] : (array) \Inflector::foreign_key($this->model_from);
-		$this->conditions  = array_key_exists('conditions', $config)
-			? (array) $config['conditions'] : array();
-
-		$this->cascade_save    = array_key_exists('cascade_save', $config)
-			? $config['cascade_save'] : $this->cascade_save;
-		$this->cascade_delete  = array_key_exists('cascade_delete', $config)
-			? $config['cascade_delete'] : $this->cascade_delete;
-
-		if ( ! class_exists($this->model_to))
-		{
-			throw new \FuelException('Related model not found by Has_One relation "'.$this->name.'": '.$this->model_to);
-		}
-		$this->model_to = get_real_class($this->model_to);
-	}
-
-	public function get(Model $from)
-	{
-		$query = call_user_func(array($this->model_to, 'query'));
-		reset($this->key_to);
-		foreach ($this->key_from as $key)
-		{
-			// no point running a query when a key value is null
-			if ($from->{$key} === null)
-			{
-				return null;
-			}
-			$query->where(current($this->key_to), $from->{$key});
-			next($this->key_to);
-		}
-
-		foreach (\Arr::get($this->conditions, 'where', array()) as $key => $condition)
-		{
-			is_array($condition) or $condition = array($key, '=', $condition);
-			$query->where($condition);
-		}
-
-		return $query->get_one();
-	}
-
-	public function join($alias_from, $rel_name, $alias_to_nr, $conditions = array())
-	{
-		$alias_to = 't'.$alias_to_nr;
-		$model = array(
-			'model'        => $this->model_to,
-			'connection'   => call_user_func(array($this->model_to, 'connection')),
-			'table'        => array(call_user_func(array($this->model_to, 'table')), $alias_to),
-			'primary_key'  => call_user_func(array($this->model_to, 'primary_key')),
-			'join_type'    => \Arr::get($conditions, 'join_type') ?: \Arr::get($this->conditions, 'join_type', 'left'),
-			'join_on'      => array(),
-			'columns'      => $this->select($alias_to),
-			'rel_name'     => strpos($rel_name, '.') ? substr($rel_name, strrpos($rel_name, '.') + 1) : $rel_name,
-			'relation'     => $this,
-			'where'        => \Arr::get($conditions, 'where', array()),
-			'order_by'     => \Arr::get($conditions, 'order_by') ?: \Arr::get($this->conditions, 'order_by', array()),
-		);
-
-		reset($this->key_to);
-		foreach ($this->key_from as $key)
-		{
-			$model['join_on'][] = array($alias_from.'.'.$key, '=', $alias_to.'.'.current($this->key_to));
-			next($this->key_to);
-		}
-		foreach (\Arr::get($this->conditions, 'where', array()) as $key => $condition)
-		{
-			! is_array($condition) and $condition = array($key, '=', $condition);
-			if ( ! $condition[0] instanceof \Fuel\Core\Database_Expression and strpos($condition[0], '.') === false)
-			{
-				$condition[0] = $alias_to.'.'.$condition[0];
-			}
-			is_string($condition[2]) and $condition[2] = \Db::quote($condition[2], $model['connection']);
-
-			$model['join_on'][] = $condition;
-		}
-
-		return array($rel_name => $model);
-	}
-
-	public function save($model_from, $model_to, $original_model_id, $parent_saved, $cascade)
-	{
-		if ( ! $parent_saved)
-		{
-			return;
-		}
-
-		if ( ! $model_to instanceof $this->model_to and $model_to !== null)
-		{
-			throw new \FuelException('Invalid Model instance added to relations in this model.');
-		}
-
-		$current_model_id = ($model_to and ! $model_to->is_new()) ? $model_to->implode_pk($model_to) : null;
-		// Check if there was another model assigned (this supersedes any change to the foreign key(s))
-		if (($model_to and $model_to->is_new()) or $current_model_id != $original_model_id)
-		{
-			// assign this object to the new objects foreign keys
-			if ( ! empty($model_to))
-			{
-				reset($this->key_to);
-				$frozen = $model_to->frozen(); // only unfreeze/refreeze when it was frozen
-				$frozen and $model_to->unfreeze();
-				foreach ($this->key_from as $pk)
-				{
-					$model_to->{current($this->key_to)} = $model_from->{$pk};
-					next($this->key_to);
-				}
-				$frozen and $model_to->freeze();
-			}
-
-			// if still loaded set this object's old relation's foreign keys to null
-			if ($original_model_id and $obj = call_user_func(array($this->model_to, 'find'),
-				count($this->key_to) == 1 ? array($original_model_id) : explode('][', substr($original_model_id, 1, -1))))
-			{
-				// check whether the object still refers to this model_from
-				$changed = false;
-				reset($this->key_to);
-				foreach ($this->key_from as $pk)
-				{
-					if ($obj->{current($this->key_to)} != $model_from->{$pk})
-					{
-						$changed = true;
-					}
-					next($this->key_to);
-				}
-
-				// when it still refers to this object, reset the foreign key(s)
-				if ( ! $changed)
-				{
-					$frozen = $obj->frozen(); // only unfreeze/refreeze when it was frozen
-					$frozen and $obj->unfreeze();
-					foreach ($this->key_to as $fk)
-					{
-						$obj->{$fk} = null;
-					}
-					$frozen and $obj->freeze();
-
-					// cascading this change won't work here, save just the object with cascading switched off
-					$obj->save(false);
-				}
-			}
-		}
-		// if not empty check the model_to's foreign_keys, when empty nothing changed
-		elseif ( ! empty($model_to))
-		{
-			// check if model_to still refers to this model_from
-			$changed = false;
-			reset($this->key_to);
-			foreach ($this->key_from as $pk)
-			{
-				if ($model_to->{current($this->key_to)} != $model_from->{$pk})
-				{
-					$changed = true;
-				}
-				next($this->key_to);
-			}
-
-			// if any of the keys changed, the relationship was broken - remove model_to from loaded objects
-			if ($changed)
-			{
-				// Remove the model_to from the relationships of model_from
-				$model_from->unfreeze();
-				$rel = $model_from->_relate();
-				$rel[$this->name] = null;
-				$model_from->_relate($rel);
-				$model_from->freeze();
-			}
-		}
-
-		$cascade = is_null($cascade) ? $this->cascade_save : (bool) $cascade;
-		if ($cascade and ! empty($model_to))
-		{
-			$model_to->save();
-		}
-	}
-
-	public function delete($model_from, $model_to, $parent_deleted, $cascade)
-	{
-		if ( ! $parent_deleted)
-		{
-			return;
-		}
-
-		// break current relations
-		$model_from->unfreeze();
-		$rels = $model_from->_relate();
-		$rels[$this->name] = null;
-		$model_from->_relate($rels);
-		$model_from->freeze();
-
-		if ($model_to and ! $model_to->frozen())
-		{
-			foreach ($this->key_to as $fk)
-			{
-				$model_to->{$fk} = null;
-			}
-		}
-
-		$cascade = is_null($cascade) ? $this->cascade_delete : (bool) $cascade;
-		if ($cascade and ! empty($model_to))
-		{
-			$model_to->delete();
-		}
-	}
-}

+ 0 - 353
frameworks/PHP/php-fuel/fuel/packages/orm/classes/manymany.php

@@ -1,353 +0,0 @@
-<?php
-/**
- * Fuel is a fast, lightweight, community driven PHP5 framework.
- *
- * @package    Fuel
- * @version    1.5
- * @author     Fuel Development Team
- * @license    MIT License
- * @copyright  2010 - 2013 Fuel Development Team
- * @link       http://fuelphp.com
- */
-
-namespace Orm;
-
-class ManyMany extends Relation
-{
-	protected $key_from = array('id');
-
-	protected $key_to = array('id');
-
-	/**
-	 * @var  string  classname of model to use as connection
-	 */
-	protected $model_through;
-
-	/**
-	 * @var  string  table name of table to use as connection, alternative to $model_through setting
-	 */
-	protected $table_through;
-
-	/**
-	 * @var  string  foreign key of from model in connection table
-	 */
-	protected $key_through_from;
-
-	/**
-	 * @var  string  foreign key of to model in connection table
-	 */
-	protected $key_through_to;
-
-	public function __construct($from, $name, array $config)
-	{
-		$this->name        = $name;
-		$this->model_from  = $from;
-		$this->model_to    = array_key_exists('model_to', $config)
-			? $config['model_to'] : \Inflector::get_namespace($from).'Model_'.\Inflector::classify($name);
-		$this->key_from    = array_key_exists('key_from', $config)
-			? (array) $config['key_from'] : $this->key_from;
-		$this->key_to      = array_key_exists('key_to', $config)
-			? (array) $config['key_to'] : $this->key_to;
-		$this->conditions  = array_key_exists('conditions', $config)
-			? (array) $config['conditions'] : array();
-
-		if ( ! empty($config['table_through']))
-		{
-			$this->table_through = $config['table_through'];
-		}
-		else
-		{
-			$table_name = array($this->model_from, $this->model_to);
-			natcasesort($table_name);
-			$table_name = array_merge($table_name);
-			$this->table_through = \Inflector::tableize($table_name[0]).'_'.\Inflector::tableize($table_name[1]);
-		}
-		$this->key_through_from = ! empty($config['key_through_from'])
-			? (array) $config['key_through_from'] : (array) \Inflector::foreign_key($this->model_from);
-		$this->key_through_to = ! empty($config['key_through_to'])
-			? (array) $config['key_through_to'] : (array) \Inflector::foreign_key($this->model_to);
-
-		$this->cascade_save    = array_key_exists('cascade_save', $config)
-			? $config['cascade_save'] : $this->cascade_save;
-		$this->cascade_delete  = array_key_exists('cascade_delete', $config)
-			? $config['cascade_delete'] : $this->cascade_delete;
-
-		if ( ! class_exists($this->model_to))
-		{
-			throw new \FuelException('Related model not found by Many_Many relation "'.$this->name.'": '.$this->model_to);
-		}
-		$this->model_to = get_real_class($this->model_to);
-	}
-
-	public function get(Model $from)
-	{
-		// Create the query on the model_through
-		$query = call_user_func(array($this->model_to, 'query'));
-
-		// set the model_from's keys as where conditions for the model_through
-		$join = array(
-				'table'      => array($this->table_through, 't0_through'),
-				'join_type'  => null,
-				'join_on'    => array(),
-				'columns'    => $this->select_through('t0_through')
-		);
-
-		reset($this->key_from);
-		foreach ($this->key_through_from as $key)
-		{
-			if ($from->{current($this->key_from)} === null)
-			{
-				return array();
-			}
-			$query->where('t0_through.'.$key, $from->{current($this->key_from)});
-			next($this->key_from);
-		}
-
-		reset($this->key_to);
-		foreach ($this->key_through_to as $key)
-		{
-			$join['join_on'][] = array('t0_through.'.$key, '=', 't0.'.current($this->key_to));
-			next($this->key_to);
-		}
-
-		foreach (\Arr::get($this->conditions, 'where', array()) as $key => $condition)
-		{
-			is_array($condition) or $condition = array($key, '=', $condition);
-			$query->where($condition);
-		}
-
-		foreach (\Arr::get($this->conditions, 'order_by', array()) as $field => $direction)
-		{
-			if (is_numeric($field))
-			{
-				$query->order_by($direction);
-			}
-			else
-			{
-				$query->order_by($field, $direction);
-			}
-		}
-
-		$query->_join($join);
-
-		return $query->get();
-	}
-
-	public function select_through($table)
-	{
-		foreach ($this->key_through_to as $to)
-		{
-			$properties[] = $table.'.'.$to;
-		}
-		foreach ($this->key_through_from as $from)
-		{
-			$properties[] = $table.'.'.$from;
-		}
-
-		return $properties;
-	}
-
-	public function join($alias_from, $rel_name, $alias_to_nr, $conditions = array())
-	{
-		$alias_to = 't'.$alias_to_nr;
-
-		$models = array(
-			$rel_name.'_through' => array(
-				'model'        => null,
-				'connection'   => call_user_func(array($this->model_to, 'connection')),
-				'table'        => array($this->table_through, $alias_to.'_through'),
-				'primary_key'  => null,
-				'join_type'    => \Arr::get($conditions, 'join_type') ?: \Arr::get($this->conditions, 'join_type', 'left'),
-				'join_on'      => array(),
-				'columns'      => $this->select_through($alias_to.'_through'),
-				'rel_name'     => $this->model_through,
-				'relation'     => $this
-			),
-			$rel_name => array(
-				'model'        => $this->model_to,
-				'connection'   => call_user_func(array($this->model_to, 'connection')),
-				'table'        => array(call_user_func(array($this->model_to, 'table')), $alias_to),
-				'primary_key'  => call_user_func(array($this->model_to, 'primary_key')),
-				'join_type'    => \Arr::get($conditions, 'join_type') ?: \Arr::get($this->conditions, 'join_type', 'left'),
-				'join_on'      => array(),
-				'columns'      => $this->select($alias_to),
-				'rel_name'     => strpos($rel_name, '.') ? substr($rel_name, strrpos($rel_name, '.') + 1) : $rel_name,
-				'relation'     => $this,
-				'where'        => \Arr::get($conditions, 'where', array()),
-				'order_by'     => \Arr::get($conditions, 'order_by') ?: \Arr::get($this->conditions, 'order_by', array()),
-			)
-		);
-
-		reset($this->key_from);
-		foreach ($this->key_through_from as $key)
-		{
-			$models[$rel_name.'_through']['join_on'][] = array($alias_from.'.'.current($this->key_from), '=', $alias_to.'_through.'.$key);
-			next($this->key_from);
-		}
-
-		reset($this->key_to);
-		foreach ($this->key_through_to as $key)
-		{
-			$models[$rel_name]['join_on'][] = array($alias_to.'_through.'.$key, '=', $alias_to.'.'.current($this->key_to));
-			next($this->key_to);
-		}
-		foreach (\Arr::get($this->conditions, 'where', array()) as $key => $condition)
-		{
-			! is_array($condition) and $condition = array($key, '=', $condition);
-			if ( ! $condition[0] instanceof \Fuel\Core\Database_Expression and strpos($condition[0], '.') === false)
-			{
-				$condition[0] = $alias_to.'.'.$condition[0];
-			}
-			is_string($condition[2]) and $condition[2] = \Db::quote($condition[2], $models[$rel_name]['connection']);
-
-			$models[$rel_name]['join_on'][] = $condition;
-		}
-
-		return $models;
-	}
-
-	public function save($model_from, $models_to, $original_model_ids, $parent_saved, $cascade)
-	{
-		if ( ! $parent_saved)
-		{
-			return;
-		}
-
-		if ( ! is_array($models_to) and ($models_to = is_null($models_to) ? array() : $models_to) !== array())
-		{
-			throw new \FuelException('Assigned relationships must be an array or null, given relationship value for '.
-				$this->name.' is invalid.');
-		}
-		$original_model_ids === null and $original_model_ids = array();
-		$del_rels = $original_model_ids;
-
-		foreach ($models_to as $key => $model_to)
-		{
-			if ( ! $model_to instanceof $this->model_to)
-			{
-				throw new \FuelException('Invalid Model instance added to relations in this model.');
-			}
-
-			// Save if it's a yet unsaved object
-			if ($model_to->is_new())
-			{
-				$model_to->save(false);
-			}
-
-			$current_model_id = $model_to ? $model_to->implode_pk($model_to) : null;
-
-			// Check if the model was already assigned, if not INSERT relationships:
-			if ( ! in_array($current_model_id, $original_model_ids))
-			{
-				$ids = array();
-				reset($this->key_from);
-				foreach ($this->key_through_from as $pk)
-				{
-					$ids[$pk] = $model_from->{current($this->key_from)};
-					next($this->key_from);
-				}
-
-				reset($this->key_to);
-				foreach ($this->key_through_to as $pk)
-				{
-					$ids[$pk] = $model_to->{current($this->key_to)};
-					next($this->key_to);
-				}
-
-				\DB::insert($this->table_through)->set($ids)->execute(call_user_func(array($model_from, 'connection')));
-				$original_model_ids[] = $current_model_id; // prevents inserting it a second time
-			}
-			else
-			{
-				// unset current model from from array of new relations
-				unset($del_rels[array_search($current_model_id, $original_model_ids)]);
-			}
-
-			// ensure correct pk assignment
-			if ($key != $current_model_id)
-			{
-				$model_from->unfreeze();
-				$rel = $model_from->_relate();
-				if ( ! empty($rel[$this->name][$key]) and $rel[$this->name][$key] === $model_to)
-				{
-					unset($rel[$this->name][$key]);
-				}
-				$rel[$this->name][$current_model_id] = $model_to;
-				$model_from->_relate($rel);
-				$model_from->freeze();
-			}
-		}
-
-		// If any ids are left in $del_rels they are no longer assigned, DELETE the relationships:
-		foreach ($del_rels as $original_model_id)
-		{
-			$query = \DB::delete($this->table_through);
-
-			reset($this->key_from);
-			foreach ($this->key_through_from as $key)
-			{
-				$query->where($key, '=', $model_from->{current($this->key_from)});
-				next($this->key_from);
-			}
-
-			$to_keys = count($this->key_to) == 1 ? array($original_model_id) : explode('][', substr($original_model_id, 1, -1));
-			reset($to_keys);
-			foreach ($this->key_through_to as $key)
-			{
-				$query->where($key, '=', current($to_keys));
-				next($to_keys);
-			}
-
-			$query->execute(call_user_func(array($model_from, 'connection')));
-		}
-
-		$cascade = is_null($cascade) ? $this->cascade_save : (bool) $cascade;
-		if ($cascade and ! empty($models_to))
-		{
-			foreach ($models_to as $m)
-			{
-				$m->save();
-			}
-		}
-	}
-
-	public function delete($model_from, $models_to, $parent_deleted, $cascade)
-	{
-		if ( ! $parent_deleted)
-		{
-			return;
-		}
-
-		// Remove relations
-		$model_from->unfreeze();
-		$rels = $model_from->_relate();
-		$rels[$this->name] = array();
-		$model_from->_relate($rels);
-		$model_from->freeze();
-
-		// Delete all relationship entries for the model_from
-		$this->delete_related($model_from);
-
-		$cascade = is_null($cascade) ? $this->cascade_delete : (bool) $cascade;
-		if ($cascade and ! empty($model_to))
-		{
-			foreach ($models_to as $m)
-			{
-				$m->delete();
-			}
-		}
-	}
-
-	public function delete_related($model_from)
-	{
-		// Delete all relationship entries for the model_from
-		$query = \DB::delete($this->table_through);
-		reset($this->key_from);
-		foreach ($this->key_through_from as $key)
-		{
-			$query->where($key, '=', $model_from->{current($this->key_from)});
-			next($this->key_from);
-		}
-		$query->execute(call_user_func(array($model_from, 'connection')));
-	}
-}

+ 0 - 1909
frameworks/PHP/php-fuel/fuel/packages/orm/classes/model.php

@@ -1,1909 +0,0 @@
-<?php
-/**
- * Fuel is a fast, lightweight, community driven PHP5 framework.
- *
- * @package    Fuel
- * @version    1.5
- * @author     Fuel Development Team
- * @license    MIT License
- * @copyright  2010 - 2013 Fuel Development Team
- * @link       http://fuelphp.com
- */
-
-namespace Orm;
-
-/**
- * Record Not Found Exception
- */
-class RecordNotFound extends \OutOfBoundsException {}
-
-/**
- * Frozen Object Exception
- */
-class FrozenObject extends \RuntimeException {}
-
-class Model implements \ArrayAccess, \Iterator
-{
-	/* ---------------------------------------------------------------------------
-	 * Static usage
-	 * --------------------------------------------------------------------------- */
-
-	/**
-	 * @var  string  connection to use
-	 */
-	// protected static $_connection = null;
-
-	/**
-	 * @var  string  write connection to use
-	 */
-	// protected static $_write_connection = null;
-
-	/**
-	 * @var  string  table name to overwrite assumption
-	 */
-	// protected static $_table_name;
-
-	/**
-	 * @var  array  array of object properties
-	 */
-	// protected static $_properties;
-
-	/**
-	 * @var  array  array of views with additional properties
-	 */
-	// protected static $_views;
-
-	/**
-	 * @var  array  array of observer classes to use
-	 */
-	// protected static $_observers;
-
-	/**
-	 * @var  array  relationship properties
-	 */
-	// protected static $_has_one;
-	// protected static $_belongs_to;
-	// protected static $_has_many;
-	// protected static $_many_many;
-	// protected static $_eav;
-
-	/**
-	 * @var  array  name or names of the primary keys
-	 */
-	protected static $_primary_key = array('id');
-
-	/**
-	 * @var  array  name or columns that need to be excluded from any to_array() result
-	 */
-	protected static $_to_array_exclude = array();
-
-	/**
-	 * @var  array  cached tables
-	 */
-	protected static $_table_names_cached = array();
-
-	/**
-	 * @var  array  cached properties
-	 */
-	protected static $_properties_cached = array();
-
-	/**
-	 * @var  array  cached properties
-	 */
-	protected static $_views_cached = array();
-
-	/**
-	 * @var  string  relationships
-	 */
-	protected static $_relations_cached = array();
-
-	/**
-	 * @var  array  cached observers
-	 */
-	protected static $_observers_cached = array();
-
-	/**
-	 * @var  array  array of fetched objects
-	 */
-	protected static $_cached_objects = array();
-
-	/**
-	 * @var  array  array of valid relation types
-	 */
-	protected static $_valid_relations = array(
-		'belongs_to'    => 'Orm\\BelongsTo',
-		'has_one'       => 'Orm\\HasOne',
-		'has_many'      => 'Orm\\HasMany',
-		'many_many'     => 'Orm\\ManyMany',
-	);
-
-	public static function forge($data = array(), $new = true, $view = null)
-	{
-		return new static($data, $new, $view);
-	}
-
-	/**
-	 * Fetch the database connection name to use
-	 *
-	 * @param	bool	if true return the writeable connection (if set)
-	 * @return  null|string
-	 */
-	public static function connection($writeable = false)
-	{
-		$class = get_called_class();
-
-		if ($writeable and property_exists($class, '_write_connection'))
-		{
-			return static::$_write_connection;
-		}
-
-		return property_exists($class, '_connection') ? static::$_connection : null;
-	}
-
-	/**
-	 * Get the table name for this class
-	 *
-	 * @return  string
-	 */
-	public static function table()
-	{
-		$class = get_called_class();
-
-		// Table name unknown
-		if ( ! array_key_exists($class, static::$_table_names_cached))
-		{
-			// Table name set in Model
-			if (property_exists($class, '_table_name'))
-			{
-				static::$_table_names_cached[$class] = static::$_table_name;
-			}
-			else
-			{
-				static::$_table_names_cached[$class] = \Inflector::tableize($class);
-			}
-		}
-
-		return static::$_table_names_cached[$class];
-	}
-
-	/**
-	 * Get a defined condition for this class
-	 *
-	 * @param	string	type of condition to return
-	 * @return  array
-	 */
-	public static function condition($type = null)
-	{
-		$class = get_called_class();
-
-		// a specific condition requested?
-		if (property_exists($class, '_conditions'))
-		{
-			if ($type !== null)
-			{
-				return isset(static::$_conditions[$type]) ? static::$_conditions[$type] : array();
-			}
-			else
-			{
-				return static::$_conditions;
-			}
-		}
-		else
-		{
-			return array();
-		}
-	}
-
-	/**
-	 * Attempt to retrieve an earlier loaded object
-	 *
-	 * @param   array|Model  $obj
-	 * @param   null|string  $class
-	 * @return  Model|false
-	 */
-	public static function cached_object($obj, $class = null)
-	{
-		$class = $class ?: get_called_class();
-		$id    = (is_int($obj) or is_string($obj)) ? (string) $obj : $class::implode_pk($obj);
-
-		$result = ( ! empty(static::$_cached_objects[$class][$id])) ? static::$_cached_objects[$class][$id] : false;
-
-		return $result;
-	}
-
-	/**
-	 * Get the primary key(s) of this class
-	 *
-	 * @return  array
-	 */
-	public static function primary_key()
-	{
-		return static::$_primary_key;
-	}
-
-	/**
-	 * Implode the primary keys within the data into a string
-	 *
-	 * @param   array
-	 * @return  string
-	 */
-	public static function implode_pk($data)
-	{
-		if (count(static::$_primary_key) == 1)
-		{
-			$p = reset(static::$_primary_key);
-			return (is_object($data)
-				? strval($data->{$p})
-				: (isset($data[$p])
-					? strval($data[$p])
-					: null));
-		}
-
-		$pk = '';
-		foreach (static::$_primary_key as $p)
-		{
-			if (is_null((is_object($data) ? $data->{$p} : (isset($data[$p]) ? $data[$p] : null))))
-			{
-				return null;
-			}
-			$pk .= '['.(is_object($data) ? $data->{$p} : $data[$p]).']';
-		}
-
-		return $pk;
-	}
-
-	/**
-	 * Get the class's properties
-	 *
-	 * @return  array
-	 */
-	public static function properties()
-	{
-		$class = get_called_class();
-
-		// If already determined
-		if (array_key_exists($class, static::$_properties_cached))
-		{
-			return static::$_properties_cached[$class];
-		}
-
-		// Try to grab the properties from the class...
-		if (property_exists($class, '_properties'))
-		{
-			$properties = static::$_properties;
-			foreach ($properties as $key => $p)
-			{
-				if (is_string($p))
-				{
-					unset($properties[$key]);
-					$properties[$p] = array();
-				}
-			}
-		}
-
-		// ...if the above failed, run DB query to fetch properties
-		if (empty($properties))
-		{
-			try
-			{
-				$properties = \DB::list_columns(static::table(), null, static::connection());
-			}
-			catch (\Exception $e)
-			{
-				throw new \FuelException('Listing columns failed, you have to set the model properties with a '.
-					'static $_properties setting in the model. Original exception: '.$e->getMessage());
-			}
-		}
-
-		// cache the properties for next usage
-		static::$_properties_cached[$class] = $properties;
-
-		return static::$_properties_cached[$class];
-	}
-
-	/**
-	 * Fetches a property description array, or specific data from it
-	 *
-	 * @param   string  property or property.key
-	 * @param   mixed   return value when key not present
-	 * @return  mixed
-	 */
-	public static function property($key, $default = null)
-	{
-		$class = get_called_class();
-
-		// If already determined
-		if ( ! array_key_exists($class, static::$_properties_cached))
-		{
-			static::properties();
-		}
-
-		return \Arr::get(static::$_properties_cached[$class], $key, $default);
-	}
-
-	/**
-	 * Fetch the model's views
-	 *
-	 * @return  array
-	 */
-	public static function views()
-	{
-		$class = get_called_class();
-
-		if ( ! isset(static::$_views_cached[$class]))
-		{
-			static::$_views_cached[$class] = array();
-			if (property_exists($class, '_views'))
-			{
-				$views = $class::$_views;
-				foreach ($views as $k => $v)
-				{
-					if ( ! isset($v['columns']))
-					{
-						throw new \InvalidArgumentException('Database view '.$k.' is defined without columns.');
-					}
-					$v['columns'] = (array) $v['columns'];
-					if ( ! isset($v['view']))
-					{
-						$v['view'] = $k;
-					}
-					static::$_views_cached[$class][$k] = $v;
-				}
-			}
-		}
-
-		return static::$_views_cached[$class];
-	}
-
-	/**
-	 * Get the class's relations
-	 *
-	 * @param   string
-	 * @return  array
-	 */
-	public static function relations($specific = false)
-	{
-		$class = get_called_class();
-
-		if ( ! array_key_exists($class, static::$_relations_cached))
-		{
-			$relations = array();
-			foreach (static::$_valid_relations as $rel_name => $rel_class)
-			{
-				if (property_exists($class, '_'.$rel_name))
-				{
-					foreach (static::${'_'.$rel_name} as $key => $settings)
-					{
-						$name = is_string($settings) ? $settings : $key;
-						$settings = is_array($settings) ? $settings : array();
-						$relations[$name] = new $rel_class($class, $name, $settings);
-					}
-				}
-			}
-
-			static::$_relations_cached[$class] = $relations;
-		}
-
-		if ($specific === false)
-		{
-			return static::$_relations_cached[$class];
-		}
-		else
-		{
-			if ( ! array_key_exists($specific, static::$_relations_cached[$class]))
-			{
-				return false;
-			}
-
-			return static::$_relations_cached[$class][$specific];
-		}
-	}
-
-	/**
-	 * Get the class's observers and what they observe
-	 *
-	 * @param   string  specific observer to retrieve info of, allows direct param access by using dot notation
-	 * @param   mixed   default return value when specific key wasn't found
-	 * @return  array
-	 */
-	public static function observers($specific = null, $default = null)
-	{
-		$class = get_called_class();
-
-		if ( ! array_key_exists($class, static::$_observers_cached))
-		{
-			$observers = array();
-			if (property_exists($class, '_observers'))
-			{
-				foreach (static::$_observers as $obs_k => $obs_v)
-				{
-					if (is_int($obs_k))
-					{
-						$observers[$obs_v] = array();
-					}
-					else
-					{
-						if (is_string($obs_v) or (is_array($obs_v) and is_int(key($obs_v))))
-						{
-							// @TODO deprecated until v1.4
-							logger(\Fuel::L_WARNING, 'Passing observer events as array is deprecated, they must be
-								inside another array under a key "events". Check the docs for more info.', __METHOD__);
-							$observers[$obs_k] = array('events' => (array) $obs_v);
-						}
-						else
-						{
-							$observers[$obs_k] = $obs_v;
-						}
-					}
-				}
-			}
-			static::$_observers_cached[$class] = $observers;
-		}
-
-		if ($specific)
-		{
-			return \Arr::get(static::$_observers_cached[$class], $specific, $default);
-		}
-
-		return static::$_observers_cached[$class];
-	}
-
-	/**
-	 * Register an observer
-	 *
-	 * @param	string	class name of the observer (including namespace)
-	 * @param	mixed	observer options
-	 *
-	 * @return	void
-	 */
-	public static function register_observer($name, $options = null)
-	{
-		$class = get_called_class();
-		$new_observer = is_null($options) ? array($name) : array($name => $options);
-
-		static::$_observers_cached[$class] = static::observers() + $new_observer;
-	}
-
-	/**
-	 * Unregister an observer
-	 *
-	 * @param string class name of the observer (including namespace)
-	 * @return void
-	 */
-	public static function unregister_observer($name)
-	{
-		$class = get_called_class();
-		foreach (static::observers() as $key => $value)
-		{
-			if ((is_array($value) and $key == $name) or $value == $name)
-			{
-				unset(static::$_observers_cached[$class][$key]);
-			}
-		}
-	}
-
-	/**
-	 * Find one or more entries
-	 *
-	 * @param   mixed
-	 * @param   array
-	 * @return  object|array
-	 */
-	public static function find($id = null, array $options = array())
-	{
-		// Return Query object
-		if (is_null($id))
-		{
-			if (func_num_args() === 1)
-			{
-				throw new \FuelException('Invalid method call.  You need to specify a key value.', 0);
-			}
-			return static::query($options);
-		}
-		// Return all that match $options array
-		elseif ($id === 'all')
-		{
-			return static::query($options)->get();
-		}
-		// Return first or last row that matches $options array
-		elseif ($id === 'first' or $id === 'last')
-		{
-			$query = static::query($options);
-
-			foreach(static::primary_key() as $pk)
-			{
-				$query->order_by($pk, $id == 'first' ? 'ASC' : 'DESC');
-			}
-
-			return $query->get_one();
-		}
-		// Return specific request row by ID
-		else
-		{
-			$cache_pk = $where = array();
-			$id = (array) $id;
-			foreach (static::primary_key() as $pk)
-			{
-				$where[] = array($pk, '=', current($id));
-				$cache_pk[$pk] = current($id);
-				next($id);
-			}
-
-			if (array_key_exists(get_called_class(), static::$_cached_objects)
-			    and array_key_exists(static::implode_pk($cache_pk), static::$_cached_objects[get_called_class()]))
-			{
-				return static::$_cached_objects[get_called_class()][static::implode_pk($cache_pk)];
-			}
-
-			array_key_exists('where', $options) and $where = array_merge($options['where'], $where);
-			$options['where'] = $where;
-			return static::query($options)->get_one();
-		}
-	}
-
-	/**
-	 * Creates a new query with optional settings up front
-	 *
-	 * @param   array
-	 * @return  Query
-	 */
-	public static function query($options = array())
-	{
-		return Query::forge(get_called_class(), array(static::connection(), static::connection(true)), $options);
-	}
-
-	/**
-	 * Count entries, optionally only those matching the $options
-	 *
-	 * @param   array
-	 * @return  int
-	 */
-	public static function count(array $options = array())
-	{
-		return Query::forge(get_called_class(), array(static::connection(), static::connection(true)), $options)->count();
-	}
-
-	/**
-	 * Find the maximum
-	 *
-	 * @param   mixed
-	 * @param   array
-	 * @return  object|array
-	 */
-	public static function max($key = null)
-	{
-		return Query::forge(get_called_class(), array(static::connection(), static::connection(true)))->max($key ?: static::primary_key());
-	}
-
-	/**
-	 * Find the minimum
-	 *
-	 * @param   mixed
-	 * @param   array
-	 * @return  object|array
-	 */
-	public static function min($key = null)
-	{
-		return Query::forge(get_called_class(), array(static::connection(), static::connection(true)))->min($key ?: static::primary_key());
-	}
-
-	public static function __callStatic($method, $args)
-	{
-		// Start with count_by? Get counting!
-		if (strpos($method, 'count_by') === 0)
-		{
-			$find_type = 'count';
-			$fields = substr($method, 9);
-		}
-
-		// Otherwise, lets find stuff
-		elseif (strpos($method, 'find_') === 0)
-		{
-			$find_type = strncmp($method, 'find_all_by_', 12) === 0 ? 'all' : (strncmp($method, 'find_by_', 8) === 0 ? 'first' : false);
-			$fields = $find_type === 'first' ? substr($method, 8) : substr($method, 12);
-		}
-
-		// God knows, complain
-		else
-		{
-			throw new \FuelException('Invalid method call.  Method '.$method.' does not exist.', 0);
-		}
-
-		$where = $or_where = array();
-
-		if (($and_parts = explode('_and_', $fields)))
-		{
-			foreach ($and_parts as $and_part)
-			{
-				$or_parts = explode('_or_', $and_part);
-
-				if (count($or_parts) == 1)
-				{
-					$where[] = array($or_parts[0] => array_shift($args));
-				}
-				else
-				{
-					foreach($or_parts as $or_part)
-					{
-						$or_where[] = array($or_part => array_shift($args));
-					}
-				}
-			}
-		}
-
-		$options = count($args) > 0 ? array_pop($args) : array();
-
-		if ( ! array_key_exists('where', $options))
-		{
-			$options['where'] = $where;
-		}
-		else
-		{
-			$options['where'] = array_merge($where, $options['where']);
-		}
-
-		if ( ! array_key_exists('or_where', $options))
-		{
-			$options['or_where'] = $or_where;
-		}
-		else
-		{
-			$options['or_where'] = array_merge($or_where, $options['or_where']);
-		}
-
-		if ($find_type == 'count')
-		{
-			return static::count($options);
-		}
-
-		else
-		{
-			return static::find($find_type, $options);
-		}
-
-		// min_...($options)
-		// max_...($options)
-	}
-
-	/* ---------------------------------------------------------------------------
-	 * Object usage
-	 * --------------------------------------------------------------------------- */
-
-	/**
-	 * @var  bool  keeps track of whether it's a new object
-	 */
-	protected $_is_new = true;
-
-	/**
-	 * @var  bool  keeps to object frozen
-	 */
-	protected $_frozen = false;
-
-	/**
-	 * @var  array  keeps the current state of the object
-	 */
-	protected $_data = array();
-
-	/**
-	 * @var  array  storage for custom properties on this object
-	 */
-	protected $_custom_data = array();
-
-	/**
-	 * @var  array  keeps a copy of the object as it was retrieved from the database
-	 */
-	protected $_original = array();
-
-	/**
-	 * @var  array
-	 */
-	protected $_data_relations = array();
-
-	/**
-	 * @var  array  keeps a copy of the relation ids that were originally retrieved from the database
-	 */
-	protected $_original_relations = array();
-
-	/**
-	 * @var  array  keeps track of relations that need to be reset before saving the new ones
-	 */
-	protected $_reset_relations = array();
-
-	/**
-	 * @var  string  view name when used
-	 */
-	protected $_view;
-
-	/**
-	 * Constructor
-	 *
-	 * @param  array
-	 * @param  bool
-	 */
-	public function __construct(array $data = array(), $new = true, $view = null)
-	{
-		// This is to deal with PHP's native hydration from that happens before constructor is called
-		// for example using the DB's as_object() function
-		if( ! empty($this->_data))
-		{
-			$this->_original = $this->_data;
-			$new = false;
-		}
-
-		if ($new)
-		{
-			$properties = $this->properties();
-			foreach ($properties as $prop => $settings)
-			{
-				if (array_key_exists($prop, $data))
-				{
-					$this->_data[$prop] = $data[$prop];
-				}
-				elseif (array_key_exists('default', $settings))
-				{
-					$this->_data[$prop] = $settings['default'];
-				}
-			}
-		}
-		else
-		{
-			$this->_update_original($data);
-			$this->_data = array_merge($this->_data, $data);
-
-			if ($view and array_key_exists($view, $this->views()))
-			{
-				$this->_view = $view;
-			}
-		}
-
-		if ($new === false)
-		{
-			static::$_cached_objects[get_class($this)][static::implode_pk($data)] = $this;
-			$this->_is_new = false;
-			$this->observe('after_load');
-		}
-		else
-		{
-			$this->observe('after_create');
-		}
-	}
-
-	/**
-	 * Update the original setting for this object
-	 *
-	 * @param  array|null  $original
-	 */
-	public function _update_original($original = null)
-	{
-		$original = is_null($original) ? $this->_data : $original;
-		$this->_original = array_merge($this->_original, $original);
-
-		$this->_update_original_relations();
-	}
-
-	/**
-	 * Update the original relations for this object
-	 */
-	public function _update_original_relations($relations = null)
-	{
-		if (is_null($relations))
-		{
-			$this->_original_relations = array();
-			$relations = $this->_data_relations;
-		}
-		else
-		{
-			foreach ($relations as $key => $rel)
-			{
-				// Unload the just fetched relation from the originals
-				unset($this->_original_relations[$rel]);
-
-				// Unset the numeric key and set the data to update by the relation name
-				unset($relations[$key]);
-				$relations[$rel] = $this->_data_relations[$rel];
-			}
-		}
-
-		foreach ($relations as $rel => $data)
-		{
-			if (is_array($data))
-			{
-				$this->_original_relations[$rel] = array();
-				foreach ($data as $obj)
-				{
-					$this->_original_relations[$rel][] = $obj ? $obj->implode_pk($obj) : null;
-				}
-			}
-			else
-			{
-				$this->_original_relations[$rel] = $data ? $data->implode_pk($data) : null;
-			}
-		}
-	}
-
-	/**
-	 * Fetch or set relations on this object
-	 * To be used only after having fetched them from the database!
-	 *
-	 * @param   array|null  $rels
-	 * @return  void|array
-	 */
-	public function _relate($rels = false)
-	{
-		if ($this->_frozen)
-		{
-			throw new FrozenObject('No changes allowed.');
-		}
-
-		if ($rels === false)
-		{
-			return $this->_data_relations;
-		}
-		elseif (is_array($rels))
-		{
-			$this->_data_relations = $rels;
-		}
-		else
-		{
-			throw new \FuelException('Invalid input for _relate(), should be an array.');
-		}
-	}
-
-	/**
-	 * Fetch a property or relation
-	 *
-	 * @param   string
-	 * @return  mixed
-	 */
-	public function & __get($property)
-	{
-		return $this->get($property);
-	}
-
-	/**
-	 * Set a property or relation
-	 *
-	 * @param  string
-	 * @param  mixed
-	 */
-	public function __set($property, $value)
-	{
-		return $this->set($property, $value);
-	}
-
-	/**
-	 * Check whether a property exists, only return true for table columns, relations and custom data
-	 *
-	 * @param   string  $property
-	 * @return  bool
-	 */
-	public function __isset($property)
-	{
-		if (array_key_exists($property, static::properties()))
-		{
-			return true;
-		}
-		elseif (static::relations($property))
-		{
-			return true;
-		}
-		elseif (array_key_exists($property, $this->_custom_data))
-		{
-			return true;
-		}
-
-		return false;
-	}
-
-	/**
-	 * Empty a property, relation or custom data
-	 *
-	 * @param   string  $property
-	 */
-	public function __unset($property)
-	{
-		if (array_key_exists($property, static::properties()))
-		{
-			$this->_data[$property] = null;
-		}
-		elseif ($rel = static::relations($property))
-		{
-			$this->_data_relations[$property] = $rel->singular ? null : array();
-		}
-		elseif (array_key_exists($property, $this->_custom_data))
-		{
-			unset($this->_custom_data[$property]);
-		}
-	}
-
-	/**
-	 * Allow for getter, setter and unset methods
-	 *
-	 * @param   string  $method
-	 * @param   array   $args
-	 * @return  mixed
-	 * @throws  \BadMethodCallException
-	 */
-	public function __call($method, $args)
-	{
-		if (substr($method, 0, 4) == 'get_')
-		{
-			return $this->get(substr($method, 4));
-		}
-		elseif (substr($method, 0, 4) == 'set_')
-		{
-			return $this->set(substr($method, 4), reset($args));
-		}
-		elseif (substr($method, 0, 6) == 'unset_')
-		{
-			return $this->__unset(substr($method, 6));
-		}
-
-		// Throw an exception
-		throw new \BadMethodCallException('Call to undefined method '.get_class($this).'::'.$method.'()');
-	}
-
-	/**
-	 * Allow object cloning to new object
-	 */
-	public function __clone()
-	{
-		// Reset primary keys
-		foreach (static::$_primary_key as $pk)
-		{
-			$this->_data[$pk] = null;
-		}
-
-		// This is a new object
-		$this->_is_new = true;
-		$this->_original = array();
-		$this->_original_relations = array();
-
-		// Cleanup relations
-		foreach ($this->relations() as $name => $rel)
-		{
-			// singular relations (hasone, belongsto) can't be copied, neither can HasMany
-			if ($rel->singular or $rel instanceof HasMany)
-			{
-				unset($this->_data_relations[$name]);
-			}
-		}
-
-		$this->observe('after_clone');
-	}
-
-	/**
-	 * Get
-	 *
-	 * Gets a property or
-	 * relation from the
-	 * object
-	 *
-	 * @access  public
-	 * @param   string  $property
-	 * @return  mixed
-	 */
-	public function & get($property)
-	{
-		if (array_key_exists($property, static::properties()))
-		{
-			if ( ! array_key_exists($property, $this->_data))
-			{
-				// avoid a notice, we're returning by reference
-				$var = null;
-				return $var;
-			}
-
-			return $this->_data[$property];
-		}
-		elseif ($rel = static::relations($property))
-		{
-			if ( ! array_key_exists($property, $this->_data_relations))
-			{
-				$this->_data_relations[$property] = $rel->get($this);
-				$this->_update_original_relations(array($property));
-			}
-			return $this->_data_relations[$property];
-		}
-		elseif (($value = $this->_get_eav($property)) !== false)
-		{
-			return $value;
-		}
-		elseif ($this->_view and in_array($property, static::$_views_cached[get_class($this)][$this->_view]['columns']))
-		{
-			return $this->_data[$property];
-		}
-		elseif (array_key_exists($property, $this->_custom_data))
-		{
-				return $this->_custom_data[$property];
-		}
-		else
-		{
-			throw new \OutOfBoundsException('Property "'.$property.'" not found for '.get_called_class().'.');
-		}
-	}
-
-	/**
-	 * Set
-	 *
-	 * Sets a property or
-	 * relation of the
-	 * object
-	 *
-	 * @access  public
-	 * @param   string|array  $property
-	 * @param   string  $value in case $property is a string
-	 * @return  Orm\Model
-	 */
-	public function set($property, $value = null)
-	{
-		if ($this->_frozen)
-		{
-			throw new FrozenObject('No changes allowed.');
-		}
-
-		if (is_array($property))
-		{
-			foreach ($property as $p => $v)
-			{
-				$this->set($p, $v);
-			}
-		}
-		else
-		{
-			if (func_num_args() < 2)
-			{
-				throw new \InvalidArgumentException('You need to pass both a property name and a value to set().');
-			}
-
-			if (in_array($property, static::primary_key()) and $this->{$property} !== null)
-			{
-				throw new \FuelException('Primary key on model '.get_class().' cannot be changed.');
-			}
-			if (array_key_exists($property, static::properties()))
-			{
-				$this->_data[$property] = $value;
-			}
-			elseif (static::relations($property))
-			{
-				$this->is_fetched($property) or $this->_reset_relations[$property] = true;
-				$this->_data_relations[$property] = $value;
-			}
-			elseif ( ! $this->_set_eav($property, $value))
-			{
-				$this->_custom_data[$property] = $value;
-			}
-		}
-
-		return $this;
-	}
-
-	/**
-	 * Save the object and it's relations, create when necessary
-	 *
-	 * @param  mixed  $cascade
-	 *     null = use default config,
-	 *     bool = force/prevent cascade,
-	 *     array cascades only the relations that are in the array
-	 */
-	public function save($cascade = null, $use_transaction = false)
-	{
-		if ($this->frozen())
-		{
-			return false;
-		}
-
-		if ($use_transaction)
-		{
-			$db = \Database_Connection::instance(static::connection(true));
-			$db->start_transaction();
-		}
-
-		try
-		{
-			$this->observe('before_save');
-
-			$this->freeze();
-			foreach($this->relations() as $rel_name => $rel)
-			{
-				if (array_key_exists($rel_name, $this->_reset_relations))
-				{
-					method_exists($rel, 'delete_related') and $rel->delete_related($this);
-					unset($this->_reset_relations[$rel_name]);
-				}
-				if (array_key_exists($rel_name, $this->_data_relations))
-				{
-					$rel->save($this, $this->{$rel_name},
-						array_key_exists($rel_name, $this->_original_relations) ? $this->_original_relations[$rel_name] : null,
-						false, is_array($cascade) ? in_array($rel_name, $cascade) : $cascade
-					);
-				}
-			}
-			$this->unfreeze();
-
-			// Insert or update
-			$return = $this->_is_new ? $this->create() : $this->update();
-
-			$this->freeze();
-			foreach($this->relations() as $rel_name => $rel)
-			{
-				if (array_key_exists($rel_name, $this->_data_relations))
-				{
-					$rel->save($this, $this->{$rel_name},
-						array_key_exists($rel_name, $this->_original_relations) ? $this->_original_relations[$rel_name] : null,
-						true, is_array($cascade) ? in_array($rel_name, $cascade) : $cascade
-					);
-				}
-			}
-			$this->unfreeze();
-
-			$this->_update_original();
-
-			$this->observe('after_save');
-
-			$use_transaction and $db->commit_transaction();
-		}
-		catch (\Exception $e)
-		{
-			$use_transaction and $db->rollback_transaction();
-			throw $e;
-		}
-
-		return $return;
-	}
-
-	/**
-	 * Save using INSERT
-	 */
-	protected function create()
-	{
-		// Only allow creation with new object, otherwise: clone first, create later
-		if ( ! $this->is_new())
-		{
-			return false;
-		}
-
-		$this->observe('before_insert');
-
-		// Set all current values
-		$query = Query::forge(get_called_class(), static::connection(true));
-		$primary_key = static::primary_key();
-		$properties  = array_keys(static::properties());
-		foreach ($properties as $p)
-		{
-			if ( ! (in_array($p, $primary_key) and is_null($this->{$p})))
-			{
-				$query->set($p, $this->{$p});
-			}
-		}
-
-		// Insert!
-		$id = $query->insert();
-
-		// when there's one PK it might be auto-incremented, get it and set it
-		if (count($primary_key) == 1 and $id !== false)
-		{
-			$pk = reset($primary_key);
-			// only set it if it hasn't been set manually
-			is_null($this->{$pk}) and $this->{$pk} = $id;
-		}
-
-		// update the original properties on creation and cache object for future retrieval in this request
-		$this->_is_new = false;
-		static::$_cached_objects[get_class($this)][static::implode_pk($this)] = $this;
-
-		$this->observe('after_insert');
-
-		return $id !== false;
-	}
-
-	/**
-	 * Save using UPDATE
-	 */
-	protected function update()
-	{
-		// New objects can't be updated, neither can frozen
-		if ($this->is_new())
-		{
-			return false;
-		}
-
-		// Non changed objects don't have to be saved, but return true anyway (no reason to fail)
-		if ( ! $this->is_changed(array_keys(static::properties())))
-		{
-			return true;
-		}
-
-		$this->observe('before_update');
-
-		// Create the query and limit to primary key(s)
-		$query       = Query::forge(get_called_class(), static::connection(true));
-		$primary_key = static::primary_key();
-		$properties  = array_keys(static::properties());
-		foreach ($primary_key as $pk)
-		{
-			$query->where($pk, '=', $this->_data[$pk]);
-		}
-
-		// Set all current values
-		foreach ($properties as $p)
-		{
-			if ( ! in_array($p, $primary_key))
-			{
-				if (array_key_exists($p, $this->_original))
-				{
-					$this->{$p} !== $this->_original[$p] and $query->set($p, isset($this->_data[$p]) ? $this->_data[$p] : null);
-				}
-				else
-				{
-					array_key_exists($p, $this->_data) and $query->set($p, $this->_data[$p]);
-				}
-			}
-		}
-
-		// Return false when update fails
-		if ( ! $query->update())
-		{
-			return false;
-		}
-
-		// update the original property on success
-		$this->observe('after_update');
-
-		return true;
-	}
-
-	/**
-	 * Delete current object
-	 *
-	 * @param   mixed  $cascade
-	 *     null = use default config,
-	 *     bool = force/prevent cascade,
-	 *     array cascades only the relations that are in the array
-	 * @return  Model  this instance as a new object without primary key(s)
-	 */
-	public function delete($cascade = null, $use_transaction = false)
-	{
-		// New objects can't be deleted, neither can frozen
-		if ($this->is_new() or $this->frozen())
-		{
-			return false;
-		}
-
-		if ($use_transaction)
-		{
-			$db = \Database_Connection::instance(static::connection(true));
-			$db->start_transaction();
-		}
-
-		try
-		{
-			$this->observe('before_delete');
-
-			$this->freeze();
-			foreach($this->relations() as $rel_name => $rel)
-			{
-				$rel->delete($this, $this->{$rel_name}, false, is_array($cascade) ? in_array($rel_name, $cascade) : $cascade);
-			}
-			$this->unfreeze();
-
-			// Create the query and limit to primary key(s)
-			$query = Query::forge(get_called_class(), static::connection(true))->limit(1);
-			$primary_key = static::primary_key();
-			foreach ($primary_key as $pk)
-			{
-				$query->where($pk, '=', $this->{$pk});
-			}
-
-			// Return success of update operation
-			if ( ! $query->delete())
-			{
-				return false;
-			}
-
-			$this->freeze();
-			foreach($this->relations() as $rel_name => $rel)
-			{
-				$rel->delete($this, $this->{$rel_name}, true, is_array($cascade) ? in_array($rel_name, $cascade) : $cascade);
-			}
-			$this->unfreeze();
-
-			// Perform cleanup:
-			// remove from internal object cache, remove PK's, set to non saved object, remove db original values
-			if (array_key_exists(get_called_class(), static::$_cached_objects)
-				and array_key_exists(static::implode_pk($this), static::$_cached_objects[get_called_class()]))
-			{
-				unset(static::$_cached_objects[get_called_class()][static::implode_pk($this)]);
-			}
-			foreach ($this->primary_key() as $pk)
-			{
-				unset($this->_data[$pk]);
-			}
-			$this->_is_new = true;
-			$this->_original = array();
-
-
-			$this->observe('after_delete');
-
-			$use_transaction and $db->commit_transaction();
-		}
-		catch (\Exception $e)
-		{
-			$use_transaction and $db->rollback_transaction();
-			throw $e;
-		}
-
-		return $this;
-	}
-
-	/**
-	 * Reset values to those gotten from the database
-	 */
-	public function reset()
-	{
-		foreach ($this->_original as $p => $val)
-		{
-			$this->_data[$p] = $val;
-		}
-	}
-
-	/**
-	 * Calls all observers for the current event
-	 *
-	 * @param  string
-	 */
-	public function observe($event)
-	{
-		foreach ($this->observers() as $observer => $settings)
-		{
-			$events = isset($settings['events']) ? $settings['events'] : array();
-			if (empty($events) or in_array($event, $events))
-			{
-				if ( ! class_exists($observer))
-				{
-					$observer_class = \Inflector::get_namespace($observer).'Observer_'.\Inflector::denamespace($observer);
-					if ( ! class_exists($observer_class))
-					{
-						throw new \UnexpectedValueException($observer);
-					}
-
-					// Add the observer with the full classname for next usage
-					unset(static::$_observers_cached[$observer]);
-					static::$_observers_cached[$observer_class] = $events;
-					$observer = $observer_class;
-				}
-
-				try
-				{
-					call_user_func(array($observer, 'orm_notify'), $this, $event);
-				}
-				catch (\Exception $e)
-				{
-					// Unfreeze before failing
-					$this->unfreeze();
-
-					throw $e;
-				}
-			}
-		}
-	}
-
-	/**
-	 * Compare current state with the retrieved state
-	 *
-	 * @param   string|array $property
-	 * @return  bool
-	 */
-	public function is_changed($property = null)
-	{
-		$properties = static::properties();
-		$relations = static::relations();
-		$property = (array) $property ?: array_merge(array_keys($properties), array_keys($relations));
-
-		foreach ($property as $p)
-		{
-			if (isset($properties[$p]))
-			{
-				if (array_key_exists($p, $this->_original))
-				{
-					if ($this->{$p} !== $this->_original[$p])
-					{
-						return true;
-					}
-				}
-				else
-				{
-					if (array_key_exists($p, $this->_data))
-					{
-						return true;
-					}
-				}
-			}
-			elseif (isset($relations[$p]))
-			{
-				if ($relations[$p]->singular)
-				{
-					if (empty($this->_original_relations[$p]) !== empty($this->_data_relations[$p])
-						or ( ! empty($this->_original_relations[$p])
-							and $this->_original_relations[$p] !== $this->_data_relations[$p]->implode_pk($this->{$p})))
-					{
-						return true;
-					}
-				}
-				else
-				{
-					if (empty($this->_original_relations[$p]))
-					{
-						if ( ! empty($this->_data_relations[$p]))
-						{
-							return true;
-						}
-						continue;
-					}
-
-					$orig_rels = $this->_original_relations[$p];
-					foreach ($this->{$p} as $rk => $r)
-					{
-						if ( ! in_array($r->implode_pk($r), $orig_rels))
-						{
-							return true;
-						}
-						unset($orig_rels[array_search($rk, $orig_rels)]);
-					}
-					if ( ! empty($orig_rels))
-					{
-						return true;
-					}
-				}
-			}
-			else
-			{
-				throw new \OutOfBoundsException('Unknown property or relation: '.$p);
-			}
-		}
-
-		return false;
-	}
-
-	/**
-	 * Generates an array with keys new & old that contain ONLY the values that differ between the original and
-	 * the current unsaved model.
-	 * Note: relations are given as single or array of imploded pks
-	 *
-	 * @return  array
-	 */
-	public function get_diff()
-	{
-		$diff = array(0 => array(), 1 => array());
-		foreach ($this->_data as $key => $val)
-		{
-			if ($this->is_changed($key))
-			{
-				$diff[0][$key] = array_key_exists($key, $this->_original) ? $this->_original[$key] : null;
-				$diff[1][$key] = $val;
-			}
-		}
-		foreach ($this->_data_relations as $key => $val)
-		{
-			$rel = static::relations($key);
-			if ($rel->singular)
-			{
-				if (empty($this->_original_relations[$key]) !== empty($val)
-					or ( ! empty($this->_original_relations[$key])
-					and $new_pk = $val->implode_pk($val)
-					and $this->_original_relations[$key] !== $new_pk))
-				{
-					$diff[0][$key] = isset($this->_original_relations[$key]) ? $this->_original_relations[$key] : null;
-					$diff[1][$key] = isset($val) ? $new_pk : null;
-				}
-			}
-			else
-			{
-				$original_pks = $this->_original_relations[$key];
-				$new_pks = array();
-				foreach ($val as $v)
-				{
-					if ( ! in_array(($new_pk = $v->implode_pk($v)), $original_pks))
-					{
-						$new_pks[] = $new_pk;
-					}
-					else
-					{
-						$original_pks = array_diff($original_pks, array($new_pk));
-					}
-				}
-				if ( ! empty($original_pks) or ! empty($new_pks)) {
-					$diff[0][$key] = empty($original_pks) ? null : $original_pks;
-					$diff[1][$key] = empty($new_pks) ? null : $new_pks;
-				}
-			}
-		}
-
-		return $diff;
-	}
-
-	/***
-	 * Returns whether the given relation is fetched. If no relation is
-	 *
-	 * @return  bool
-	 */
-	public function is_fetched($relation)
-	{
-		if (static::relations($relation))
-		{
-			return array_key_exists($relation, $this->_data_relations);
-		}
-
-		return false;
-	}
-
-	/***
-	 * Returns whether this is a saved or a new object
-	 *
-	 * @return  bool
-	 */
-	public function is_new()
-	{
-		return $this->_is_new;
-	}
-
-	/**
-	 * Check whether the object was frozen
-	 *
-	 * @return  boolean
-	 */
-	public function frozen()
-	{
-		return $this->_frozen;
-	}
-
-	/**
-	 * Freeze the object to disallow changing it or saving it
-	 */
-	public function freeze()
-	{
-		$this->_frozen = true;
-	}
-
-	/**
-	 * Unfreeze the object to allow changing it or saving it again
-	 */
-	public function unfreeze()
-	{
-		$this->_frozen = false;
-	}
-
-	/**
-	 * Method for use with Fieldset::add_model()
-	 *
-	 * @param   Fieldset     Fieldset instance to add fields to
-	 * @param   array|Model  Model instance or array for use to repopulate
-	 */
-	public static function set_form_fields($form, $instance = null)
-	{
-		Observer_Validation::set_fields($instance instanceof static ? $instance : get_called_class(), $form);
-		$instance and $form->populate($instance, true);
-	}
-
-
-	/**
-	 * Allow populating this object from an array, and any related objects
-	 *
-	 * @return  array
-	 */
-	public function from_array(array $values)
-	{
-		foreach($values as $property => $value)
-		{
-			if (array_key_exists($property, static::properties()) and ! in_array($property, static::primary_key()))
-			{
-				$this->_data[$property] = $value;
-			}
-			elseif (array_key_exists($property, static::relations()) and is_array($value))
-			{
-				foreach($value as $id => $data)
-				{
-					if (array_key_exists($id, $this->_data_relations[$property]) and is_array($data))
-					{
-						foreach($data as $field => $contents)
-						{
-							$this->_data_relations[$property][$id]->{$field} = $contents;
-						}
-					}
-				}
-			}
-		}
-	}
-
-	/**
-	 * Allow converting this object to an array
-	 *
-	 * @param	bool	whether or not to include the custom data array
-	 * @return  array
-	 */
-	public function to_array($custom = false, $recurse = false)
-	{
-		static $references = array();
-
-		$array = array();
-
-		// reset the references array on first call
-		$recurse or $references = array();
-
-		// make sure all data is scalar or array
-		if ($custom)
-		{
-			foreach ($this->_custom_data as $key => $val)
-			{
-				if (is_object($val))
-				{
-					if (method_exists($val, '__toString'))
-					{
-						$val = (string) $val;
-					}
-					else
-					{
-						$val = get_object_vars($val);
-					}
-				}
-				$array[$key] = $val;
-			}
-		}
-
-		// make sure all data is scalar or array
-		foreach ($this->_data as $key => $val)
-		{
-			if (is_object($val))
-			{
-				if (method_exists($val, '__toString'))
-				{
-					$val = (string) $val;
-				}
-				else
-				{
-					$val = get_object_vars($val);
-				}
-			}
-			$array[$key] = $val;
-		}
-
-		// convert relations
-		foreach ($this->_data_relations as $name => $rel)
-		{
-			if (is_array($rel))
-			{
-				$array[$name] = array();
-				if ( ! empty($rel))
-				{
-					foreach ($rel as $id => $r)
-					{
-						$array[$name][$id] = $r->to_array($custom, true);
-					}
-					$references[] = get_class($r);
-				}
-			}
-			else
-			{
-				if ( ! in_array(get_class($rel), $references))
-				{
-					if (is_null($rel))
-					{
-						$array[$name] = null;
-					}
-					else
-					{
-						$array[$name] = $rel->to_array($custom, true);
-						$references[] = get_class($rel);
-					}
-				}
-			}
-		}
-
-		// strip any excluded values from the array
-		foreach (static::$_to_array_exclude as $key)
-		{
-			if (array_key_exists($key, $array))
-			{
-				unset($array[$key]);
-			}
-		}
-
-		return $array;
-	}
-
-
-	/**
-	 * Allow converting this object to a real object
-	 *
-	 * @return  object
-	 */
-	public function to_object()
-	{
-		return (object) $this->to_array();
-	}
-
-	/**
-	 * EAV attribute getter
-	 *
-	 * @param   string  $attribute, the attribute value to get
-	 *
-	 * @return  mixed
-	 * @throws	OutOfBoundsException if the defined EAV relation does not exist or of the wrong type
-	 */
-	protected function _get_eav($attribute)
-	{
-		// get the current class name
-		$class = get_called_class();
-
-		// don't do anything unless we actually have an EAV container
-		if (property_exists($class, '_eav'))
-		{
-			// loop through the defined EAV containers
-			foreach (static::$_eav as $rel => $settings)
-			{
-				// normalize the container definition, could be string or array
-				if (is_string($settings))
-				{
-					$rel = $settings;
-					$settings = array();
-				}
-
-				// fetch the relation object for this EAV container
-				if ( ! $rel = static::relations($rel))
-				{
-					throw new \OutOfBoundsException('EAV container defines a relation that does not exist in '.get_called_class().'.');
-				}
-
-				// EAV containers must be of the "Many type"
-				if ($rel instanceOf \Orm\HasOne or $rel instanceOf \Orm\BelongsTo )
-				{
-					throw new \OutOfBoundsException('EAV containers can only be defined on "HasMany" or "ManyMany" relations in '.get_called_class().'.');
-				}
-
-				// determine attribute and value column names
-				$attr = isset($settings['attribute']) ? $settings['attribute'] : 'attribute';
-				$val = isset($settings['value']) ? $settings['value'] : 'value';
-
-				// loop over the resultset
-				foreach ($this->{$rel->name} as $key => $record)
-				{
-					// and return the value if found
-					if ($record->{$attr} === $attribute)
-					{
-						return $record->{$val};
-					}
-				}
-			}
-		}
-
-		return false;
-	}
-
-	/**
-	 * EAV attribute setter
-	 *
-	 * @param   string  $attribute
-	 * @param   string  $value
-	 *
-	 * @return  mixed
-	 */
-	protected function _set_eav($attribute, $value)
-	{
-		// get the current class name
-		$class = get_called_class();
-
-		// don't do anything unless we actually have an EAV container
-		if (property_exists($class, '_eav'))
-		{
-			// loop through the defined EAV containers
-			foreach (static::$_eav as $rel => $settings)
-			{
-				// normalize the container definition, could be string or array
-				if (is_string($settings))
-				{
-					$rel = $settings;
-					$settings = array();
-				}
-
-				// fetch the relation object for this EAV container
-				if ( ! $rel = static::relations($rel))
-				{
-					throw new \OutOfBoundsException('EAV container defines a relation that does not exist in '.get_called_class().'.');
-				}
-
-				// EAV containers must be of the "Many type"
-				if ($rel instanceOf \Orm\HasOne or $rel instanceOf \Orm\BelongsTo )
-				{
-					throw new \OutOfBoundsException('EAV containers can only be defined on "HasMany" or "ManyMany" relations in '.get_called_class().'.');
-				}
-
-				// determine attribute and value column names
-				$attr = isset($settings['attribute']) ? $settings['attribute'] : 'attribute';
-				$val = isset($settings['value']) ? $settings['value'] : 'value';
-
-				// loop over the resultset
-				foreach ($this->{$rel->name} as $key => $record)
-				{
-					if ($record->{$attr} === $attribute)
-					{
-						$record->{$val} = $value;
-						return true;
-					}
-				}
-			}
-		}
-
-		return false;
-	}
-
-	/***************************************************************************
-	 * Implementation of ArrayAccess
-	 **************************************************************************/
-
-	public function offsetSet($offset, $value)
-	{
-		try
-		{
-			$this->__set($offset, $value);
-		}
-		catch (\Exception $e)
-		{
-			return false;
-		}
-	}
-
-	public function offsetExists($offset)
-	{
-		return $this->__isset($offset);
-	}
-
-	public function offsetUnset($offset)
-	{
-		$this->__unset($offset);
-	}
-
-	public function offsetGet($offset)
-	{
-		try
-		{
-			return $this->__get($offset);
-		}
-		catch (\Exception $e)
-		{
-			return false;
-		}
-	}
-
-	/***************************************************************************
-	 * Implementation of Iterable
-	 **************************************************************************/
-
-	protected $_iterable = array();
-
-	public function rewind()
-	{
-		$this->_iterable = array_merge($this->_custom_data, $this->_data, $this->_data_relations);
-		reset($this->_iterable);
-	}
-
-	public function current()
-	{
-		return current($this->_iterable);
-	}
-
-	public function key()
-	{
-		return key($this->_iterable);
-	}
-
-	public function next()
-	{
-		return next($this->_iterable);
-	}
-
-	public function valid()
-	{
-		return key($this->_iterable) !== null;
-	}
-
-}

+ 0 - 303
frameworks/PHP/php-fuel/fuel/packages/orm/classes/model/soft.php

@@ -1,303 +0,0 @@
-<?php
-
-namespace Orm;
-
-class RelationNotSoft extends \Exception
-{
-
-}
-
-/**
- * Defines a model that can be "soft" deleted. A timestamp is used to indicate
- * that the data has been deleted but the data itself is not removed from the
- * database.
- *
- * @author Steve "Uru" West <[email protected]>
- */
-class Model_Soft extends Model
-{
-
-	/**
-	 * Default column name that contains the deleted timestamp
-	 * @var string
-	 */
-	protected static $_default_field_name = 'deleted_at';
-
-	/**
-	 * Default value for if a mysql timestamp should be used.
-	 * @var boolean
-	 */
-	protected static $_default_mysql_timestamp = true;
-
-	/**
-	 * Contains cached soft delete properties.
-	 * @var array
-	 */
-	protected static $_soft_delete_cached = array();
-
-	protected static $_disable_filter = array();
-
-	/**
-	 * Gets the soft delete properties.
-	 * Mostly stolen from the parent class properties() function
-	 *
-	 * @return array
-	 */
-	public static function soft_delete_properties()
-	{
-		$class = get_called_class();
-
-		// If already determined
-		if (array_key_exists($class, static::$_soft_delete_cached))
-		{
-			return static::$_soft_delete_cached[$class];
-		}
-
-		$properties = array();
-
-		// Try to grab the properties from the class...
-		if (property_exists($class, '_soft_delete'))
-		{
-			//Load up the info
-			$properties = static::$_soft_delete;
-		}
-
-		// cache the properties for next usage
-		static::$_soft_delete_cached[$class] = $properties;
-
-		return static::$_soft_delete_cached[$class];
-	}
-
-	/**
-	 * Disables filtering of deleted entries.
-	 */
-	public static function disable_filter()
-	{
-		$class = get_called_class();
-		static::$_disable_filter[$class] = false;
-	}
-
-	/**
-	 * Enables filtering of deleted entries.
-	 */
-	public static function enable_filter()
-	{
-		$class = get_called_class();
-		static::$_disable_filter[$class] = true;
-	}
-
-	/**
-	 * @return boolean True if the deleted items are to be filtered out.
-	 */
-	public static function get_filter_status()
-	{
-		$class = get_called_class();
-		return \Arr::get(static::$_disable_filter, $class, true);
-	}
-
-	/**
-	 * Fetches a soft delete property description array, or specific data from it.
-	 * Stolen from parent class.
-	 *
-	 * @param   string  property or property.key
-	 * @param   mixed   return value when key not present
-	 * @return  mixed
-	 */
-	public static function soft_delete_property($key, $default = null)
-	{
-		$class = get_called_class();
-
-		// If already determined
-		if ( ! array_key_exists($class, static::$_soft_delete_cached))
-		{
-			static::soft_delete_properties();
-		}
-
-		return \Arr::get(static::$_soft_delete_cached[$class], $key, $default);
-	}
-
-	/**
-	 * Do some php magic to allow static::find_deleted() to work
-	 *
-	 * @param type $method
-	 * @param type $args
-	 */
-	public static function __callStatic($method, $args)
-	{
-		if (strpos($method, 'find_deleted') === 0)
-		{
-			$temp_args = $args;
-
-			$find_type = count($temp_args) > 0 ? array_pop($temp_args) : 'all';
-			$options = count($temp_args) > 0 ? array_pop($temp_args) : array();
-
-			return static::deleted($find_type, $options);
-		}
-
-		parent::__callStatic($method, $args);
-	}
-
-	/**
-	 * Updates the defined deleted_field with a current timestamp rather than
-	 * deleting.
-	 *
-	 * @return this
-	 */
-	public function delete($cascade = null, $use_transaction = false)
-	{
-		$deleted_column = static::soft_delete_property('deleted_field', static::$_default_field_name);
-		$mysql_timestamp = static::soft_delete_property('mysql_timestamp', static::$_default_mysql_timestamp);
-
-		//If we are using a transcation then make sure it's started
-		if ($use_transaction)
-		{
-			$db = \Database_Connection::instance(static::connection(true));
-			$db->start_transaction();
-		}
-
-		//Call the observers
-		$this->observe('before_delete');
-
-		//Generate the correct timestamp and save it
-		$this->{$deleted_column} = $mysql_timestamp ? \Date::forge()->format('mysql') : \Date::forge()->get_timestamp();
-
-		//Loop through all relations and delete if we are cascading.
-		$this->freeze();
-		foreach ($this->relations() as $rel_name => $rel)
-		{
-			//get the cascade delete status
-			$relCascade = is_null($cascade) ? $rel->cascade_delete : (bool) $cascade;
-
-			//Make sure that the other model is soft delete too
-			if ($relCascade)
-			{
-				if ( ! is_subclass_of($rel->model_to, 'Orm\Model_Soft'))
-				{
-					//Throw if other is not soft
-					throw new RelationNotSoft('Both sides of the relation must be subclasses of Model_Soft if cascade delete is true');
-				}
-
-				if(get_class($rel) != 'Orm\ManyMany')
-				{
-					//Loop through and call delete on all the models
-					foreach($rel->get($this) as $model)
-					{
-						$model->delete($cascade);
-					}
-				}
-			}
-		}
-		$this->unfreeze();
-
-		$this->save();
-
-		$this->observe('after_delete');
-
-		//Make sure the transaction is commited if needed
-		$use_transaction and $db->commit_transaction();
-
-		return $this;
-	}
-
-	/**
-	 * Allows a soft deleted entry to be restored.
-	 */
-	public function restore($cascade_restore = null)
-	{
-		$deleted_column = static::soft_delete_property('deleted_field', static::$_default_field_name);
-		$this->{$deleted_column} = null;
-
-		//Loop through all relations and delete if we are cascading.
-		$this->freeze();
-		foreach ($this->relations() as $rel_name => $rel)
-		{
-			//get the cascade delete status
-			$rel_cascade = is_null($cascade_restore) ? $rel->cascade_delete : (bool) $cascade_restore;
-
-			//Make sure that the other model is soft delete too
-			if ($rel_cascade)
-			{
-				if ( ! is_subclass_of($rel->model_to, 'Orm\Model_Soft'))
-				{
-					//Throw if other is not soft
-					throw new RelationNotSoft('Both sides of the relation must be subclasses of Model_Soft if cascade delete is true');
-				}
-
-				if (get_class($rel) != 'Orm\ManyMany')
-				{
-					$model_to = $rel->model_to;
-					$model_to::disable_filter();
-
-					//Loop through and call restore on all the models
-					foreach($rel->get($this) as $model)
-					{
-						$model->restore($cascade_restore);
-					}
-
-					$model_to::enable_filter();
-				}
-			}
-		}
-		$this->unfreeze();
-
-		$this->save();
-
-		return $this;
-	}
-
-	/**
-	 * Alias of restore()
-	 */
-	public function undelete()
-	{
-		return $this->restore();
-	}
-
-	/**
-	 * Overrides the find method to allow soft deleted items to be filtered out.
-	 */
-	public static function find($id = null, array $options = array())
-	{
-		if (static::get_filter_status())
-		{
-			//Make sure we are filtering out soft deleted items
-			$deleted_column = static::soft_delete_property('deleted_field', static::$_default_field_name);
-			$options['where'][] = array($deleted_column, null);
-		}
-
-		return parent::find($id, $options);
-	}
-
-	/**
-	 * Overrides the query method to allow soft delete items to be filtered out.
-	 */
-	public static function query($options=array())
-	{
-		if (static::get_filter_status())
-		{
-			//Make sure we are filtering out soft deleted items
-			$deleted_column = static::soft_delete_property('deleted_field', static::$_default_field_name);
-			$options['where'][] = array($deleted_column, null);
-		}
-
-		return parent::query($options);
-	}
-
-	/**
-	 * Alisas of find() but selects only deleted entries rather than non-deleted
-	 * ones.
-	 */
-	public static function deleted($id = null, array $options = array())
-	{
-		//Make sure we are not filtering out soft deleted items
-		$deleted_column = static::soft_delete_property('deleted_field', static::$_default_field_name);
-		$options['where'][] = array($deleted_column, 'IS NOT', null);
-
-		static::disable_filter();
-		$result = parent::find($id, $options);
-		static::enable_filter();
-
-		return $result;
-	}
-
-}

+ 0 - 55
frameworks/PHP/php-fuel/fuel/packages/orm/classes/observer.php

@@ -1,55 +0,0 @@
-<?php
-/**
- * Fuel is a fast, lightweight, community driven PHP5 framework.
- *
- * @package    Fuel
- * @version    1.5
- * @author     Fuel Development Team
- * @license    MIT License
- * @copyright  2010 - 2013 Fuel Development Team
- * @link       http://fuelphp.com
- */
-
-namespace Orm;
-
-/**
- * Observer base class
- */
-abstract class Observer
-{
-	/**
-	 * @var	array	list of created observer instances created
-	 */
-	protected static $_instances = array();
-
-	/**
-	 * Get notified of an event
-	 *
-	 * @param  Model   $instance
-	 * @param  string  $event
-	 */
-	public static function orm_notify($instance, $event)
-	{
-		$model_class = get_class($instance);
-		if (method_exists(static::instance($model_class), $event))
-		{
-			static::instance($model_class)->{$event}($instance);
-		}
-	}
-
-	/**
-	 * Create an instance of this observer
-	 *
-	 * @param  string  name of the model class
-	 */
-	public static function instance($model_class)
-	{
-		$observer = get_called_class();
-		if (empty(static::$_instances[$observer][$model_class]))
-		{
-			static::$_instances[$observer][$model_class] = new static($model_class);
-		}
-
-		return static::$_instances[$observer][$model_class];
-	}
-}

+ 0 - 63
frameworks/PHP/php-fuel/fuel/packages/orm/classes/observer/createdat.php

@@ -1,63 +0,0 @@
-<?php
-/**
- * Fuel is a fast, lightweight, community driven PHP5 framework.
- *
- * @package    Fuel
- * @version    1.5
- * @author     Fuel Development Team
- * @license    MIT License
- * @copyright  2010 - 2013 Fuel Development Team
- * @link       http://fuelphp.com
- */
-
-namespace Orm;
-
-/**
- * CreatedAt observer. Makes sure the created timestamp column in a Model record
- * gets a value when a new record is inserted in the database.
- */
-class Observer_CreatedAt extends Observer
-{
-	/**
-	 * @var  bool  default setting, true to use mySQL timestamp instead of UNIX timestamp
-	 */
-	public static $mysql_timestamp = false;
-
-	/**
-	 * @var  string  default property to set the timestamp on
-	 */
-	public static $property = 'created_at';
-
-	/**
-	 * @var  bool  true to use mySQL timestamp instead of UNIX timestamp
-	 */
-	protected $_mysql_timestamp;
-
-	/**
-	 * @var  string  property to set the timestamp on
-	 */
-	protected $_property;
-
-	/**
-	 * Set the properties for this observer instance, based on the parent model's
-	 * configuration or the defined defaults.
-	 *
-	 * @param  string  Model class this observer is called on
-	 */
-	public function __construct($class)
-	{
-		$props = $class::observers(get_class($this));
-		$this->_mysql_timestamp  = isset($props['mysql_timestamp']) ? $props['mysql_timestamp'] : static::$mysql_timestamp;
-		$this->_property         = isset($props['property']) ? $props['property'] : static::$property;
-	}
-
-	/**
-	 * Set the CreatedAt property to the current time.
-	 *
-	 * @param  Model  Model object subject of this observer method
-	 */
-	public function before_insert(Model $obj)
-	{
-		$obj->{$this->_property} = $this->_mysql_timestamp ? \Date::time()->format('mysql') : \Date::time()->get_timestamp();
-	}
-}

+ 0 - 34
frameworks/PHP/php-fuel/fuel/packages/orm/classes/observer/self.php

@@ -1,34 +0,0 @@
-<?php
-/**
- * Fuel is a fast, lightweight, community driven PHP5 framework.
- *
- * @package    Fuel
- * @version    1.5
- * @author     Fuel Development Team
- * @license    MIT License
- * @copyright  2010 - 2013 Fuel Development Team
- * @link       http://fuelphp.com
- */
-
-namespace Orm;
-
-/**
- * Dummy observer class, which allows you to define observer methods in the
- * model itself.
- */
-class Observer_Self
-{
-	/**
-	 * Get notified of an event
-	 *
-	 * @param  Model   $instance
-	 * @param  string  $event
-	 */
-	public static function orm_notify(Model $instance, $event)
-	{
-		if (method_exists($instance, $method = '_event_'.$event))
-		{
-			call_user_func(array($instance, $method));
-		}
-	}
-}

+ 0 - 111
frameworks/PHP/php-fuel/fuel/packages/orm/classes/observer/slug.php

@@ -1,111 +0,0 @@
-<?php
-/**
- * Fuel is a fast, lightweight, community driven PHP5 framework.
- *
- * @package    Fuel
- * @version    1.5
- * @author     Fuel Development Team
- * @license    MIT License
- * @copyright  2010 - 2013 Fuel Development Team
- * @link       http://fuelphp.com
- */
-
-namespace Orm;
-
-/**
- * Observer class to generate SEO friendly slugs from a model property (usually something like a title)
- */
-class Observer_Slug extends Observer
-{
-	/**
-	 * @var  mixed  Default source property or array of properties, which is/are used to create the slug
-	 */
-	public static $source = 'title';
-
-	/**
-	 * @var  string  Default slug property
-	 */
-	public static $property = 'slug';
-
-	/**
-	 * @var  mixed  Source property or array of properties, which is/are used to create the slug
-	 */
-	protected $_source;
-
-	/**
-	 * @var  string  Slug property
-	 */
-	protected $_property;
-
-	/**
-	 * Set the properties for this observer instance, based on the parent model's
-	 * configuration or the defined defaults.
-	 *
-	 * @param  string  Model class this observer is called on
-	 */
-	public function __construct($class)
-	{
-		$props = $class::observers(get_class($this));
-		$this->_source    = isset($props['source']) ? $props['source'] : static::$source;
-		$this->_property  = isset($props['property']) ? $props['property'] : static::$property;
-	}
-
-	/**
-	 * Creates a unique slug and adds it to the object
-	 *
-	 * @param  Model  Model object subject of this observer method
-	 */
-	public function before_insert(Model $obj)
-	{
-		// determine the slug
-		$properties = (array) $this->_source;
-		$source = '';
-		foreach ($properties as $property)
-		{
-			$source .= '-'.$obj->{$property};
-		}
-		$slug = \Inflector::friendly_title(substr($source, 1), '-', true);
-
-		// do we have records with this slug?
-		$same = $obj->query()->where($this->_property, 'like', $slug.'%')->get();
-
-		// make sure our slug is unique
-		if ( ! empty($same))
-		{
-			$max = -1;
-
-			foreach ($same as $record)
-			{
-				if (preg_match('/^'.$slug.'(?:-([0-9]+))?$/', $record->{$this->_property}, $matches))
-				{
-					$index = isset($matches[1]) ? (int) $matches[1] : 0;
-					$max < $index and $max = $index;
-				}
-			}
-
-			$max < 0 or $slug .= '-'.($max + 1);
-		}
-
-		$obj->{$this->_property} = $slug;
-	}
-
-	/**
-	 * Creates a new unique slug and update the object
-	 *
-	 * @param  Model  Model object subject of this observer method
-	 */
-	public function before_update(Model $obj)
-	{
-		// determine the slug
-		$properties = (array) $this->_source;
-		$source = '';
-		foreach ($properties as $property)
-		{
-			$source .= '-'.$obj->{$property};
-		}
-		$slug = \Inflector::friendly_title(substr($source, 1), '-', true);
-
-		// update it if it's different from the current one
-		$obj->{$this->_property} === $slug or $this->before_insert($obj);
-	}
-}

+ 0 - 445
frameworks/PHP/php-fuel/fuel/packages/orm/classes/observer/typing.php

@@ -1,445 +0,0 @@
-<?php
-/**
- * Fuel is a fast, lightweight, community driven PHP5 framework.
- *
- * @package    Fuel
- * @version    1.5
- * @author     Fuel Development Team
- * @license    MIT License
- * @copyright  2010 - 2013 Fuel Development Team
- * @link       http://fuelphp.com
- */
-
-namespace Orm;
-
-/**
- * Invalid content exception, thrown when type conversion is not possible.
- */
-class InvalidContentType extends \UnexpectedValueException {}
-
-/**
- * Typing observer.
- *
- * Runs on load or save, and ensures the correct data type of your ORM object properties.
- */
-class Observer_Typing
-{
-	/**
-	 * @var  array  types of events to act on and whether they are pre- or post-database
-	 */
-	public static $events = array(
-		'before_save'  => 'before',
-		'after_save'   => 'after',
-		'after_load'   => 'after',
-	);
-
-	/**
-	 * @var  array  regexes for db types with the method(s) to use, optionally pre- or post-database
-	 */
-	public static $type_methods = array(
-		'/^varchar/uiD' => array(
-			'before' => 'Orm\\Observer_Typing::type_string',
-		),
-		'/^(tiny|small|medium|big)?int(eger)?/uiD'
-			=> 'Orm\\Observer_Typing::type_integer',
-		'/^(float|double|decimal)/uiD'
-			=> 'Orm\\Observer_Typing::type_float',
-		'/^(tiny|medium|long)?text/' => array(
-			'before' => 'Orm\\Observer_Typing::type_string',
-		),
-		'/^set/uiD' => array(
-			'before' => 'Orm\\Observer_Typing::type_set_before',
-			'after' => 'Orm\\Observer_Typing::type_set_after',
-		),
-		'/^enum/uiD' => array(
-			'before' => 'Orm\\Observer_Typing::type_set_before',
-		),
-		'/^bool(ean)?$/uiD' => array(
-			'before' => 'Orm\\Observer_Typing::type_bool_to_int',
-			'after'  => 'Orm\\Observer_Typing::type_bool_from_int',
-		),
-		'/^serialize$/uiD' => array(
-			'before' => 'Orm\\Observer_Typing::type_serialize',
-			'after'  => 'Orm\\Observer_Typing::type_unserialize',
-		),
-		'/^json$/uiD' => array(
-			'before' => 'Orm\\Observer_Typing::type_json_encode',
-			'after'  => 'Orm\\Observer_Typing::type_json_decode',
-		),
-		'/^time_(unix|mysql)$/' => array(
-			'before' => 'Orm\\Observer_Typing::type_time_encode',
-			'after'  => 'Orm\\Observer_Typing::type_time_decode',
-		),
-	);
-
-	/**
-	 * Get notified of an event
-	 *
-	 * @param  Model   $instance
-	 * @param  string  $event
-	 */
-	public static function orm_notify(Model $instance, $event)
-	{
-		if ( ! array_key_exists($event, static::$events))
-		{
-			return;
-		}
-
-		$event_type = static::$events[$event];
-		$properties = $instance->properties();
-
-		foreach ($properties as $p => $settings)
-		{
-			if (empty($settings['data_type']) || in_array($p, $instance->primary_key()))
-			{
-				continue;
-			}
-			if ($instance->{$p} === null) // add check if null is allowed
-			{
-				if (array_key_exists('null', $settings) and $settings['null'] === false)
-				{
-					throw new InvalidContentType('The property "'.$p.'" cannot be NULL.');
-				}
-				continue;
-			}
-
-			foreach (static::$type_methods as $match => $method)
-			{
-				if (is_array($method))
-				{
-					$method = ! empty($method[$event_type]) ? $method[$event_type] : false;
-				}
-				if ($method === false)
-				{
-					continue;
-				}
-
-				if ($method and preg_match($match, $settings['data_type']) > 0)
-				{
-					$instance->{$p} = call_user_func($method, $instance->{$p}, $settings);
-					continue;
-				}
-			}
-		}
-
-		if ($event_type == 'after')
-		{
-			$instance->_update_original();
-		}
-	}
-
-	/**
-	 * Typecast a single column value based on the model properties for that column
-	 *
-	 * @param  string  $column	name of the column
-	 * @param  string  $value	value
-	 * @param  string  $settings	column settings from the model
-	 *
-	 * @throws  InvalidContentType
-	 *
-	 * @return  mixed
-	 */
-	public static function typecast($column, $value, $settings)
-	{
-		if ($value === null) // add check if null is allowed
-		{
-			if (array_key_exists('null', $settings) and $settings['null'] === false)
-			{
-				throw new InvalidContentType('The property "'.$column.'" cannot be NULL.');
-			}
-		}
-
-		if (isset($settings['data_type']))
-		{
-			foreach (static::$type_methods as $match => $method)
-			{
-				if (is_array($method))
-				{
-					if ( ! empty($method['before']))
-					{
-						$method = $method['before'];
-					}
-					else
-					{
-						continue;
-					}
-				}
-				if ($method and preg_match($match, $settings['data_type']) > 0)
-				{
-					$value = call_user_func($method, $value, $settings);
-					break;
-				}
-			}
-		}
-
-		return $value;
-	}
-
-	/**
-	 * Casts to string when necessary and checks if within max length
-	 *
-	 * @param   mixed  value to typecast
-	 * @param   array  any options to be passed
-	 *
-	 * @throws  InvalidContentType
-	 *
-	 * @return  string
-	 */
-	public static function type_string($var, array $settings)
-	{
-		if (is_array($var) or (is_object($var) and ! method_exists($var, '__toString')))
-		{
-			throw new InvalidContentType('Array or object could not be converted to varchar.');
-		}
-
-		$var = strval($var);
-
-		if (array_key_exists('character_maximum_length', $settings))
-		{
-			$length  = intval($settings['character_maximum_length']);
-			if ($length > 0 and strlen($var) > $length)
-			{
-				$var = substr($var, 0, $length);
-			}
-		}
-
-		return $var;
-	}
-
-	/**
-	 * Casts to int when necessary and checks if within max values
-	 *
-	 * @param   mixed  value to typecast
-	 * @param   array  any options to be passed
-	 *
-	 * @throws  InvalidContentType
-	 *
-	 * @return  int
-	 */
-	public static function type_integer($var, array $settings)
-	{
-		if (is_array($var) or is_object($var))
-		{
-			throw new InvalidContentType('Array or object could not be converted to integer.');
-		}
-
-		if ((array_key_exists('min', $settings) and $var < intval($settings['min']))
-			or (array_key_exists('max', $settings) and $var > intval($settings['max'])))
-		{
-			throw new InvalidContentType('Integer value outside of range: '.$var);
-		}
-
-		return intval($var);
-	}
-
-	/**
-	 * Casts to float when necessary
-	 *
-	 * @param   mixed  value to typecast
-	 *
-	 * @throws  InvalidContentType
-	 *
-	 * @return  float
-	 */
-	public static function type_float($var)
-	{
-		if (is_array($var) or is_object($var))
-		{
-			throw new InvalidContentType('Array or object could not be converted to float.');
-		}
-
-		return floatval($var);
-	}
-
-	/**
-	 * Value pre-treater, deals with array values, and handles the enum type
-	 *
-	 * @param   mixed  value
-	 * @param   array  any options to be passed
-	 *
-	 * @throws  InvalidContentType
-	 *
-	 * @return  string
-	 */
-	public static function type_set_before($var, array $settings)
-	{
-		$var    = is_array($var) ? implode(',', $var) : strval($var);
-		$values = array_filter(explode(',', trim($var)));
-
-		if ($settings['data_type'] == 'enum' and count($values) > 1)
-		{
-			throw new InvalidContentType('Enum cannot have more than 1 value.');
-		}
-
-		foreach ($values as $val)
-		{
-			if ( ! in_array($val, $settings['options']))
-			{
-				throw new InvalidContentType('Invalid value given for '.ucfirst($settings['data_type']).
-					', value "'.$var.'" not in available options: "'.implode(', ', $settings['options']).'".');
-			}
-		}
-
-		return $var;
-	}
-
-	/**
-	 * Value post-treater, converts a comma-delimited string into an array
-	 *
-	 * @param   mixed  value
-	 *
-	 * @return  array
-	 */
-	public static function type_set_after($var)
-	{
-		return explode(',', $var);
-	}
-
-	/**
-	 * Converts boolean input to 1 or 0 for the DB
-	 *
-	 * @param   bool  value
-	 *
-	 * @return  int
-	 */
-	public static function type_bool_to_int($var)
-	{
-		return $var ? 1 : 0;
-	}
-
-	/**
-	 * Converts DB bool values to PHP bool value
-	 *
-	 * @param   bool  value
-	 *
-	 * @return  int
-	 */
-	public static function type_bool_from_int($var)
-	{
-		return $var == '1' ? true : false;
-	}
-
-	/**
-	 * Returns the serialized input
-	 *
-	 * @param   mixed  value
-	 * @param   array  any options to be passed
-	 *
-	 * @throws  InvalidContentType
-	 *
-	 * @return  string
-	 */
-	public static function type_serialize($var, array $settings)
-	{
-		$var = serialize($var);
-
-		if (array_key_exists('character_maximum_length', $settings))
-		{
-			$length  = intval($settings['character_maximum_length']);
-			if ($length > 0 and strlen($var) > $length)
-			{
-				throw new InvalidContentType('Value could not be serialized, exceeds max string length for field.');
-			}
-		}
-
-		return $var;
-	}
-
-	/**
-	 * Unserializes the input
-	 *
-	 * @param   string  value
-	 *
-	 * @return  mixed
-	 */
-	public static function type_unserialize($var)
-	{
-		return unserialize($var);
-	}
-
-	/**
-	 * JSON encodes the input
-	 *
-	 * @param   mixed  value
-	 * @param   array  any options to be passed
-	 *
-	 * @throws  InvalidContentType
-	 *
-	 * @return  string
-	 */
-	public static function type_json_encode($var, array $settings)
-	{
-		$var = json_encode($var);
-
-		if (array_key_exists('character_maximum_length', $settings))
-		{
-			$length  = intval($settings['character_maximum_length']);
-			if ($length > 0 and strlen($var) > $length)
-			{
-				throw new InvalidContentType('Value could not be JSON encoded, exceeds max string length for field.');
-			}
-		}
-
-		return $var;
-	}
-
-	/**
-	 * Decodes the JSON
-	 *
-	 * @param   string  value
-	 *
-	 * @return  mixed
-	 */
-	public static function type_json_decode($var, $settings)
-	{
-		$assoc = false;
-		if (array_key_exists('json_assoc', $settings))
-		{
-			$assoc = (bool)$settings['json_assoc'];
-		}
-		return json_decode($var, $assoc);
-	}
-
-	/**
-	 * Takes a Date instance and transforms it into a DB timestamp
-	 *
-	 * @param   \Fuel\Core\Date  value
-	 * @param   array  any options to be passed
-	 *
-	 * @throws  InvalidContentType
-	 *
-	 * @return  int|string
-	 */
-	public static function type_time_encode(\Fuel\Core\Date $var, array $settings)
-	{
-		if ( ! $var instanceof \Fuel\Core\Date)
-		{
-			throw new InvalidContentType('Value must be an instance of the Date class.');
-		}
-
-		if ($settings['data_type'] == 'time_mysql')
-		{
-			return $var->format('mysql');
-		}
-
-		return $var->get_timestamp();
-	}
-
-	/**
-	 * Takes a DB timestamp and converts it into a Date object
-	 *
-	 * @param   string  value
-	 * @param   array  any options to be passed
-	 *
-	 * @return  \Fuel\Core\Date
-	 */
-	public static function type_time_decode($var, array $settings)
-	{
-		if ($settings['data_type'] == 'time_mysql')
-		{
-			return \Date::create_from_string($var, 'mysql');
-		}
-
-		return \Date::forge($var);
-	}
-}

+ 0 - 66
frameworks/PHP/php-fuel/fuel/packages/orm/classes/observer/updatedat.php

@@ -1,66 +0,0 @@
-<?php
-/**
- * Fuel is a fast, lightweight, community driven PHP5 framework.
- *
- * @package    Fuel
- * @version    1.5
- * @author     Fuel Development Team
- * @license    MIT License
- * @copyright  2010 - 2013 Fuel Development Team
- * @link       http://fuelphp.com
- */
-
-namespace Orm;
-
-/**
- * UpdatedAt observer. Makes sure the updated timestamp column in a Model record
- * gets a value when a record is updated in the database.
- */
-class Observer_UpdatedAt extends Observer
-{
-	/**
-	 * @var  bool  set true to use mySQL timestamp instead of UNIX timestamp
-	 */
-	public static $mysql_timestamp = false;
-
-	/**
-	 * @var  string  property to set the timestamp on
-	 */
-	public static $property = 'updated_at';
-
-	/**
-	 * @var  bool  true to use mySQL timestamp instead of UNIX timestamp
-	 */
-	protected $_mysql_timestamp;
-
-	/**
-	 * @var  string  property to set the timestamp on
-	 */
-	protected $_property;
-
-	/**
-	 * Set the properties for this observer instance, based on the parent model's
-	 * configuration or the defined defaults.
-	 *
-	 * @param  string  Model class this observer is called on
-	 */
-	public function __construct($class)
-	{
-		$props = $class::observers(get_class($this));
-		$this->_mysql_timestamp  = isset($props['mysql_timestamp']) ? $props['mysql_timestamp'] : static::$mysql_timestamp;
-		$this->_property         = isset($props['property']) ? $props['property'] : static::$property;
-	}
-
-	/**
-	 * Set the UpdatedAt property to the current time.
-	 *
-	 * @param  Model  Model object subject of this observer method
-	 */
-	public function before_save(Model $obj)
-	{
-		if ($obj->is_new() or $obj->is_changed())
-		{
-			$obj->{$this->_property} = $this->_mysql_timestamp ? \Date::time()->format('mysql') : \Date::time()->get_timestamp();
-		}
-	}
-}

+ 0 - 219
frameworks/PHP/php-fuel/fuel/packages/orm/classes/observer/validation.php

@@ -1,219 +0,0 @@
-<?php
-/**
- * Fuel is a fast, lightweight, community driven PHP5 framework.
- *
- * @package    Fuel
- * @version    1.5
- * @author     Fuel Development Team
- * @license    MIT License
- * @copyright  2010 - 2013 Fuel Development Team
- * @link       http://fuelphp.com
- */
-
-namespace Orm;
-
-/**
- *  Exception to throw when validation failed
- */
-class ValidationFailed extends \FuelException
-{
-	/**
-	 * @var  Fieldset the fieldset causing this exception
-	 */
-	protected $fieldset;
-
-	/**
-	 * Overridden \FuelException construct to add a Fieldset instance into the exception
-	 *
-	 * @param  string  the error message
-	 * @param  int  the error code
-	 * @param  \Exception any previous exception
-	 * @param  \Fieldset  the fieldset on which this exception was triggered
-	 */
-	public function __construct($message = null, $code = 0, \Exception $previous = null, \Fieldset $fieldset = null)
-	{
-		parent::__construct($message, $code, $previous);
-
-		$this->fieldset = $fieldset;
-	}
-
-	/**
-	 * Gets the Fieldset from this exception
-	 *
-	 * @return Fieldset
-	 */
-	public function get_fieldset()
-	{
-		return $this->fieldset;
-	}
-}
-
-/**
- * Observer class to validate the properties of the model before save.
- *
- * It is also used in Fieldset generation based on a model, to populate the fields
- * and field validation rules of the Fieldset.
- */
-class Observer_Validation extends Observer
-{
-
-	/**
-	 * Set a Model's properties as fields on a Fieldset, which will be created with the Model's
-	 * classname if none is provided.
-	 *
-	 * @param   string
-	 * @param   \Fieldset|null
-	 * @return  \Fieldset
-	 */
-	public static function set_fields($obj, $fieldset = null)
-	{
-		static $_generated = array();
-		static $_tabular_rows = array();
-
-		$class = is_object($obj) ? get_class($obj) : $obj;
-		if (is_null($fieldset))
-		{
-			$fieldset = \Fieldset::instance($class);
-			if ( ! $fieldset)
-			{
-				$fieldset = \Fieldset::forge($class);
-			}
-		}
-
-		// is our parent fieldset a tabular form set?
-		$tabular_form = is_object($fieldset->parent()) ? $fieldset->parent()->get_tabular_form() : false;
-
-		// don't cache tabular form fieldsets
-		if ( ! $tabular_form)
-		{
-			! array_key_exists($class, $_generated) and $_generated[$class] = array();
-			if (in_array($fieldset, $_generated[$class], true))
-			{
-				return $fieldset;
-			}
-			$_generated[$class][] = $fieldset;
-		}
-
-		$primary_keys = is_object($obj) ? $obj->primary_key() : $class::primary_key();
-		$primary_key = count($primary_keys) === 1 ? reset($primary_keys) : false;
-		$properties = is_object($obj) ? $obj->properties() : $class::properties();
-
-		if ($tabular_form and $primary_key and ! is_object($obj))
-		{
-			isset($_tabular_rows[$class]) or $_tabular_rows[$class] = 0;
-		}
-
-		foreach ($properties as $p => $settings)
-		{
-			if (\Arr::get($settings, 'skip', in_array($p, $primary_keys)))
-			{
-				continue;
-			}
-
-			if (isset($settings['form']['options']))
-			{
-				foreach ($settings['form']['options'] as $key => $value)
-				{
-					is_array($value) or $settings['form']['options'][$key] = \Lang::get($value, array(), false) ?: $value;
-				}
-			}
-
-			// field attributes can be passed in form key
-			$attributes = isset($settings['form']) ? $settings['form'] : array();
-			// label is either set in property setting, as part of form attributes or defaults to fieldname
-			$label = isset($settings['label']) ? $settings['label'] : (isset($attributes['label']) ? $attributes['label'] : $p);
-			$label = \Lang::get($label, array(), false) ?: $label;
-
-			// change the fieldname and label for tabular form fieldset children
-			if ($tabular_form and $primary_key)
-			{
-				if (is_object($obj))
-				{
-					$p = $tabular_form.'['.$obj->{$primary_key}.']['.$p.']';
-				}
-				else
-				{
-					$p = $tabular_form.'_new['.$_tabular_rows[$class].']['.$p.']';
-				}
-				$label = '';
-			}
-
-			// create the field and add validation rules
-			$field = $fieldset->add($p, $label, $attributes);
-			if ( ! empty($settings['validation']))
-			{
-				foreach ($settings['validation'] as $rule => $args)
-				{
-					if (is_int($rule) and is_string($args))
-					{
-						$args = array($args);
-					}
-					else
-					{
-						array_unshift($args, $rule);
-					}
-
-					call_user_func_array(array($field, 'add_rule'), $args);
-				}
-			}
-		}
-
-		// increase the row counter for tabular row fieldsets
-		if ($tabular_form and $primary_key and ! is_object($obj))
-		{
-			$_tabular_rows[$class]++;
-		}
-
-		return $fieldset;
-	}
-
-	/**
-	 * Execute before saving the Model
-	 *
-	 * @param   Model	the model object to validate
-	 *
-	 * @throws  ValidationFailed
-	 */
-	public function before_save(Model $obj)
-	{
-		$this->validate($obj);
-	}
-
-	/**
-	 * Validate the model
-	 *
-	 * @param   Model	the model object to validate
-	 *
-	 * @throws  ValidationFailed
-	 */
-	public function validate(Model $obj)
-	{
-		$fieldset = static::set_fields($obj);
-		$val = $fieldset->validation();
-
-		// only allow partial validation on updates, specify the fields for updates to allow null
-		$allow_partial = $obj->is_new() ? false : array();
-
-		$input = array();
-		foreach (array_keys($obj->properties()) as $p)
-		{
-			if ( ! in_array($p, $obj->primary_key()) and $obj->is_changed($p))
-			{
-				$input[$p] = $obj->{$p};
-				is_array($allow_partial) and $allow_partial[] = $p;
-			}
-		}
-
-		if ( ! empty($input) and $val->run($input, $allow_partial, array($obj)) === false)
-		{
-			throw new ValidationFailed($val->show_errors(), 0, null, $fieldset);
-		}
-		else
-		{
-			foreach ($input as $k => $v)
-			{
-				$obj->{$k} = $val->validated($k);
-			}
-		}
-	}
-}

+ 0 - 1330
frameworks/PHP/php-fuel/fuel/packages/orm/classes/query.php

@@ -1,1330 +0,0 @@
-<?php
-/**
- * Fuel is a fast, lightweight, community driven PHP5 framework.
- *
- * @package    Fuel
- * @version    1.5
- * @author     Fuel Development Team
- * @license    MIT License
- * @copyright  2010 - 2013 Fuel Development Team
- * @link       http://fuelphp.com
- */
-
-namespace Orm;
-
-/**
- * ORM query object.
- */
-class Query
-{
-	/**
-	 * Create a new instance of the Query class.
-	 *
-	 * @param	string	name of the model this instance has to operate on
-	 * @param	mixed	DB connection to use to run the query
-	 * @param	array	any options to pass on to the query
-	 *
-	 * return	Query	newly created instance
-	 */
-	public static function forge($model, $connection = null, $options = array())
-	{
-		return new static($model, $connection, $options);
-	}
-
-	/**
-	 * @var  string  classname of the model
-	 */
-	protected $model;
-
-	/**
-	 * @var  null|string  connection name to use
-	 */
-	protected $connection;
-
-	/**
-	 * @var  null|string  connection name to use for writes
-	 */
-	protected $write_connection;
-
-	/**
-	 * @var  array  database view to use with keys 'view' and 'columns'
-	 */
-	protected $view;
-
-	/**
-	 * @var  string  table alias
-	 */
-	protected $alias = 't0';
-
-	/**
-	 * @var  array  relations to join on
-	 */
-	protected $relations = array();
-
-	/**
-	 * @var  array  tables to join without returning any info
-	 */
-	protected $joins = array();
-
-	/**
-	 * @var  array  fields to select
-	 */
-	protected $select = array();
-
-	/**
-	 * @var  int  max number of returned base model instances
-	 */
-	protected $limit;
-
-	/**
-	 * @var  int  offset of base model table
-	 */
-	protected $offset;
-
-	/**
-	 * @var  int  max number of requested rows
-	 */
-	protected $rows_limit;
-
-	/**
-	 * @var  int  offset of requested rows
-	 */
-	protected $rows_offset;
-
-	/**
-	 * @var  array  where conditions
-	 */
-	protected $where = array();
-
-	/**
-	 * @var  array  order by clauses
-	 */
-	protected $order_by = array();
-
-	/**
-	 * @var  array  group by clauses
-	 */
-	protected $group_by = array();
-
-	/**
-	 * @var  array  values for insert or update
-	 */
-	protected $values = array();
-
-	/**
-	 * @var  array  select filters
-	 */
-	protected $select_filter = array();
-
-	/**
-	 * Create a new instance of the Query class.
-	 *
-	 * @param	string	name of the model this instance has to operate on
-	 * @param	mixed	DB connection to use to run the query
-	 * @param	array	any options to pass on to the query
-	 * @param	mixed	optionally, the alias to use for the models table
-	 */
-	protected function __construct($model, $connection, $options, $table_alias = null)
-	{
-		$this->model = $model;
-
-		if (is_array($connection))
-		{
-			list($this->connection, $this->write_connection) = $connection;
-		}
-		else
-		{
-			$this->connection = $connection;
-			$this->write_connection = $connection;
-		}
-
-		foreach ($options as $opt => $val)
-		{
-			switch ($opt)
-			{
-				case 'select':
-					$val = (array) $val;
-					call_user_func_array(array($this, 'select'), $val);
-					break;
-				case 'related':
-					$val = (array) $val;
-					$this->related($val);
-					break;
-				case 'use_view':
-					$this->use_view($val);
-					break;
-				case 'where':
-					$this->_parse_where_array($val);
-					break;
-				case 'order_by':
-					$val = (array) $val;
-					$this->order_by($val);
-					break;
-				case 'group_by':
-					$this->group_by($val);
-					break;
-				case 'limit':
-					$this->limit($val);
-					break;
-				case 'offset':
-					$this->offset($val);
-					break;
-				case 'rows_limit':
-					$this->rows_limit($val);
-					break;
-				case 'rows_offset':
-					$this->rows_offset($val);
-					break;
-			}
-		}
-	}
-
-	/**
-	 * Select which properties are included, each as its own param. Or don't give input to retrieve
-	 * the current selection.
-	 *
-	 * @param	bool	whether or not to add the Primary Keys to the list of selected columns
-	 *
-	 * @return  void|array
-	 */
-	public function select($add_pks = true)
-	{
-		$fields = func_get_args();
-
-		if (empty($fields) or is_bool($add_pks))
-		{
-			if (empty($this->select))
-			{
-				$fields = array_keys(call_user_func($this->model.'::properties'));
-
-				if (empty($fields))
-				{
-					throw new \FuelException('No properties found in model.');
-				}
-				foreach ($fields as $field)
-				{
-					in_array($field, $this->select_filter) or $this->select($field);
-				}
-
-				if ($this->view)
-				{
-					foreach ($this->view['columns'] as $field)
-					{
-						$this->select($field);
-					}
-				}
-			}
-
-			// backup select before adding PKs
-			$select = $this->select;
-
-			// ensure all PKs are being selected
-			if ($add_pks)
-			{
-				$pks = call_user_func($this->model.'::primary_key');
-				foreach($pks as $pk)
-				{
-					if ( ! in_array($this->alias.'.'.$pk, $this->select))
-					{
-						$this->select($pk);
-					}
-				}
-			}
-
-			// convert selection array for DB class
-			$out = array();
-			foreach($this->select as $k => $v)
-			{
-				$out[] = array($v, $k);
-			}
-
-			// set select back to before the PKs were added
-			$this->select = $select;
-
-			return $out;
-		}
-
-		$i = count($this->select);
-		foreach ($fields as $val)
-		{
-			is_array($val) or $val = array($val => true);
-
-			foreach ($val as $field => $include)
-			{
-				if ($include)
-				{
-					$this->select[$this->alias.'_c'.$i++] = (strpos($field, '.') === false ? $this->alias.'.' : '').$field;
-				}
-				else
-				{
-					$this->select_filter[] = $field;
-				}
-			}
-		}
-
-		return $this;
-	}
-
-	/**
-	 * Set a view to use instead of the table
-	 *
-	 * @param   string
-	 *
-	 * @return  Query
-	 */
-	public function use_view($view)
-	{
-		$views = call_user_func(array($this->model, 'views'));
-		if ( ! array_key_exists($view, $views))
-		{
-			throw new \OutOfBoundsException('Cannot use undefined database view, must be defined with Model.');
-		}
-
-		$this->view = $views[$view];
-		$this->view['_name'] = $view;
-		return $this;
-	}
-
-	/**
-	 * Creates a "GROUP BY ..." filter.
-	 *
-	 * @param   mixed   column name or array($column, $alias) or object
-	 * @param   mixed	..., optional list of additional filter definitions
-	 *
-	 * @return  $this
-	 */
-	public function group_by($columns)
-	{
-		$columns = func_get_args();
-
-		$this->group_by = array_merge($this->group_by, $columns);
-
-		return $this;
-	}
-
-	/**
-	 * Set the limit
-	 *
-	 * @param   int
-	 *
-	 * @return  $this
-	 */
-	public function limit($limit)
-	{
-		$this->limit = intval($limit);
-
-		return $this;
-	}
-
-	/**
-	 * Set the offset
-	 *
-	 * @param   int
-	 *
-	 * @return  $this
-	 */
-	public function offset($offset)
-	{
-		$this->offset = intval($offset);
-
-		return $this;
-	}
-
-	/**
-	 * Set the limit of rows requested
-	 *
-	 * @param   int
-	 *
-	 * @return  $this
-	 */
-	public function rows_limit($limit)
-	{
-		$this->rows_limit = intval($limit);
-
-		return $this;
-	}
-
-	/**
-	 * Set the offset of rows requested
-	 *
-	 * @param   int
-	 *
-	 * @return  $this
-	 */
-	public function rows_offset($offset)
-	{
-		$this->rows_offset = intval($offset);
-
-		return $this;
-	}
-
-	/**
-	 * Set where condition
-	 *
-	 * @param   string  property
-	 * @param   string  comparison type (can be omitted)
-	 * @param   string  comparison value
-	 *
-	 * @return  $this
-	 */
-	public function where()
-	{
-		$condition = func_get_args();
-		is_array(reset($condition)) and $condition = reset($condition);
-
-		return $this->_where($condition);
-	}
-
-	/**
-	 * Set or_where condition
-	 *
-	 * @param   string  property
-	 * @param   string  comparison type (can be omitted)
-	 * @param   string  comparison value
-	 *
-	 * @return  $this
-	 */
-	public function or_where()
-	{
-		$condition = func_get_args();
-		is_array(reset($condition)) and $condition = reset($condition);
-
-		return $this->_where($condition, 'or_where');
-	}
-
-	/**
-	 * Does the work for where() and or_where()
-	 *
-	 * @param   array
-	 * @param   string
-	 *
-	 * @return  $this
-	 */
-	public function _where($condition, $type = 'and_where')
-	{
-		if (is_array(reset($condition)) or is_string(key($condition)))
-		{
-			foreach ($condition as $k_c => $v_c)
-			{
-				is_string($k_c) and $v_c = array($k_c, $v_c);
-				$this->_where($v_c, $type);
-			}
-			return $this;
-		}
-
-		// prefix table alias when not yet prefixed and not a DB expression object
-		if (strpos($condition[0], '.') === false and ! $condition[0] instanceof \Fuel\Core\Database_Expression)
-		{
-			$condition[0] = $this->alias.'.'.$condition[0];
-		}
-
-		if (count($condition) == 2)
-		{
-			$this->where[] = array($type, array($condition[0], '=', $condition[1]));
-		}
-		elseif (count($condition) == 3)
-		{
-			$this->where[] = array($type, $condition);
-		}
-		else
-		{
-			throw new \FuelException('Invalid param count for where condition.');
-		}
-
-		return $this;
-	}
-
-	/**
-	 * Open a nested and_where condition
-	 *
-	 * @return  $this
-	 */
-	public function and_where_open()
-	{
-		$this->where[] = array('and_where_open', array());
-
-		return $this;
-	}
-
-	/**
-	 * Close a nested and_where condition
-	 *
-	 * @return  $this
-	 */
-	public function and_where_close()
-	{
-		$this->where[] = array('and_where_close', array());
-
-		return $this;
-	}
-
-	/**
-	 * Alias to and_where_open()
-	 *
-	 * @return  $this
-	 */
-	public function where_open()
-	{
-		$this->where[] = array('and_where_open', array());
-
-		return $this;
-	}
-
-	/**
-	 * Alias to and_where_close()
-	 *
-	 * @return  $this
-	 */
-	public function where_close()
-	{
-		$this->where[] = array('and_where_close', array());
-
-		return $this;
-	}
-
-	/**
-	 * Open a nested or_where condition
-	 *
-	 * @return  $this
-	 */
-	public function or_where_open()
-	{
-		$this->where[] = array('or_where_open', array());
-
-		return $this;
-	}
-
-	/**
-	 * Close a nested or_where condition
-	 *
-	 * @return  $this
-	 */
-	public function or_where_close()
-	{
-		$this->where[] = array('or_where_close', array());
-
-		return $this;
-	}
-
-	/**
-	 * Parses an array of where conditions into the query
-	 *
-	 * @param   array   $val
-	 * @param   string  $base
-	 * @param   bool    $or
-	 */
-	protected function _parse_where_array(array $val, $base = '', $or = false)
-	{
-		$or and $this->or_where_open();
-		foreach ($val as $k_w => $v_w)
-		{
-			if (is_array($v_w) and ! empty($v_w[0]) and is_string($v_w[0]))
-			{
-				! $v_w[0] instanceof \Database_Expression and strpos($v_w[0], '.') === false and $v_w[0] = $base.$v_w[0];
-				call_user_func_array(array($this, ($k_w === 'or' ? 'or_' : '').'where'), $v_w);
-			}
-			elseif (is_int($k_w) or $k_w == 'or')
-			{
-				$k_w === 'or' ? $this->or_where_open() : $this->where_open();
-				$this->_parse_where_array($v_w, $base, $k_w === 'or');
-				$k_w === 'or' ? $this->or_where_close() : $this->where_close();
-			}
-			else
-			{
-				! $k_w instanceof \Database_Expression and strpos($k_w, '.') === false and $k_w = $base.$k_w;
-				$this->where($k_w, $v_w);
-			}
-		}
-		$or and $this->or_where_close();
-	}
-
-	/**
-	 * Set the order_by
-	 *
-	 * @param   string|array
-	 * @param   string|null
-	 *
-	 * @return  $this
-	 */
-	public function order_by($property, $direction = 'ASC')
-	{
-		if (is_array($property))
-		{
-			foreach ($property as $p => $d)
-			{
-				if (is_int($p))
-				{
-					is_array($d) ? $this->order_by($d[0], $d[1]) : $this->order_by($d, $direction);
-				}
-				else
-				{
-					$this->order_by($p, $d);
-				}
-			}
-			return $this;
-		}
-
-		// prefix table alias when not yet prefixed and not a DB expression object
-		if ( ! $property instanceof \Fuel\Core\Database_Expression and strpos($property, '.') === false)
-		{
-			$property = $this->alias.'.'.$property;
-		}
-
-		$this->order_by[] = array($property, $direction);
-
-		return $this;
-	}
-
-	/**
-	 * Set a relation to include
-	 *
-	 * @param   string
-	 * @param   array
-	 *
-	 * @return  $this
-	 */
-	public function related($relation, $conditions = array())
-	{
-		if (is_array($relation))
-		{
-			foreach ($relation as $k_r => $v_r)
-			{
-				is_array($v_r) ? $this->related($k_r, $v_r) : $this->related($v_r);
-			}
-			return $this;
-		}
-
-		if (strpos($relation, '.'))
-		{
-			$rels = explode('.', $relation);
-			$model = $this->model;
-			foreach ($rels as $r)
-			{
-				$rel = call_user_func(array($model, 'relations'), $r);
-				if (empty($rel))
-				{
-					throw new \UnexpectedValueException('Relation "'.$r.'" was not found in the model "'.$model.'".');
-				}
-				$model = $rel->model_to;
-			}
-		}
-		else
-		{
-			$rel = call_user_func(array($this->model, 'relations'), $relation);
-			if (empty($rel))
-			{
-				throw new \UnexpectedValueException('Relation "'.$relation.'" was not found in the model.');
-			}
-		}
-
-		$this->relations[$relation] = array($rel, $conditions);
-
-		if ( ! empty($conditions['related']))
-		{
-			$conditions['related'] = (array) $conditions['related'];
-			foreach ($conditions['related'] as $k_r => $v_r)
-			{
-				is_array($v_r) ? $this->related($relation.'.'.$k_r, $v_r) : $this->related($relation.'.'.$v_r);
-			}
-
-			unset($conditions['related']);
-		}
-
-		return $this;
-	}
-
-	/**
-	 * Add a table to join, consider this a protect method only for Orm package usage
-	 *
-	 * @param   array
-	 *
-	 * @return  $this
-	 */
-	public function _join(array $join)
-	{
-		$this->joins[] = $join;
-
-		return $this;
-	}
-
-	/**
-	 * Set any properties for insert or update
-	 *
-	 * @param   string|array
-	 * @param   mixed
-	 *
-	 * @return  $this
-	 */
-	public function set($property, $value = null)
-	{
-		if (is_array($property))
-		{
-			foreach ($property as $p => $v)
-			{
-				$this->set($p, $v);
-			}
-			return $this;
-		}
-
-		$this->values[$property] = $value;
-
-		return $this;
-	}
-
-	/**
-	 * Build a select, delete or update query
-	 *
-	 * @param   \Fuel\Core\Database_Query_Builder_Where  DB where() query object
-	 * @param   string|select  either array for select query or string update, delete, insert
-	 * @param	string  type of query to build (select/update/delete/insert)
-	 *
-	 * @return  array          with keys query and relations
-	 */
-	public function build_query(\Fuel\Core\Database_Query_Builder_Where $query, $columns = array(), $type = 'select')
-	{
-		// Get the limit
-		if ( ! is_null($this->limit))
-		{
-			$query->limit($this->limit);
-		}
-
-		// Get the offset
-		if ( ! is_null($this->offset))
-		{
-			$query->offset($this->offset);
-		}
-
-		$where_conditions = call_user_func($this->model.'::condition', 'where');
-		empty($where_conditions) or $this->where($where_conditions);
-
-		$where_backup = $this->where;
-		if ( ! empty($this->where))
-		{
-			$open_nests = 0;
-			foreach ($this->where as $key => $w)
-			{
-				list($method, $conditional) = $w;
-
-				if ($type == 'select' and (empty($conditional) or $open_nests > 0))
-				{
-					strpos($method, '_open') and $open_nests++;
-					strpos($method, '_close') and $open_nests--;
-					continue;
-				}
-
-				if (empty($conditional)
-					or strpos($conditional[0], $this->alias.'.') === 0
-					or ($type != 'select' and $conditional[0] instanceof \Fuel\Core\Database_Expression))
-				{
-					if ($type != 'select' and ! empty($conditional)
-						and ! $conditional[0] instanceof \Fuel\Core\Database_Expression)
-					{
-						$conditional[0] = substr($conditional[0], strlen($this->alias.'.'));
-					}
-					call_user_func_array(array($query, $method), $conditional);
-					unset($this->where[$key]);
-				}
-			}
-		}
-
-		// If it's not a select we're done
-		if ($type != 'select')
-		{
-			return array('query' => $query, 'models' => array());
-		}
-
-		$i = 1;
-		$models = array();
-		foreach ($this->relations as $name => $rel)
-		{
-			// when there's a dot it must be a nested relation
-			if ($pos = strrpos($name, '.'))
-			{
-				if (empty($models[substr($name, 0, $pos)]['table'][1]))
-				{
-					throw new \UnexpectedValueException('Trying to get the relation of an unloaded relation, make sure you load the parent relation before any of its children.');
-				}
-
-				$alias = $models[substr($name, 0, $pos)]['table'][1];
-			}
-			else
-			{
-				$alias = $this->alias;
-			}
-
-			$models = array_merge($models, $rel[0]->join($alias, $name, $i++, $rel[1]));
-		}
-
-		if ($this->use_subquery())
-		{
-			// Get the columns for final select
-			foreach ($models as $m)
-			{
-				foreach ($m['columns'] as $c)
-				{
-					$columns[] = $c;
-				}
-			}
-
-			// make current query subquery of ultimate query
-			$new_query = call_user_func_array('DB::select', $columns);
-			$query = $new_query->from(array($query, $this->alias));
-		}
-		else
-		{
-			// add additional selected columns
-			foreach ($models as $m)
-			{
-				foreach ($m['columns'] as $c)
-				{
-					$query->select($c);
-				}
-			}
-		}
-
-		// join tables
-		foreach ($this->joins as $j)
-		{
-			$join_query = $query->join($j['table'], $j['join_type']);
-			foreach ($j['join_on'] as $on)
-			{
-				$join_query->on($on[0], $on[1], $on[2]);
-			}
-		}
-		foreach ($models as $m)
-		{
-			if (($type == 'select' and $m['connection'] != $this->connection) or
-				($type != 'select' and $m['connection'] != $this->write_connection))
-			{
-				throw new \FuelException('Models cannot be related between different database connections.');
-			}
-
-			$join_query = $query->join($m['table'], $m['join_type']);
-			foreach ($m['join_on'] as $on)
-			{
-				$join_query->on($on[0], $on[1], $on[2]);
-			}
-		}
-
-		// Get the order, if none set see if we have an order_by condition set
-		empty($this->order_by) and $this->order_by(call_user_func($this->model.'::condition', 'order_by'));
-		$order_by = $order_by_backup = $this->order_by;
-
-		// Add any additional order_by and where clauses from the relations
-		foreach ($models as $m_name => $m)
-		{
-			if ( ! empty($m['order_by']))
-			{
-				foreach ((array) $m['order_by'] as $k_ob => $v_ob)
-				{
-					if (is_int($k_ob))
-					{
-						$v_dir = is_array($v_ob) ? $v_ob[1] : 'ASC';
-						$v_ob = is_array($v_ob) ? $v_ob[0] : $v_ob;
-						if ( ! $v_ob instanceof \Fuel\Core\Database_Expression and strpos($v_ob, '.') === false)
-						{
-							$v_ob = $m_name.'.'.$v_ob;
-						}
-
-						$order_by[] = array($v_ob, $v_dir);
-					}
-					else
-					{
-						strpos($k_ob, '.') === false and $k_ob = $m_name.'.'.$k_ob;
-						$order_by[] = array($k_ob, $v_ob);
-					}
-				}
-			}
-			if ( ! empty($m['where']))
-			{
-				$this->_parse_where_array($m['where'], $m_name.'.');
-			}
-		}
-
-		// Get the order
-		if ( ! empty($order_by))
-		{
-			foreach ($order_by as $ob)
-			{
-				if ( ! $ob[0] instanceof \Fuel\Core\Database_Expression)
-				{
-					if (strpos($ob[0], $this->alias.'.') === 0)
-					{
-						// order by on the current model
-						$type == 'select' or $ob[0] = substr($ob[0], strlen($this->alias.'.'));
-					}
-					else
-					{
-						// try to rewrite conditions on the relations to their table alias
-						$dotpos = strrpos($ob[0], '.');
-						$relation = substr($ob[0], 0, $dotpos);
-						if ($dotpos > 0 and array_key_exists($relation, $models))
-						{
-							$ob[0] = $models[$relation]['table'][1].substr($ob[0], $dotpos);
-						}
-					}
-				}
-				$query->order_by($ob[0], $ob[1]);
-			}
-		}
-
-		// Get the grouping
-		if ( ! empty($this->group_by))
-		{
-			call_user_func_array(array($query, 'group_by'), $this->group_by);
-		}
-
-		// put omitted where conditions back
-		if ( ! empty($this->where))
-		{
-			foreach ($this->where as $w)
-			{
-				list($method, $conditional) = $w;
-
-				// try to rewrite conditions on the relations to their table alias
-				if ( ! empty($conditional))
-				{
-					$dotpos = strrpos($conditional[0], '.');
-					$relation = substr($conditional[0], 0, $dotpos);
-					if ($dotpos > 0 and array_key_exists($relation, $models))
-					{
-						$conditional[0] = $models[$relation]['table'][1].substr($conditional[0], $dotpos);
-					}
-				}
-
-				call_user_func_array(array($query, $method), $conditional);
-			}
-		}
-
-		$this->where = $where_backup;
-		$this->order_by = $order_by_backup;
-
-		// Set the row limit and offset, these are applied to the outer query when a subquery
-		// is used or overwrite limit/offset when it's a normal query
-		! is_null($this->rows_limit) and $query->limit($this->rows_limit);
-		! is_null($this->rows_offset) and $query->offset($this->rows_offset);
-
-		return array('query' => $query, 'models' => $models);
-	}
-
-	/**
-	 * Determines whether a subquery is needed, is the case if there was a limit/offset on a join
-	 *
-	 * @return  bool
-	 */
-	public function use_subquery()
-	{
-		return ( ! empty($this->relations) and ( ! empty($this->limit) or ! empty($this->offset)));
-	}
-
-	/**
-	 * Hydrate model instances with retrieved data
-	 *
-	 * @param   array   row from the database
-	 * @param   array   relations to be expected
-	 * @param   array   current result array (by reference)
-	 * @param   string  model classname to hydrate
-	 * @param   array   columns to use
-	 * @param   array   primary key(s) for this model
-	 * @return  Model
-	 */
-	public function hydrate(&$row, $models, &$result, $model = null, $select = null, $primary_key = null)
-	{
-		// First check the PKs, if null it's an empty row
-		$r1c1    = reset($select);
-		$prefix  = substr($r1c1[0], 0, strpos($r1c1[0], '.') + 1);
-		$obj     = array();
-		foreach ($primary_key as $pk)
-		{
-			$pk_c = null;
-			foreach ($select as $s)
-			{
-				$s[0] === $prefix.$pk and $pk_c = $s[1];
-			}
-
-			if (is_null($row[$pk_c]))
-			{
-				return false;
-			}
-			$obj[$pk] = $row[$pk_c];
-		}
-
-		// Check for cached object
-		$pk  = count($primary_key) == 1 ? reset($obj) : '['.implode('][', $obj).']';
-		$obj = Model::cached_object($pk, $model);
-
-		// Create the object when it wasn't found
-		if ( ! $obj)
-		{
-			// Retrieve the object array from the row
-			$obj = array();
-			foreach ($select as $s)
-			{
-				$f = substr($s[0], strpos($s[0], '.') + 1);
-				$obj[$f] = $row[$s[1]];
-				if (in_array($f, $primary_key))
-				{
-					$obj[$f] = \Orm\Observer_Typing::typecast($f, $obj[$f], call_user_func($model.'::property', $f));
-				}
-				unset($row[$s[1]]);
-			}
-			$obj = $model::forge($obj, false, $this->view ? $this->view['_name'] : null);
-		}
-		else
-		{
-			// add fields not present in the already cached version
-			foreach ($select as $s)
-			{
-				$f = substr($s[0], strpos($s[0], '.') + 1);
-				if ($obj->{$f} === null and $row[$s[1]] !== null)
-				{
-					$obj->{$f} = $row[$s[1]];
-				}
-			}
-		}
-
-		// if the result to be generated is an array and the current object is not yet in there
-		if (is_array($result) and ! array_key_exists($pk, $result))
-		{
-			$result[$pk] = $obj;
-		}
-		// if the result to be generated is a single object and empty
-		elseif ( ! is_array($result) and empty($result))
-		{
-			$result = $obj;
-		}
-
-		// start fetching relationships
-		$rel_objs = $obj->_relate();
-		foreach ($models as $m)
-		{
-			// when the expected model is empty, there's nothing to be done
-			if (empty($m['model']))
-			{
-				continue;
-			}
-
-			// when not yet set, create the relation result var with null or array
-			if ( ! array_key_exists($m['rel_name'], $rel_objs))
-			{
-				$rel_objs[$m['rel_name']] = $m['relation']->singular ? null : array();
-			}
-
-			// when result is array or singular empty, try to fetch the new relation from the row
-			$this->hydrate(
-				$row,
-				! empty($m['models']) ? $m['models'] : array(),
-				$rel_objs[$m['rel_name']],
-				$m['model'],
-				$m['columns'],
-				$m['primary_key']
-			);
-		}
-
-		// attach the retrieved relations to the object and update its original DB values
-		$obj->_relate($rel_objs);
-		$obj->_update_original_relations();
-
-		return $obj;
-	}
-
-	/**
-	 * Build the query and return hydrated results
-	 *
-	 * @return  array
-	 */
-	public function get()
-	{
-		// Get the columns
-		$columns = $this->select();
-
-		// Start building the query
-		$select = $columns;
-		if ($this->use_subquery())
-		{
-			$select = array();
-			foreach ($columns as $c)
-			{
-				$select[] = $c[0];
-			}
-		}
-		$query = call_user_func_array('DB::select', $select);
-
-		// Set from view/table
-		$table = $this->view ? $this->view['view'] : call_user_func($this->model.'::table');
-		$query->from(array($table, $this->alias));
-
-		// Build the query further
-		$tmp     = $this->build_query($query, $columns);
-		$query   = $tmp['query'];
-		$models  = $tmp['models'];
-
-		// Make models hierarchical
-		foreach ($models as $name => $values)
-		{
-			if (strpos($name, '.'))
-			{
-				unset($models[$name]);
-				$rels = explode('.', $name);
-				$ref =& $models[array_shift($rels)];
-				foreach ($rels as $rel)
-				{
-					empty($ref['models']) and $ref['models'] = array();
-					empty($ref['models'][$rel]) and $ref['models'][$rel] = array();
-					$ref =& $ref['models'][$rel];
-				}
-				$ref = $values;
-			}
-		}
-
-		$rows = $query->execute($this->connection)->as_array();
-		$result = array();
-		$model = $this->model;
-		$select = $this->select();
-		$primary_key = $model::primary_key();
-		foreach ($rows as $id => $row)
-		{
-			$this->hydrate($row, $models, $result, $model, $select, $primary_key);
-			unset($rows[$id]);
-		}
-
-		// It's all built, now lets execute and start hydration
-		return $result;
-	}
-
-	/**
-	 * Get the Query as it's been build up to this point and return it as an object
-	 *
-	 * @return  Database_Query
-	 */
-	public function get_query()
-	{
-		// Get the columns
-		$columns = $this->select(false);
-
-		// Start building the query
-		$select = $columns;
-		if ($this->use_subquery())
-		{
-			$select = array();
-			foreach ($columns as $c)
-			{
-				$select[] = $c[0];
-			}
-		}
-		$query = call_user_func_array('DB::select', $select);
-
-		// Set from table
-		$query->from(array(call_user_func($this->model.'::table'), $this->alias));
-
-		// Build the query further
-		$tmp     = $this->build_query($query, $columns);
-
-		return $tmp['query'];
-	}
-
-	/**
-	 * Build the query and return single object hydrated
-	 *
-	 * @return  Model
-	 */
-	public function get_one()
-	{
-		// save the current limits
-		$limit = $this->limit;
-		$rows_limit = $this->rows_limit;
-
-		// if a row limit is set, use that
-		if ($this->rows_limit !== null)
-		{
-			$this->limit = null;
-			$this->rows_limit = 1;
-		}
-		else
-		{
-			$this->limit = 1;
-			$this->rows_limit = null;
-		}
-
-		// get the result using normal find
-		$result = $this->get();
-
-		// put back the old limits
-		$this->limit = $limit;
-		$this->rows_limit = $rows_limit;
-
-		return $result ? reset($result) : null;
-	}
-
-	/**
-	 * Count the result of a query
-	 *
-	 * @param   bool  false for random selected column or specific column, only works for main model currently
-	 * @param	bool  true if DISTINCT has to be aded to the query
-	 *
-	 * @return  mixed   number of rows OR false
-	 */
-	public function count($column = null, $distinct = true)
-	{
-		$select = $column ?: \Arr::get(call_user_func($this->model.'::primary_key'), 0);
-		$select = (strpos($select, '.') === false ? $this->alias.'.'.$select : $select);
-
-		// Get the columns
-		$columns = \DB::expr('COUNT('.($distinct ? 'DISTINCT ' : '').
-			\Database_Connection::instance()->quote_identifier($select).
-			') AS count_result');
-
-		// Remove the current select and
-		$query = \DB::select($columns);
-
-		// Set from table
-		$query->from(array(call_user_func($this->model.'::table'), $this->alias));
-
-		$tmp   = $this->build_query($query, $columns, 'select');
-		$query = $tmp['query'];
-		$count = $query->execute($this->connection)->get('count_result');
-
-		// Database_Result::get('count_result') returns a string | null
-		if ($count === null)
-		{
-			return false;
-		}
-
-		return (int) $count;
-	}
-
-	/**
-	 * Get the maximum of a column for the current query
-	 *
-	 * @param   string  column
-	 * @return  mixed   maximum value OR false
-	 */
-	public function max($column)
-	{
-		is_array($column) and $column = array_shift($column);
-
-		// Get the columns
-		$columns = \DB::expr('MAX('.
-			\Database_Connection::instance()->quote_identifier($this->alias.'.'.$column).
-			') AS max_result');
-
-		// Remove the current select and
-		$query = \DB::select($columns);
-
-		// Set from table
-		$query->from(array(call_user_func($this->model.'::table'), $this->alias));
-
-		$tmp   = $this->build_query($query, $columns, 'max');
-		$query = $tmp['query'];
-		$max   = $query->execute($this->connection)->get('max_result');
-
-		// Database_Result::get('max_result') returns a string | null
-		if ($max === null)
-		{
-			return false;
-		}
-
-		return $max;
-	}
-
-	/**
-	 * Get the minimum of a column for the current query
-	 *
-	 * @param   string  column
-	 * @return  mixed   minimum value OR false
-	 */
-	public function min($column)
-	{
-		is_array($column) and $column = array_shift($column);
-
-		// Get the columns
-		$columns = \DB::expr('MIN('.
-			\Database_Connection::instance()->quote_identifier($this->alias.'.'.$column).
-			') AS min_result');
-
-		// Remove the current select and
-		$query = \DB::select($columns);
-
-		// Set from table
-		$query->from(array(call_user_func($this->model.'::table'), $this->alias));
-
-		$tmp   = $this->build_query($query, $columns, 'min');
-		$query = $tmp['query'];
-		$min   = $query->execute($this->connection)->get('min_result');
-
-		// Database_Result::get('min_result') returns a string | null
-		if ($min === null)
-		{
-			return false;
-		}
-
-		return $min;
-	}
-
-	/**
-	 * Run INSERT with the current values
-	 *
-	 * @return  mixed  last inserted ID or false on failure
-	 */
-	public function insert()
-	{
-		$res = \DB::insert(call_user_func($this->model.'::table'), array_keys($this->values))
-			->values(array_values($this->values))
-			->execute($this->write_connection);
-
-		// Failed to save the new record
-		if ($res[0] === 0)
-		{
-			return false;
-		}
-
-		return $res[0];
-	}
-
-	/**
-	 * Run UPDATE with the current values
-	 *
-	 * @return  bool  success of update operation
-	 */
-	public function update()
-	{
-		// temporary disable relations
-		$tmp_relations   = $this->relations;
-		$this->relations = array();
-
-		// Build query and execute update
-		$query = \DB::update(call_user_func($this->model.'::table'));
-		$tmp   = $this->build_query($query, array(), 'update');
-		$query = $tmp['query'];
-		$res = $query->set($this->values)->execute($this->write_connection);
-
-		// put back any relations settings
-		$this->relations = $tmp_relations;
-
-		// Update can affect 0 rows when input types are different but outcome stays the same
-		return $res >= 0;
-	}
-
-	/**
-	 * Run DELETE with the current values
-	 *
-	 * @return  bool  success of delete operation
-	 */
-	public function delete()
-	{
-		// temporary disable relations
-		$tmp_relations   = $this->relations;
-		$this->relations = array();
-
-		// Build query and execute update
-		$query = \DB::delete(call_user_func($this->model.'::table'));
-		$tmp   = $this->build_query($query, array(), 'delete');
-		$query = $tmp['query'];
-		$res = $query->execute($this->write_connection);
-
-		// put back any relations settings
-		$this->relations = $tmp_relations;
-
-		return $res > 0;
-	}
-}

+ 0 - 145
frameworks/PHP/php-fuel/fuel/packages/orm/classes/relation.php

@@ -1,145 +0,0 @@
-<?php
-/**
- * Fuel is a fast, lightweight, community driven PHP5 framework.
- *
- * @package    Fuel
- * @version    1.5
- * @author     Fuel Development Team
- * @license    MIT License
- * @copyright  2010 - 2013 Fuel Development Team
- * @link       http://fuelphp.com
- */
-
-namespace Orm;
-
-abstract class Relation
-{
-	/**
-	 * @var  string  name of the relationship in the model_from
-	 */
-	protected $name;
-
-	/**
-	 * @var  Model  classname of the parent model
-	 */
-	protected $model_from;
-
-	/**
-	 * @var  string  classname of the related model
-	 */
-	protected $model_to;
-
-	/**
-	 * @var  string  primary key of parent model
-	 */
-	protected $key_from = array('id');
-
-	/**
-	 * @var  string  foreign key in related model
-	 */
-	protected $key_to = array();
-
-	/**
-	 * @var  array  where & order_by conditions for loading this relation
-	 */
-	protected $conditions = array();
-
-	/**
-	 * @var  bool  whether it's a single object or multiple
-	 */
-	protected $singular = false;
-
-	/**
-	 * @var  bool  whether saving this one's model_from should cascade to save model_to
-	 */
-	protected $cascade_save = true;
-
-	/**
-	 * @var  bool  whether deleting this one's model_from should cascade to delete model_to
-	 */
-	protected $cascade_delete = false;
-
-	/**
-	 * Configures the relationship
-	 *
-	 * @param  string  the model that initiates the relationship
-	 * @param  string  name of the relationship
-	 * @param  array   config values like model_to classname, key_from & key_to
-	 */
-	abstract public function __construct($from, $name, array $config);
-
-	/**
-	 * Should get the objects related to the given object by this relation
-	 *
-	 * @param   Model
-	 * @return  object|array
-	 */
-	abstract public function get(Model $from);
-
-	/**
-	 * Should get the properties as associative array with alias => property, the table alias is
-	 * given to be included with the property
-	 *
-	 * @param   string
-	 * @return  array
-	 */
-	public function select($table)
-	{
-		$props = call_user_func(array($this->model_to, 'properties'));
-		$i = 0;
-		$properties = array();
-		foreach ($props as $pk => $pv)
-		{
-			$properties[] = array($table.'.'.$pk, $table.'_c'.$i);
-			$i++;
-		}
-
-		return $properties;
-	}
-
-	/**
-	 * Returns tables to join and fields to select with optional additional settings like order/where
-	 *
-	 * @param   string  alias for the from table
-	 * @param   string  alias for the to table
-	 * @return  array
-	 */
-	abstract public function join($alias_from, $rel_name, $alias_to);
-
-	/**
-	 * Saves the current relationships and may cascade saving to model_to instances
-	 *
-	 * @param  Model        instance of model_from
-	 * @param  array|Model  single or multiple model instances to save
-	 * @param  bool         whether the model_from has been saved already
-	 * @param  null|bool    either uses default setting (null) or forces when true or prevents when false
-	 * @todo   make abstract
-	 */
-	abstract public function save($model_from, $model_to, $original_model_id, $parent_saved, $cascade);
-
-	/**
-	 * Takes the current relations and attempts to delete them when cascading is allowed or forced
-	 *
-	 * @param  Model        instance of model_from
-	 * @param  array|Model  single or multiple model instances to delete
-	 * @param  bool         whether the model_from has been saved already
-	 * @param  null|bool    either uses default setting (null) or forces when true or prevents when false
-	 * @todo   make abstract
-	 */
-	abstract public function delete($model_from, $model_to, $parent_deleted, $cascade);
-
-	/**
-	 * Allow outside access to protected properties
-	 *
-	 * @param  $property
-	 */
-	public function __get($property)
-	{
-		if (strncmp($property, '_', 1) == 0 or ! property_exists($this, $property))
-		{
-			throw new \FuelException('Invalid relation property: '.$property);
-		}
-
-		return $this->{$property};
-	}
-}

+ 0 - 15
frameworks/PHP/php-fuel/fuel/packages/parser/.gitignore

@@ -1,15 +0,0 @@
-*~
-*.bak
-Thumbs.db
-desktop.ini
-.DS_Store
-.buildpath
-.project
-.settings
-fuel/app/logs/*/*/*
-fuel/app/cache/*/*
-nbproject/
-.idea
-*.tmproj
-*.sublime-project
-*.sublime-workspace

+ 0 - 53
frameworks/PHP/php-fuel/fuel/packages/parser/README.md

@@ -1,53 +0,0 @@
-# Parser package
-
-## Installing
-
-Simply add `parser` to your config.php `always_loaded.packages` config option.
-
-## Included Parsers
-
-* Mustache - A lightweight, yet powerful templating library.
-* Markdown - A PHP version of Markdown by Michel Fortin.
-
-## Usage
-
-```php
-// old usage still valid, will load app/views/example.php
-View::forge('example');
-
-// load a SimpleTags template, will load and parse app/views/example.stags
-View::forge('example.stags');
-
-// load a Mustache template, will load and parse app/views/example.mustache
-View::forge('example.mustache');
-
-// load a Twig template, will load and parse app/views/example.twig
-View::forge('example.twig');
-
-// load a Jade template, will load and parse app/views/example.jade
-View::forge('example.jade');
-
-// load a Haml template, will load and parse app/views/example.haml
-View::forge('example.haml');
-
-// load a Smarty template, will load and parse app/views/example.smarty
-View::forge('example.smarty');
-
-// load a Dwoo template, ATTENTION: this one expects app/views/example.tpl
-View::forge('example.dwoo');
-```
-
-## Installing parsers
-
-Only Markdown and Mustache are included. While many other drivers are included, their libraries are not and are by default expected in `app/vendor/lib_name` (capitalize lib_name), you'll have to download them yourself. Don't change the casing or anything, keep it as much original as possible within the `vendor/lib_name` dir to keep updating easy (also because some come with their own autoloader).
-
-You can configure them to be loaded from other locations by copying the parser.php config file to your app and editing it.
-
-## Config and runtime config
-
-Currently the drivers still lack a lot of config options they should probably accept. They are currently all configured to work with one instance of their parser library, which is available to config:
-
-```php
-$view = View::forge('example.stags');
-$view->parser()->set_delimiters('{', '}');
-```

+ 0 - 32
frameworks/PHP/php-fuel/fuel/packages/parser/bootstrap.php

@@ -1,32 +0,0 @@
-<?php
-/**
- * Fuel
- *
- * Fuel is a fast, lightweight, community driven PHP5 framework.
- *
- * @package    Fuel
- * @version    1.5
- * @author     Fuel Development Team
- * @license    MIT License
- * @copyright  2010 - 2013 Fuel Development Team
- * @link       http://fuelphp.com
- */
-
-Autoloader::add_core_namespace('Parser');
-
-Autoloader::add_classes(array(
-	'Parser\\View'             => __DIR__.'/classes/view.php',
-	'Parser\\View_Dwoo'        => __DIR__.'/classes/view/dwoo.php',
-	'Parser\\View_Mustache'    => __DIR__.'/classes/view/mustache.php',
-	'Parser\\View_Markdown'    => __DIR__.'/classes/view/markdown.php',
-	'Parser\\View_SimpleTags'  => __DIR__.'/classes/view/simpletags.php',
-	'Parser\\View_Twig'        => __DIR__.'/classes/view/twig.php',
-	'Parser\\Twig_Fuel_Extension' => __DIR__.'/classes/twig/fuel/extension.php',
-	'Parser\\View_Jade'        => __DIR__.'/classes/view/jade.php',
-	'Parser\\View_Haml'        => __DIR__.'/classes/view/haml.php',
-	'Parser\\View_Smarty'      => __DIR__.'/classes/view/smarty.php',
-	'Parser\\View_Phptal'      => __DIR__.'/classes/view/phptal.php',
-));
-
-
-/* End of file bootstrap.php */

+ 0 - 93
frameworks/PHP/php-fuel/fuel/packages/parser/classes/twig/fuel/extension.php

@@ -1,93 +0,0 @@
-<?php
-/**
- * Fuel
- *
- * Fuel is a fast, lightweight, community driven PHP5 framework.
- *
- * @package    Fuel
- * @version    1.5
- * @author     Fuel Development Team
- * @license    MIT License
- * @copyright  2010 - 2013 Fuel Development Team
- * @link       http://fuelphp.com
- */
-
-namespace Parser;
-
-use Router;
-use Uri;
-use Twig_Extension;
-use Twig_Function_Function;
-use Twig_Function_Method;
-
-/**
- * Provides Twig support for commonly used FuelPHP classes and methods.
- */
-class Twig_Fuel_Extension extends Twig_Extension
-{
-	/**
-	 * Gets the name of the extension.
-	 *
-	 * @return  string
-	 */
-	public function getName()
-	{
-		return 'fuel';
-	}
-
-	/**
-	 * Sets up all of the functions this extension makes available.
-	 *
-	 * @return  array
-	 */
-	public function getFunctions()
-	{
-		return array(
-			'url'           => new Twig_Function_Method($this, 'url'),
-			'base_url'      => new Twig_Function_Function('Uri::base'),
-			'uri_segment'   => new Twig_Function_Function('Uri::segment'),
-			'uri_segments'  => new Twig_Function_Function('Uri::segments'),
-			'config'        => new Twig_Function_Function('Config::get'),
-			'lang'          => new Twig_Function_Function('Lang::get'),
-
-			'form_open'     => new Twig_Function_Function('Form::open'),
-			'form_close'    => new Twig_Function_Function('Form::close'),
-			'form_input'    => new Twig_Function_Function('Form::input'),
-			'form_password' => new Twig_Function_Function('Form::password'),
-			'form_hidden'   => new Twig_Function_Function('Form::hidden'),
-			'form_radio'    => new Twig_Function_Function('Form::radio'),
-			'form_checkbox' => new Twig_Function_Function('Form::checkbox'),
-			'form_textarea' => new Twig_Function_Function('Form::textarea'),
-			'form_file'     => new Twig_Function_Function('Form::file'),
-			'form_button'   => new Twig_Function_Function('Form::button'),
-			'form_reset'    => new Twig_Function_Function('Form::reset'),
-			'form_submit'   => new Twig_Function_Function('Form::submit'),
-			'form_select'   => new Twig_Function_Function('Form::select'),
-			'form_label'    => new Twig_Function_Function('Form::label'),
-			'form_val'      => new Twig_Function_Function('Input::param'),
-
-			'asset_css'     => new Twig_Function_Function('Asset::css'),
-			'asset_js'      => new Twig_Function_Function('Asset::js'),
-			'asset_img'     => new Twig_Function_Function('Asset::img'),
-			'asset_render'  => new Twig_Function_Function('Asset::render'),
-		);
-	}
-
-	/**
-	 * Provides the url() functionality.  Generates a full url (including
-	 * domain and index.php).
-	 *
-	 * @param   string  URI to make a full URL for (or name of a named route)
-	 * @param   array   Array of named params for named routes
-	 * @return  string
-	 */
-	public function url($uri = '', $named_params = array())
-	{
-		if ($named_uri = Router::get($uri, $named_params))
-		{
-			$uri = $named_uri;
-		}
-
-		return Uri::create($uri);
-	}
-}

+ 0 - 112
frameworks/PHP/php-fuel/fuel/packages/parser/classes/view.php

@@ -1,112 +0,0 @@
-<?php
-/**
- * Fuel
- *
- * Fuel is a fast, lightweight, community driven PHP5 framework.
- *
- * @package    Fuel
- * @version    1.5
- * @author     Fuel Development Team
- * @license    MIT License
- * @copyright  2010 - 2013 Fuel Development Team
- * @link       http://fuelphp.com
- */
-
-namespace Parser;
-
-class View extends \Fuel\Core\View
-{
-
-	/**
-	 * @var  array  Holds the list of loaded files.
-	 */
-	protected static $loaded_files = array();
-
-	public static function _init()
-	{
-		\Config::load('parser', true);
-
-		// Get class name
-		$class = \Inflector::denamespace(get_called_class());
-
-		if ($class !== __CLASS__)
-		{
-			// Include necessary files
-			foreach ((array) \Config::get('parser.'.$class.'.include', array()) as $include)
-			{
-				if ( ! array_key_exists($include, static::$loaded_files))
-				{
-					require $include;
-					static::$loaded_files[$include] = true;
-				}
-			}
-		}
-	}
-
-	/**
-	 * Forges a new View object based on the extension
-	 *
-	 * @param   string  $file         view filename
-	 * @param   array   $data         view data
-	 * @param   bool    $auto_encode  auto encode boolean, null for default
-	 * @return  object  a new view instance
-	 */
-	public static function forge($file = null, $data = null, $auto_encode = null)
-	{
-		$class = null;
-
-		if ($file !== null)
-		{
-			$extension = pathinfo($file, PATHINFO_EXTENSION);
-
-			$class = \Config::get('parser.extensions.'.$extension, null);
-		}
-
-		if ($class === null)
-		{
-			$class = get_called_class();
-		}
-
-		// Only get rid of the extension if it is not an absolute file path
-		if ($file !== null and $file[0] !== '/' and $file[1] !== ':')
-		{
-			$file = $extension ? preg_replace('/\.'.preg_quote($extension).'$/i', '', $file) : $file;
-		}
-
-		// Class can be an array config
-		if (is_array($class))
-		{
-			$class['extension'] and $extension = $class['extension'];
-			$class = $class['class'];
-		}
-
-		// Include necessary files
-		foreach ((array) \Config::get('parser.'.$class.'.include', array()) as $include)
-		{
-			if ( ! array_key_exists($include, static::$loaded_files))
-			{
-				require $include;
-				static::$loaded_files[$include] = true;
-			}
-		}
-
-		// Instantiate the Parser class without auto-loading the view file
-		if ($auto_encode === null)
-		{
-			$auto_encode = \Config::get('parser.'.$class.'.auto_encode', null);
-		}
-
-		$view = new $class(null, $data, $auto_encode);
-
-		if ($file !== null)
-		{
-			// Set extension when given
-			$extension and $view->extension = $extension;
-
-			// Load the view file
-			$view->set_filename($file);
-		}
-
-		return $view;
-	}
-}

+ 0 - 85
frameworks/PHP/php-fuel/fuel/packages/parser/classes/view/dwoo.php

@@ -1,85 +0,0 @@
-<?php
-/**
- * Fuel
- *
- * Fuel is a fast, lightweight, community driven PHP5 framework.
- *
- * @package    Fuel
- * @version    1.5
- * @author     Fuel Development Team
- * @license    MIT License
- * @copyright  2010 - 2013 Fuel Development Team
- * @link       http://fuelphp.com
- */
-
-namespace Parser;
-
-use Dwoo;
-use Dwoo_Compiler;
-use Dwoo_Security_Policy;
-
-class View_Dwoo extends \View
-{
-	protected static $_parser;
-	protected static $_parser_compiler;
-	protected static $_parser_security;
-
-	protected function process_file($file_override = false)
-	{
-		$file = $file_override ?: $this->file_name;
-		$data = $this->get_data();
-
-		try
-		{
-			return static::parser()->get($file, $data);
-		}
-		catch (\Exception $e)
-		{
-			// Delete the output buffer & re-throw the exception
-			ob_end_clean();
-			throw $e;
-		}
-	}
-
-	public $extension = 'tpl';
-
-	/**
-	 * Returns the Parser lib object
-	 *
-	 * @return  Dwoo
-	 */
-	public static function parser()
-	{
-		if ( ! empty(static::$_parser))
-		{
-			return static::$_parser;
-		}
-
-		// Parser
-		static::$_parser = new Dwoo();
-		static::$_parser->setCacheTime(\Config::get('parser.View_Dwoo.environment.cache_time', 0));
-		static::$_parser->setCacheDir(\Config::get('parser.View_Dwoo.environment.cache_dir', APPPATH.'cache'.DS.'dwoo'.DS));
-		static::$_parser->setCompileDir(\Config::get('parser.View_Dwoo.environment.compile_dir', APPPATH.'cache'.DS.'dwoo'.DS.'compiled'.DS));
-
-		// Compiler
-		static::$_parser_compiler = new Dwoo_Compiler;
-		static::$_parser_compiler->setAutoEscape(\Config::get('parser.View_Dwoo.environment.autoescape', false));
-		static::$_parser_compiler->setLooseOpeningHandling(\Config::get('parser.View_Dwoo.environment.allow_spaces', false));
-		static::$_parser_compiler->setNestedCommentsHandling(\Config::get('parser.View_Dwoo.environment.nested_comments', false));
-		static::$_parser_compiler->setDelimiters(
-			\Config::get('parser.View_Dwoo.delimiters.left', '{'),
-			\Config::get('parser.View_Dwoo.delimiters.right', '}')
-		);
-
-		// Security
-		static::$_parser_security = new Dwoo_Security_Policy;
-		static::$_parser_security->setPhpHandling(\Config::get('parser.View_Dwoo.environment.allow_php_tags', 2));
-		static::$_parser_security->allowPhpFunction(\Config::get('parser.View_Dwoo.environment.allow_php_func', array()));
-
-		static::$_parser->setSecurityPolicy(static::$_parser_security);
-
-		return static::$_parser;
-	}
-}
-
-// end of file dwoo.php

+ 0 - 75
frameworks/PHP/php-fuel/fuel/packages/parser/classes/view/haml.php

@@ -1,75 +0,0 @@
-<?php
-/**
- * Fuel
- *
- * Fuel is a fast, lightweight, community driven PHP5 framework.
- *
- * @package    Fuel
- * @version    1.5
- * @author     Fuel Development Team
- * @license    MIT License
- * @copyright  2010 - 2013 Fuel Development Team
- * @link       http://fuelphp.com
- */
-
-namespace Parser;
-
-use HamlParser;
-
-class View_Haml extends \View
-{
-
-	protected static $_parser;
-	protected static $_cache;
-
-	protected function process_file($file_override = false)
-	{
-		$file = $file_override ?: $this->file_name;
-
-		static::cache_init($file);
-		$file = static::parser()->parse($file, static::$_cache);
-
-		return parent::process_file($file);
-	}
-
-	public $extension = 'haml';
-
-	/**
-	 * Returns the Parser lib object
-	 *
-	 * @return  HamlParser
-	 */
-	public static function parser()
-	{
-		if ( ! empty(static::$_parser))
-		{
-			return static::$_parser;
-		}
-
-		static::$_parser = new HamlParser();
-
-		return static::$_parser;
-	}
-
-	// Jade stores cached templates as the filename in plain text,
-	// so there is a high chance of name collisions (ex: index.jade).
-	// This function attempts to create a unique directory for each
-	// compiled template.
-	// TODO: Extend Jade's caching class?
-	public function cache_init($file_path)
-	{
-		$cache_key = md5($file_path);
-		$cache_path = \Config::get('parser.View_Haml.cache_dir', null)
-			.substr($cache_key, 0, 2).DS.substr($cache_key, 2, 2);
-
-		if ($cache_path !== null AND ! is_dir($cache_path))
-		{
-			mkdir($cache_path, 0777, true);
-		}
-
-		static::$_cache = $cache_path;
-	}
-
-}
-
-/* end of file haml.php */

+ 0 - 81
frameworks/PHP/php-fuel/fuel/packages/parser/classes/view/jade.php

@@ -1,81 +0,0 @@
-<?php
-/**
- * Fuel
- *
- * Fuel is a fast, lightweight, community driven PHP5 framework.
- *
- * @package    Fuel
- * @version    1.5
- * @author     Fuel Development Team
- * @license    MIT License
- * @copyright  2010 - 2013 Fuel Development Team
- * @link       http://fuelphp.com
- */
-
-namespace Parser;
-
-use Everzet\Jade;
-
-class View_Jade extends \View
-{
-
-	protected static $_jade;
-	protected static $_cache;
-
-	protected function process_file($file_override = false)
-	{
-		$file = $file_override ?: $this->file_name;
-		static::cache_init($file);
-
-		$file = static::parser()->cache($file);
-		return parent::process_file($file);
-	}
-
-	public $extension = 'jade';
-
-	/**
-	 * Returns the Parser lib object
-	 *
-	 * @return  Jade\Parser
-	 */
-	public static function parser()
-	{
-		if ( ! empty(static::$_parser))
-		{
-			return static::$_parser;
-		}
-
-		$parser = new Jade\Parser(new Jade\Lexer\Lexer());
-		$dumper = new Jade\Dumper\PHPDumper();
-		$dumper->registerVisitor('tag', new Jade\Visitor\AutotagsVisitor());
-		$dumper->registerFilter('javascript', new Jade\Filter\JavaScriptFilter());
-		$dumper->registerFilter('cdata', new Jade\Filter\CDATAFilter());
-		$dumper->registerFilter('php', new Jade\Filter\PHPFilter());
-		$dumper->registerFilter('style', new Jade\Filter\CSSFilter());
-
-		static::$_jade = new Jade\Jade($parser, $dumper, static::$_cache);
-
-		return static::$_jade;
-	}
-
-	// Jade stores cached templates as the filename in plain text,
-	// so there is a high chance of name collisions (ex: index.jade).
-	// This function attempts to create a unique directory for each
-	// compiled template.
-	public function cache_init($file_path)
-	{
-		$cache_key = md5($file_path);
-		$cache_path = \Config::get('parser.View_Jade.cache_dir', null)
-			.substr($cache_key, 0, 2).DS.substr($cache_key, 2, 2);
-
-		if ($cache_path !== null AND ! is_dir($cache_path))
-		{
-			mkdir($cache_path, 0777, true);
-		}
-
-		static::$_cache = $cache_path;
-	}
-
-}
-
-/* end of file jade.php */

+ 0 - 89
frameworks/PHP/php-fuel/fuel/packages/parser/classes/view/markdown.php

@@ -1,89 +0,0 @@
-<?php
-/**
- * Fuel
- *
- * Fuel is a fast, lightweight, community driven PHP5 framework.
- *
- * @package    Fuel
- * @version    1.5
- * @author     Fuel Development Team
- * @license    MIT License
- * @copyright  2010 - 2013 Fuel Development Team
- * @link       http://fuelphp.com
- */
-
-namespace Parser;
-
-class View_Markdown extends \View
-{
-
-	protected static $_parser;
-
-	protected function process_file($file_override = false)
-	{
-		$file = $file_override ?: $this->file_name;
-
-		$contents = '';
-
-		if (\Config::get('parser.View_Markdown.allow_php', false))
-		{
-			$contents = static::pre_process('php', $file, $this->get_data());
-		}
-		else
-		{
-			$contents = file_get_contents($file);
-		}
-
-		return static::parser()->transform($contents);
-	}
-
-	protected static function pre_process($_type = 'php', $_view_filename, array $_data = array())
-	{
-		if ($_type == 'php')
-		{
-			// Import the view variables to local namespace
-			$_data AND extract($_data, EXTR_REFS);
-
-			// Capture the view output
-			ob_start();
-
-			try
-			{
-				// Load the view within the current scope
-				include $_view_filename;
-			}
-			catch (\Exception $e)
-			{
-				// Delete the output buffer
-				ob_end_clean();
-
-				// Re-throw the exception
-				throw $e;
-			}
-
-			// Get the captured output and close the buffer
-			return ob_get_clean();
-		}
-	}
-
-	public $extension = 'md';
-
-	/**
-	 * Returns the Parser lib object
-	 *
-	 * @return  Markdown_Parser
-	 */
-	public static function parser()
-	{
-		static $parser = null;
-		if (is_null($parser))
-		{
-			$parser_class = \MARKDOWN_PARSER_CLASS;
-			$parser = new $parser_class;
-		}
-
-		return $parser;
-	}
-}
-
-// end of file mustache.php

+ 0 - 66
frameworks/PHP/php-fuel/fuel/packages/parser/classes/view/mustache.php

@@ -1,66 +0,0 @@
-<?php
-/**
- * Fuel
- *
- * Fuel is a fast, lightweight, community driven PHP5 framework.
- *
- * @package    Fuel
- * @version    1.5
- * @author     Fuel Development Team
- * @license    MIT License
- * @copyright  2010 - 2013 Fuel Development Team
- * @link       http://fuelphp.com
- */
-
-namespace Parser;
-
-use Mustache;
-
-class View_Mustache extends \View
-{
-	protected static $_parser;
-
-	protected function process_file($file_override = false)
-	{
-		$file = $file_override ?: $this->file_name;
-		$data = $this->get_data();
-
-		try
-		{
-			return static::parser()->render(file_get_contents($file), $data);
-		}
-		catch (\Exception $e)
-		{
-			// Delete the output buffer & re-throw the exception
-			ob_end_clean();
-			throw $e;
-		}
-	}
-
-	public $extension = 'mustache';
-
-	/**
-	 * Returns the Parser lib object
-	 *
-	 * @return  Mustache
-	 */
-	public static function parser()
-	{
-		if ( ! empty(static::$_parser))
-		{
-			return static::$_parser;
-		}
-
-		$options = array(
-			'delimiters'  => array_values(\Config::get('parser.View_Mustache.delimiters', array('{{','}}'))),
-			'charset'     => \Config::get('parser.View_Mustache.environment.charset', 'UTF-8'),
-			'pragmas'     => \Config::get('parser.View_Mustache.environment.pragmas', array()),
-		);
-
-		static::$_parser = new Mustache(null, null, null, $options);
-
-		return static::$_parser;
-	}
-}
-
-// end of file mustache.php

+ 0 - 65
frameworks/PHP/php-fuel/fuel/packages/parser/classes/view/phptal.php

@@ -1,65 +0,0 @@
-<?php
-/**
- * Fuel
- *
- * Fuel is a fast, lightweight, community driven PHP5 framework.
- *
- * @package    Fuel
- * @version    1.5
- * @author     Fuel Development Team
- * @license    MIT License
- * @copyright  2010 - 2013 Fuel Development Team
- * @link       http://fuelphp.com
- */
-
-namespace Parser;
-
-class View_Phptal extends \View
-{
-
-	protected static $_parser;
-
-	protected function process_file($file_override = false)
-	{
-		$file = $file_override ?: $this->file_name;
-
-		try
-		{
-			$parser = static::parser();
-			foreach($this->get_data() as $key => $value)
-			{
-				$parser->set($key,$value);
-			}
-			$parser->setTemplate($file);
-			return $parser->execute();
-		}
-		catch (\Exception $e)
-		{
-			// Delete the output buffer & re-throw the exception
-			ob_end_clean();
-			throw $e;
-		}
-	}
-
-	public $extension = 'phptal';
-
-	public static function parser()
-	{
-		if ( ! empty(static::$_parser))
-		{
-			return static::$_parser;
-		}
-
-		static::$_parser = new \PHPTAL();
-		static::$_parser->setEncoding(\Config::get('parser.View_Phptal.encoding', 'UTF-8'));
-		static::$_parser->setOutputMode(constant('\\'.\Config::get('parser.View_Phptal.output_mode', 'PHPTAL::XHTML')));
-		static::$_parser->setTemplateRepository(\Config::get('parser.View_Phptal.template_repository', ''));
-		static::$_parser->setPhpCodeDestination(\Config::get('parser.View_Phptal.cache_dir', APPPATH.'cache'.DS.'PHPTAL'.DS));
-		static::$_parser->setCacheLifetime(\Config::get('parser.View_Phptal.cache_lifetime', 0));
-		static::$_parser->setForceReparse(\Config::get('parser.View_Phptal.force_reparse', false));
-
-		return static::$_parser;
-	}
-}
-
-// end of file phptal.php

+ 0 - 81
frameworks/PHP/php-fuel/fuel/packages/parser/classes/view/smarty.php

@@ -1,81 +0,0 @@
-<?php
-/**
- * Fuel
- *
- * Fuel is a fast, lightweight, community driven PHP5 framework.
- *
- * @package    Fuel
- * @version    1.5
- * @author     Fuel Development Team
- * @license    MIT License
- * @copyright  2010 - 2013 Fuel Development Team
- * @link       http://fuelphp.com
- */
-
-namespace Parser;
-
-use Smarty;
-
-class View_Smarty extends \View
-{
-	protected static $_parser;
-
-	protected function process_file($file_override = false)
-	{
-		$file = $file_override ?: $this->file_name;
-
-		try
-		{
-			// Smarty doesn't support method chaining
-			$parser = static::parser();
-			$parser->assign($this->get_data());
-			return $parser->fetch($file);
-		}
-		catch (\Exception $e)
-		{
-			// Delete the output buffer & re-throw the exception
-			ob_end_clean();
-			throw $e;
-		}
-	}
-
-	public $extension = 'smarty';
-
-	/**
-	 * Returns the Parser lib object
-	 *
-	 * @return  Smarty
-	 */
-	public static function parser()
-	{
-		if ( ! empty(static::$_parser))
-		{
-			return static::$_parser;
-		}
-
-		// Parser
-		static::$_parser = new Smarty();
-		static::$_parser->template_dir      = \Config::get('parser.View_Smarty.environment.template_dir', APPPATH.'views'.DS);
-		static::$_parser->compile_dir       = \Config::get('parser.View_Smarty.environment.compile_dir', APPPATH.'tmp'.DS.'Smarty'.DS.'templates_c'.DS);
-		static::$_parser->config_dir        = \Config::get('parser.View_Smarty.environment.config_dir', APPPATH.'tmp'.DS.'Smarty'.DS.'configs'.DS);
-		static::$_parser->cache_dir         = \Config::get('parser.View_Smarty.environment.cache_dir', APPPATH.'cache'.DS.'Smarty'.DS);
-		$plugins_dir 						= \Config::get('parser.View_Smarty.environment.plugins_dir', array());
-		static::$_parser->addPluginsDir($plugins_dir);
-
-		static::$_parser->caching           = \Config::get('parser.View_Smarty.environment.caching', false);
-		static::$_parser->cache_lifetime    = \Config::get('parser.View_Smarty.environment.cache_lifetime', 0);
-		static::$_parser->force_compile     = \Config::get('parser.View_Smarty.environment.force_compile', false);
-		static::$_parser->compile_check     = \Config::get('parser.View_Smarty.environment.compile_check', true);
-		static::$_parser->debugging         = \Config::get('parser.View_Smarty.environment.debugging', false);
-
-		static::$_parser->left_delimiter    = \Config::get('parser.View_Smarty.delimiters.left', '{');
-		static::$_parser->right_delimiter   = \Config::get('parser.View_Smarty.delimiters.right', '}');
-
-		static::$_parser->autoload_filters  = \Config::get('parser.View_Smarty.environment.autoload_filters', array());
-		static::$_parser->default_modifiers = \Config::get('parser.View_Smarty.environment.default_modifiers', array());
-
-		return static::$_parser;
-	}
-}
-
-// end of file smarty.php

+ 0 - 117
frameworks/PHP/php-fuel/fuel/packages/parser/classes/view/twig.php

@@ -1,117 +0,0 @@
-<?php
-/**
- * Fuel
- *
- * Fuel is a fast, lightweight, community driven PHP5 framework.
- *
- * @package    Fuel
- * @version    1.5
- * @author     Fuel Development Team
- * @license    MIT License
- * @copyright  2010 - 2013 Fuel Development Team
- * @link       http://fuelphp.com
- */
-
-namespace Parser;
-
-use Twig_Autoloader;
-use Twig_Environment;
-use Twig_Loader_Filesystem;
-use Twig_Lexer;
-
-class View_Twig extends \View
-{
-	protected static $_parser;
-	protected static $_parser_loader;
-	protected static $_twig_lexer_conf;
-
-	public static function _init()
-	{
-		parent::_init();
-		Twig_Autoloader::register();
-	}
-
-	protected function process_file($file_override = false)
-	{
-		$file = $file_override ?: $this->file_name;
-
-		$local_data  = $this->get_data('local');
-		$global_data = $this->get_data('global');
-
-		// Extract View name/extension (ex. "template.twig")
-		$view_name = pathinfo($file, PATHINFO_BASENAME);
-
-		// Twig Loader
-		$views_paths = \Config::get('parser.View_Twig.views_paths', array(APPPATH . 'views'));
-		array_unshift($views_paths, pathinfo($file, PATHINFO_DIRNAME));
-		static::$_parser_loader = new Twig_Loader_Filesystem($views_paths);
-
-		if ( ! empty($global_data))
-		{
-			foreach ($global_data as $key => $value)
-			{
-				static::parser()->addGlobal($key, $value);
-			}
-		}
-		else
-		{
-			// Init the parser if you have no global data
-			static::parser();
-		}
-
-		$twig_lexer = new Twig_Lexer(static::$_parser, static::$_twig_lexer_conf);
-		static::$_parser->setLexer($twig_lexer);
-
-		try
-		{
-			return static::parser()->loadTemplate($view_name)->render($local_data);
-		}
-		catch (\Exception $e)
-		{
-			// Delete the output buffer & re-throw the exception
-			ob_end_clean();
-			throw $e;
-		}
-	}
-
-	public $extension = 'twig';
-
-	/**
-	 * Returns the Parser lib object
-	 *
-	 * @return  Twig_Environment
-	 */
-	public static function parser()
-	{
-		if ( ! empty(static::$_parser))
-		{
-			static::$_parser->setLoader(static::$_parser_loader);
-			return static::$_parser;
-		}
-
-		// Twig Environment
-		$twig_env_conf = \Config::get('parser.View_Twig.environment', array('optimizer' => -1));
-		static::$_parser = new Twig_Environment(static::$_parser_loader, $twig_env_conf);
-
-		foreach (\Config::get('parser.View_Twig.extensions') as $ext)
-		{
-			static::$_parser->addExtension(new $ext());
-		}
-
-		// Twig Lexer
-		static::$_twig_lexer_conf = \Config::get('parser.View_Twig.delimiters', null);
-		if (isset(static::$_twig_lexer_conf))
-		{
-			isset(static::$_twig_lexer_conf['tag_block'])
-				and static::$_twig_lexer_conf['tag_block'] = array_values(static::$_twig_lexer_conf['tag_block']);
-			isset(static::$_twig_lexer_conf['tag_comment'])
-				and static::$_twig_lexer_conf['tag_comment'] = array_values(static::$_twig_lexer_conf['tag_comment']);
-			isset(static::$_twig_lexer_conf['tag_variable'])
-				and static::$_twig_lexer_conf['tag_variable'] = array_values(static::$_twig_lexer_conf['tag_variable']);
-		}
-
-		return static::$_parser;
-	}
-}
-
-// end of file twig.php

+ 0 - 166
frameworks/PHP/php-fuel/fuel/packages/parser/config/parser.php

@@ -1,166 +0,0 @@
-<?php
-/**
- * Fuel is a fast, lightweight, community driven PHP5 framework.
- *
- * @package    Fuel
- * @version    1.5
- * @author     Fuel Development Team
- * @license    MIT License
- * @copyright  2010 - 2013 Fuel Development Team
- * @link       http://fuelphp.com
- */
-
-/**
- * NOTICE:
- *
- * If you need to make modifications to the default configuration, copy
- * this file to your app/config folder, and make them in there.
- *
- * This will allow you to upgrade fuel without losing your custom config.
- */
-
-return array(
-
-	// ------------------------------------------------------------------------
-	// Register extensions to their parsers, either classname or array config
-	// ------------------------------------------------------------------------
-	'extensions' => array(
-		'php'       => 'View',
-		'twig'      => 'View_Twig',
-		'mustache'  => 'View_Mustache',
-		'md'        => 'View_Markdown',
-		'dwoo'      => array('class' => 'View_Dwoo', 'extension' => 'tpl'),
-		'jade'      => 'View_Jade',
-		'haml'      => 'View_Haml',
-		'smarty'    => 'View_Smarty',
-		'phptal'    => 'View_Phptal',
-	),
-
-
-	// ------------------------------------------------------------------------
-	// Individual class config by classname
-	// ------------------------------------------------------------------------
-
-
-	// MARKDOWN ( http://michelf.com/projects/php-markdown/ )
-	// ------------------------------------------------------------------------
-	'View_Markdown' => array(
-		'include'      => \Package::exists('parser').'vendor'.DS.'markdown'.DS.'markdown.php',
-		'auto_encode'  => true,
-		'allow_php'    => true,
-	),
-
-	// TWIG ( http://www.twig-project.org/documentation )
-	// ------------------------------------------------------------------------
-	'View_Twig' => array(
-		'include' => APPPATH.'vendor'.DS.'Twig'.DS.'Autoloader.php',
-		'auto_encode' => true,
-		'views_paths' => array(APPPATH.'views'),
-		'delimiters' => array(
-			'tag_block'     => array('left' => '{%', 'right' => '%}'),
-			'tag_comment'   => array('left' => '{#', 'right' => '#}'),
-			'tag_variable'  => array('left' => '{{', 'right' => '}}'),
-		),
-		'environment' => array(
-			'debug'                => false,
-			'charset'              => 'utf-8',
-			'base_template_class'  => 'Twig_Template',
-			'cache'                => APPPATH.'cache'.DS.'twig'.DS,
-			'auto_reload'          => true,
-			'strict_variables'     => false,
-			'autoescape'           => false,
-			'optimizations'        => -1,
-		),
-		'extensions' => array(
-			'Twig_Fuel_Extension'
-		),
-	),
-
-	// DWOO ( http://wiki.dwoo.org/ )
-	// ------------------------------------------------------------------------
-	'View_Dwoo' => array(
-		'include' => APPPATH.'vendor'.DS.'Dwoo'.DS.'dwooAutoload.php',
-		'auto_encode' => true,
-		'delimiters' => array('left' => '{{', 'right' => '}}'),
-		'environment' => array(
-			'autoescape'       => false,
-			'nested_comments'  => false,
-			'allow_spaces'     => false,
-			'cache_dir'        => APPPATH.'cache'.DS.'dwoo'.DS,
-			'compile_dir'      => APPPATH.'cache'.DS.'dwoo'.DS.'compiled'.DS,
-			'cache_time'       => 0,
-
-			// Set what parser should do with PHP tags
-			// 1 - Encode tags | 2 - Remove tags | 3 - Allow tags
-			'allow_php_tags'   => 2,
-
-			// Which PHP functions should be accessible through Parser
-			'allow_php_func'   => array(),
-		),
-	),
-
-	// MUSTACHE ( https://github.com/bobthecow/mustache.php )
-	// ------------------------------------------------------------------------
-	'View_Mustache' => array(
-		'include' => \Package::exists('parser').'vendor'.DS.'Mustache'.DS.'Mustache.php',
-		'auto_encode' => true,
-		'delimiters' => array('left' => '{{', 'right' => '}}'),
-		'environment' => array(
-			'charset' => 'UTF-8',
-			'pragmas' => array(),
-		),
-	),
-
-	// JADE PHP ( https://github.com/everzet/jade.php )
-	// See notes in /parser/classes/view/jade.php
-	// ------------------------------------------------------------------------
-	'View_Jade' => array(
-		'include'      => APPPATH.'vendor'.DS.'Jade'.DS.'autoload.php.dist',
-		'auto_encode'  => true,
-		'cache_dir'    => APPPATH.'cache'.DS.'jade'.DS,
-	),
-
-	// HAML / PHAMLP ( http://code.google.com/p/phamlp/ )
-	// ------------------------------------------------------------------------
-	'View_Haml'   => array(
-		'include'      => APPPATH.'vendor'.DS.'Phamlp'.DS.'haml'.DS.'HamlParser.php',
-		'auto_encode'  => true,
-		'cache_dir'    => APPPATH.'cache'.DS.'haml'.DS,
-	),
-
-	// SMARTY ( http://www.smarty.net/documentation )
-	// ------------------------------------------------------------------------
-	'View_Smarty'   => array(
-		'include'       => APPPATH.'vendor'.DS.'Smarty'.DS.'libs'.DS.'Smarty.class.php',
-		'auto_encode' => true,
-		'delimiters'    => array('left' => '{', 'right' => '}'),
-		'environment'   => array(
-			'compile_dir'       => APPPATH.'tmp'.DS.'Smarty'.DS.'templates_c'.DS,
-			'config_dir'        => APPPATH.'tmp'.DS.'Smarty'.DS.'configs'.DS,
-			'cache_dir'         => APPPATH.'cache'.DS.'Smarty'.DS,
-			'plugins_dir'       => array(),
-			'caching'           => false,
-			'cache_lifetime'    => 0,
-			'force_compile'     => false,
-			'compile_check'     => true,
-			'debugging'         => false,
-			'autoload_filters'  => array(),
-			'default_modifiers' => array(),
-		),
-	),
-
-	// Phptal ( http://phptal.org/manual/en/ )
-	// ------------------------------------------------------------------------
-	'View_Phptal'   => array(
-		'include'   => APPPATH.'vendor'.DS.'PHPTAL'.DS.'PHPTAL.php',
-		'auto_encode' => true,
-		'cache_dir' => APPPATH.'cache'.DS.'PHPTAL'.DS,
-		'cache_lifetime' => 0,
-		'encoding' => 'UTF-8',
-		'output_mode' => 'PHPTAL::XHTML',
-		'template_repository' => '',
-		'force_reparse' => false,
-	),
-);
-
-// end of file parser.php

+ 0 - 22
frameworks/PHP/php-fuel/fuel/packages/parser/vendor/Mustache/LICENSE

@@ -1,22 +0,0 @@
-Copyright (c) 2010 Justin Hileman
-
-Permission is hereby granted, free of charge, to any person
-obtaining a copy of this software and associated documentation
-files (the "Software"), to deal in the Software without
-restriction, including without limitation the rights to use,
-copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the
-Software is furnished to do so, subject to the following
-conditions:
-
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-OTHER DEALINGS IN THE SOFTWARE.

+ 0 - 861
frameworks/PHP/php-fuel/fuel/packages/parser/vendor/Mustache/Mustache.php

@@ -1,861 +0,0 @@
-<?php
-
-/**
- * A Mustache implementation in PHP.
- *
- * {@link http://defunkt.github.com/mustache}
- *
- * Mustache is a framework-agnostic logic-less templating language. It enforces separation of view
- * logic from template files. In fact, it is not even possible to embed logic in the template.
- *
- * This is very, very rad.
- *
- * @author Justin Hileman {@link http://justinhileman.com}
- */
-class Mustache {
-
-	const VERSION = '0.7.1';
-
-	/**
-	 * Should this Mustache throw exceptions when it finds unexpected tags?
-	 *
-	 * @see self::_throwsException()
-	 */
-	protected $_throwsExceptions = array(
-		MustacheException::UNKNOWN_VARIABLE         => false,
-		MustacheException::UNCLOSED_SECTION         => true,
-		MustacheException::UNEXPECTED_CLOSE_SECTION => true,
-		MustacheException::UNKNOWN_PARTIAL          => false,
-		MustacheException::UNKNOWN_PRAGMA           => true,
-	);
-
-	// Override charset passed to htmlentities() and htmlspecialchars(). Defaults to UTF-8.
-	protected $_charset = 'UTF-8';
-
-	/**
-	 * Pragmas are macro-like directives that, when invoked, change the behavior or
-	 * syntax of Mustache.
-	 *
-	 * They should be considered extremely experimental. Most likely their implementation
-	 * will change in the future.
-	 */
-
-	/**
-	 * The {{%UNESCAPED}} pragma swaps the meaning of the {{normal}} and {{{unescaped}}}
-	 * Mustache tags. That is, once this pragma is activated the {{normal}} tag will not be
-	 * escaped while the {{{unescaped}}} tag will be escaped.
-	 *
-	 * Pragmas apply only to the current template. Partials, even those included after the
-	 * {{%UNESCAPED}} call, will need their own pragma declaration.
-	 *
-	 * This may be useful in non-HTML Mustache situations.
-	 */
-	const PRAGMA_UNESCAPED    = 'UNESCAPED';
-
-	/**
-	 * Constants used for section and tag RegEx
-	 */
-	const SECTION_TYPES = '\^#\/';
-	const TAG_TYPES = '#\^\/=!<>\\{&';
-
-	protected $_otag = '{{';
-	protected $_ctag = '}}';
-
-	protected $_tagRegEx;
-
-	protected $_template = '';
-	protected $_context  = array();
-	protected $_partials = array();
-	protected $_pragmas  = array();
-
-	protected $_pragmasImplemented = array(
-		self::PRAGMA_UNESCAPED
-	);
-
-	protected $_localPragmas = array();
-
-	/**
-	 * Mustache class constructor.
-	 *
-	 * This method accepts a $template string and a $view object. Optionally, pass an associative
-	 * array of partials as well.
-	 *
-	 * Passing an $options array allows overriding certain Mustache options during instantiation:
-	 *
-	 *     $options = array(
-	 *         // `charset` -- must be supported by `htmlspecialentities()`. defaults to 'UTF-8'
-	 *         'charset' => 'ISO-8859-1',
-	 *
-	 *         // opening and closing delimiters, as an array or a space-separated string
-	 *         'delimiters' => '<% %>',
-	 *
-	 *         // an array of pragmas to enable
-	 *         'pragmas' => array(
-	 *             Mustache::PRAGMA_UNESCAPED
-	 *         ),
-	 *     );
-	 *
-	 * @access public
-	 * @param string $template (default: null)
-	 * @param mixed $view (default: null)
-	 * @param array $partials (default: null)
-	 * @param array $options (default: array())
-	 * @return void
-	 */
-	public function __construct($template = null, $view = null, $partials = null, array $options = null) {
-		if ($template !== null) $this->_template = $template;
-		if ($partials !== null) $this->_partials = $partials;
-		if ($view !== null)     $this->_context = array($view);
-		if ($options !== null)  $this->_setOptions($options);
-	}
-
-	/**
-	 * Helper function for setting options from constructor args.
-	 *
-	 * @access protected
-	 * @param array $options
-	 * @return void
-	 */
-	protected function _setOptions(array $options) {
-		if (isset($options['charset'])) {
-			$this->_charset = $options['charset'];
-		}
-
-		if (isset($options['delimiters'])) {
-			$delims = $options['delimiters'];
-			if (!is_array($delims)) {
-				$delims = array_map('trim', explode(' ', $delims, 2));
-			}
-			$this->_otag = $delims[0];
-			$this->_ctag = $delims[1];
-		}
-
-		if (isset($options['pragmas'])) {
-			foreach ($options['pragmas'] as $pragma_name) {
-				if (!in_array($pragma_name, $this->_pragmasImplemented)) {
-					throw new MustacheException('Unknown pragma: ' . $pragma_name, MustacheException::UNKNOWN_PRAGMA);
-				}
-			}
-			$this->_pragmas = $options['pragmas'];
-		}
-	}
-
-	/**
-	 * Mustache class clone method.
-	 *
-	 * A cloned Mustache instance should have pragmas, delimeters and root context
-	 * reset to default values.
-	 *
-	 * @access public
-	 * @return void
-	 */
-	public function __clone() {
-		$this->_otag = '{{';
-		$this->_ctag = '}}';
-		$this->_localPragmas = array();
-
-		if ($keys = array_keys($this->_context)) {
-			$last = array_pop($keys);
-			if ($this->_context[$last] instanceof Mustache) {
-				$this->_context[$last] =& $this;
-			}
-		}
-	}
-
-	/**
-	 * Render the given template and view object.
-	 *
-	 * Defaults to the template and view passed to the class constructor unless a new one is provided.
-	 * Optionally, pass an associative array of partials as well.
-	 *
-	 * @access public
-	 * @param string $template (default: null)
-	 * @param mixed $view (default: null)
-	 * @param array $partials (default: null)
-	 * @return string Rendered Mustache template.
-	 */
-	public function render($template = null, $view = null, $partials = null) {
-		if ($template === null) $template = $this->_template;
-		if ($partials !== null) $this->_partials = $partials;
-
-		$otag_orig = $this->_otag;
-		$ctag_orig = $this->_ctag;
-
-		if ($view) {
-			$this->_context = array($view);
-		} else if (empty($this->_context)) {
-			$this->_context = array($this);
-		}
-
-		$template = $this->_renderPragmas($template);
-		$template = $this->_renderTemplate($template, $this->_context);
-
-		$this->_otag = $otag_orig;
-		$this->_ctag = $ctag_orig;
-
-		return $template;
-	}
-
-	/**
-	 * Wrap the render() function for string conversion.
-	 *
-	 * @access public
-	 * @return string
-	 */
-	public function __toString() {
-		// PHP doesn't like exceptions in __toString.
-		// catch any exceptions and convert them to strings.
-		try {
-			$result = $this->render();
-			return $result;
-		} catch (Exception $e) {
-			return "Error rendering mustache: " . $e->getMessage();
-		}
-	}
-
-	/**
-	 * Internal render function, used for recursive calls.
-	 *
-	 * @access protected
-	 * @param string $template
-	 * @return string Rendered Mustache template.
-	 */
-	protected function _renderTemplate($template) {
-		if ($section = $this->_findSection($template)) {
-			list($before, $type, $tag_name, $content, $after) = $section;
-
-			$rendered_before = $this->_renderTags($before);
-
-			$rendered_content = '';
-			$val = $this->_getVariable($tag_name);
-			switch($type) {
-				// inverted section
-				case '^':
-					if (empty($val)) {
-						$rendered_content = $this->_renderTemplate($content);
-					}
-					break;
-
-				// regular section
-				case '#':
-					if ($this->_varIsIterable($val)) {
-						foreach ($val as $local_context) {
-							$this->_pushContext($local_context);
-							$rendered_content .= $this->_renderTemplate($content);
-							$this->_popContext();
-						}
-					} else if ($val) {
-						if (is_array($val) || is_object($val)) {
-							$this->_pushContext($val);
-							$rendered_content = $this->_renderTemplate($content);
-							$this->_popContext();
-						} else {
-							$rendered_content = $this->_renderTemplate($content);
-						}
-					}
-					break;
-			}
-
-			return $rendered_before . $rendered_content . $this->_renderTemplate($after);
-		}
-
-		return $this->_renderTags($template);
-	}
-
-	/**
-	 * Prepare a section RegEx string for the given opening/closing tags.
-	 *
-	 * @access protected
-	 * @param string $otag
-	 * @param string $ctag
-	 * @return string
-	 */
-	protected function _prepareSectionRegEx($otag, $ctag) {
-		return sprintf(
-			'/(?:(?<=\\n)[ \\t]*)?%s(?:(?P<type>[%s])(?P<tag_name>.+?)|=(?P<delims>.*?)=)%s\\n?/s',
-			preg_quote($otag, '/'),
-			self::SECTION_TYPES,
-			preg_quote($ctag, '/')
-		);
-	}
-
-	/**
-	 * Extract the first section from $template.
-	 *
-	 * @access protected
-	 * @param string $template
-	 * @return array $before, $type, $tag_name, $content and $after
-	 */
-	protected function _findSection($template) {
-		$regEx = $this->_prepareSectionRegEx($this->_otag, $this->_ctag);
-
-		$section_start = null;
-		$section_type  = null;
-		$content_start = null;
-
-		$search_offset = 0;
-
-		$section_stack = array();
-		$matches = array();
-		while (preg_match($regEx, $template, $matches, PREG_OFFSET_CAPTURE, $search_offset)) {
-			if (isset($matches['delims'][0])) {
-				list($otag, $ctag) = explode(' ', $matches['delims'][0]);
-				$regEx = $this->_prepareSectionRegEx($otag, $ctag);
-				$search_offset = $matches[0][1] + strlen($matches[0][0]);
-				continue;
-			}
-
-			$match    = $matches[0][0];
-			$offset   = $matches[0][1];
-			$type     = $matches['type'][0];
-			$tag_name = trim($matches['tag_name'][0]);
-
-			$search_offset = $offset + strlen($match);
-
-			switch ($type) {
-				case '^':
-				case '#':
-					if (empty($section_stack)) {
-						$section_start = $offset;
-						$section_type  = $type;
-						$content_start = $search_offset;
-					}
-					array_push($section_stack, $tag_name);
-					break;
-				case '/':
-					if (empty($section_stack) || ($tag_name !== array_pop($section_stack))) {
-						if ($this->_throwsException(MustacheException::UNEXPECTED_CLOSE_SECTION)) {
-							throw new MustacheException('Unexpected close section: ' . $tag_name, MustacheException::UNEXPECTED_CLOSE_SECTION);
-						}
-					}
-
-					if (empty($section_stack)) {
-						// $before, $type, $tag_name, $content, $after
-						return array(
-							substr($template, 0, $section_start),
-							$section_type,
-							$tag_name,
-							substr($template, $content_start, $offset - $content_start),
-							substr($template, $search_offset),
-						);
-					}
-					break;
-			}
-		}
-
-		if (!empty($section_stack)) {
-			if ($this->_throwsException(MustacheException::UNCLOSED_SECTION)) {
-				throw new MustacheException('Unclosed section: ' . $section_stack[0], MustacheException::UNCLOSED_SECTION);
-			}
-		}
-	}
-
-	/**
-	 * Prepare a pragma RegEx for the given opening/closing tags.
-	 *
-	 * @access protected
-	 * @param string $otag
-	 * @param string $ctag
-	 * @return string
-	 */
-	protected function _preparePragmaRegEx($otag, $ctag) {
-		return sprintf(
-			'/%s%%\\s*(?P<pragma_name>[\\w_-]+)(?P<options_string>(?: [\\w]+=[\\w]+)*)\\s*%s\\n?/s',
-			preg_quote($otag, '/'),
-			preg_quote($ctag, '/')
-		);
-	}
-
-	/**
-	 * Initialize pragmas and remove all pragma tags.
-	 *
-	 * @access protected
-	 * @param string $template
-	 * @return string
-	 */
-	protected function _renderPragmas($template) {
-		$this->_localPragmas = $this->_pragmas;
-
-		// no pragmas
-		if (strpos($template, $this->_otag . '%') === false) {
-			return $template;
-		}
-
-		$regEx = $this->_preparePragmaRegEx($this->_otag, $this->_ctag);
-		return preg_replace_callback($regEx, array($this, '_renderPragma'), $template);
-	}
-
-	/**
-	 * A preg_replace helper to remove {{%PRAGMA}} tags and enable requested pragma.
-	 *
-	 * @access protected
-	 * @param mixed $matches
-	 * @return void
-	 * @throws MustacheException unknown pragma
-	 */
-	protected function _renderPragma($matches) {
-		$pragma         = $matches[0];
-		$pragma_name    = $matches['pragma_name'];
-		$options_string = $matches['options_string'];
-
-		if (!in_array($pragma_name, $this->_pragmasImplemented)) {
-			throw new MustacheException('Unknown pragma: ' . $pragma_name, MustacheException::UNKNOWN_PRAGMA);
-		}
-
-		$options = array();
-		foreach (explode(' ', trim($options_string)) as $o) {
-			if ($p = trim($o)) {
-				$p = explode('=', $p);
-				$options[$p[0]] = $p[1];
-			}
-		}
-
-		if (empty($options)) {
-			$this->_localPragmas[$pragma_name] = true;
-		} else {
-			$this->_localPragmas[$pragma_name] = $options;
-		}
-
-		return '';
-	}
-
-	/**
-	 * Check whether this Mustache has a specific pragma.
-	 *
-	 * @access protected
-	 * @param string $pragma_name
-	 * @return bool
-	 */
-	protected function _hasPragma($pragma_name) {
-		if (array_key_exists($pragma_name, $this->_localPragmas) && $this->_localPragmas[$pragma_name]) {
-			return true;
-		} else {
-			return false;
-		}
-	}
-
-	/**
-	 * Return pragma options, if any.
-	 *
-	 * @access protected
-	 * @param string $pragma_name
-	 * @return mixed
-	 * @throws MustacheException Unknown pragma
-	 */
-	protected function _getPragmaOptions($pragma_name) {
-		if (!$this->_hasPragma($pragma_name)) {
-			throw new MustacheException('Unknown pragma: ' . $pragma_name, MustacheException::UNKNOWN_PRAGMA);
-		}
-
-		return (is_array($this->_localPragmas[$pragma_name])) ? $this->_localPragmas[$pragma_name] : array();
-	}
-
-	/**
-	 * Check whether this Mustache instance throws a given exception.
-	 *
-	 * Expects exceptions to be MustacheException error codes (i.e. class constants).
-	 *
-	 * @access protected
-	 * @param mixed $exception
-	 * @return void
-	 */
-	protected function _throwsException($exception) {
-		return (isset($this->_throwsExceptions[$exception]) && $this->_throwsExceptions[$exception]);
-	}
-
-	/**
-	 * Prepare a tag RegEx for the given opening/closing tags.
-	 *
-	 * @access protected
-	 * @param string $otag
-	 * @param string $ctag
-	 * @return string
-	 */
-	protected function _prepareTagRegEx($otag, $ctag, $first = false) {
-		return sprintf(
-			'/(?P<leading>(?:%s\\r?\\n)[ \\t]*)?%s(?P<type>[%s]?)(?P<tag_name>.+?)(?:\\2|})?%s(?P<trailing>\\s*(?:\\r?\\n|\\Z))?/s',
-			($first ? '\\A|' : ''),
-			preg_quote($otag, '/'),
-			self::TAG_TYPES,
-			preg_quote($ctag, '/')
-		);
-	}
-
-	/**
-	 * Loop through and render individual Mustache tags.
-	 *
-	 * @access protected
-	 * @param string $template
-	 * @return void
-	 */
-	protected function _renderTags($template) {
-		if (strpos($template, $this->_otag) === false) {
-			return $template;
-		}
-
-		$first = true;
-		$this->_tagRegEx = $this->_prepareTagRegEx($this->_otag, $this->_ctag, true);
-
-		$html = '';
-		$matches = array();
-		while (preg_match($this->_tagRegEx, $template, $matches, PREG_OFFSET_CAPTURE)) {
-			$tag      = $matches[0][0];
-			$offset   = $matches[0][1];
-			$modifier = $matches['type'][0];
-			$tag_name = trim($matches['tag_name'][0]);
-
-			if (isset($matches['leading']) && $matches['leading'][1] > -1) {
-				$leading = $matches['leading'][0];
-			} else {
-				$leading = null;
-			}
-
-			if (isset($matches['trailing']) && $matches['trailing'][1] > -1) {
-				$trailing = $matches['trailing'][0];
-			} else {
-				$trailing = null;
-			}
-
-			$html .= substr($template, 0, $offset);
-
-			$next_offset = $offset + strlen($tag);
-			if ((substr($html, -1) == "\n") && (substr($template, $next_offset, 1) == "\n")) {
-				$next_offset++;
-			}
-			$template = substr($template, $next_offset);
-
-			$html .= $this->_renderTag($modifier, $tag_name, $leading, $trailing);
-
-			if ($first == true) {
-				$first = false;
-				$this->_tagRegEx = $this->_prepareTagRegEx($this->_otag, $this->_ctag);
-			}
-		}
-
-		return $html . $template;
-	}
-
-	/**
-	 * Render the named tag, given the specified modifier.
-	 *
-	 * Accepted modifiers are `=` (change delimiter), `!` (comment), `>` (partial)
-	 * `{` or `&` (don't escape output), or none (render escaped output).
-	 *
-	 * @access protected
-	 * @param string $modifier
-	 * @param string $tag_name
-	 * @param string $leading Whitespace
-	 * @param string $trailing Whitespace
-	 * @throws MustacheException Unmatched section tag encountered.
-	 * @return string
-	 */
-	protected function _renderTag($modifier, $tag_name, $leading, $trailing) {
-		switch ($modifier) {
-			case '=':
-				return $this->_changeDelimiter($tag_name, $leading, $trailing);
-				break;
-			case '!':
-				return $this->_renderComment($tag_name, $leading, $trailing);
-				break;
-			case '>':
-			case '<':
-				return $this->_renderPartial($tag_name, $leading, $trailing);
-				break;
-			case '{':
-				// strip the trailing } ...
-				if ($tag_name[(strlen($tag_name) - 1)] == '}') {
-					$tag_name = substr($tag_name, 0, -1);
-				}
-			case '&':
-				if ($this->_hasPragma(self::PRAGMA_UNESCAPED)) {
-					return $this->_renderEscaped($tag_name, $leading, $trailing);
-				} else {
-					return $this->_renderUnescaped($tag_name, $leading, $trailing);
-				}
-				break;
-			case '#':
-			case '^':
-			case '/':
-				// remove any leftover section tags
-				return $leading . $trailing;
-				break;
-			default:
-				if ($this->_hasPragma(self::PRAGMA_UNESCAPED)) {
-					return $this->_renderUnescaped($modifier . $tag_name, $leading, $trailing);
-				} else {
-					return $this->_renderEscaped($modifier . $tag_name, $leading, $trailing);
-				}
-				break;
-		}
-	}
-
-	/**
-	 * Returns true if any of its args contains the "\r" character.
-	 *
-	 * @access protected
-	 * @param string $str
-	 * @return boolean
-	 */
-	protected function _stringHasR($str) {
-		foreach (func_get_args() as $arg) {
-			if (strpos($arg, "\r") !== false) {
-				return true;
-			}
-		}
-		return false;
-	}
-
-	/**
-	 * Escape and return the requested tag.
-	 *
-	 * @access protected
-	 * @param string $tag_name
-	 * @param string $leading Whitespace
-	 * @param string $trailing Whitespace
-	 * @return string
-	 */
-	protected function _renderEscaped($tag_name, $leading, $trailing) {
-		return $leading . htmlentities($this->_getVariable($tag_name), ENT_COMPAT, $this->_charset) . $trailing;
-	}
-
-	/**
-	 * Render a comment (i.e. return an empty string).
-	 *
-	 * @access protected
-	 * @param string $tag_name
-	 * @param string $leading Whitespace
-	 * @param string $trailing Whitespace
-	 * @return string
-	 */
-	protected function _renderComment($tag_name, $leading, $trailing) {
-		if ($leading !== null && $trailing !== null) {
-			if (strpos($leading, "\n") === false) {
-				return '';
-			}
-			return $this->_stringHasR($leading, $trailing) ? "\r\n" : "\n";
-		}
-		return $leading . $trailing;
-	}
-
-	/**
-	 * Return the requested tag unescaped.
-	 *
-	 * @access protected
-	 * @param string $tag_name
-	 * @param string $leading Whitespace
-	 * @param string $trailing Whitespace
-	 * @return string
-	 */
-	protected function _renderUnescaped($tag_name, $leading, $trailing) {
-		return $leading . $this->_getVariable($tag_name) . $trailing;
-	}
-
-	/**
-	 * Render the requested partial.
-	 *
-	 * @access protected
-	 * @param string $tag_name
-	 * @param string $leading Whitespace
-	 * @param string $trailing Whitespace
-	 * @return string
-	 */
-	protected function _renderPartial($tag_name, $leading, $trailing) {
-		$partial = $this->_getPartial($tag_name);
-		if ($leading !== null && $trailing !== null) {
-			$whitespace = trim($leading, "\r\n");
-			$partial = preg_replace('/(\\r?\\n)(?!$)/s', "\\1" . $whitespace, $partial);
-		}
-
-		$view = clone($this);
-
-		if ($leading !== null && $trailing !== null) {
-			return $leading . $view->render($partial);
-		} else {
-			return $leading . $view->render($partial) . $trailing;
-		}
-	}
-
-	/**
-	 * Change the Mustache tag delimiter. This method also replaces this object's current
-	 * tag RegEx with one using the new delimiters.
-	 *
-	 * @access protected
-	 * @param string $tag_name
-	 * @param string $leading Whitespace
-	 * @param string $trailing Whitespace
-	 * @return string
-	 */
-	protected function _changeDelimiter($tag_name, $leading, $trailing) {
-		list($otag, $ctag) = explode(' ', $tag_name);
-		$this->_otag = $otag;
-		$this->_ctag = $ctag;
-
-		$this->_tagRegEx = $this->_prepareTagRegEx($this->_otag, $this->_ctag);
-
-		if ($leading !== null && $trailing !== null) {
-			if (strpos($leading, "\n") === false) {
-				return '';
-			}
-			return $this->_stringHasR($leading, $trailing) ? "\r\n" : "\n";
-		}
-		return $leading . $trailing;
-	}
-
-	/**
-	 * Push a local context onto the stack.
-	 *
-	 * @access protected
-	 * @param array &$local_context
-	 * @return void
-	 */
-	protected function _pushContext(&$local_context) {
-		$new = array();
-		$new[] =& $local_context;
-		foreach (array_keys($this->_context) as $key) {
-			$new[] =& $this->_context[$key];
-		}
-		$this->_context = $new;
-	}
-
-	/**
-	 * Remove the latest context from the stack.
-	 *
-	 * @access protected
-	 * @return void
-	 */
-	protected function _popContext() {
-		$new = array();
-
-		$keys = array_keys($this->_context);
-		array_shift($keys);
-		foreach ($keys as $key) {
-			$new[] =& $this->_context[$key];
-		}
-		$this->_context = $new;
-	}
-
-	/**
-	 * Get a variable from the context array.
-	 *
-	 * If the view is an array, returns the value with array key $tag_name.
-	 * If the view is an object, this will check for a public member variable
-	 * named $tag_name. If none is available, this method will execute and return
-	 * any class method named $tag_name. Failing all of the above, this method will
-	 * return an empty string.
-	 *
-	 * @access protected
-	 * @param string $tag_name
-	 * @throws MustacheException Unknown variable name.
-	 * @return string
-	 */
-	protected function _getVariable($tag_name) {
-		if ($tag_name === '.') {
-			return $this->_context[0];
-		} else if (strpos($tag_name, '.') !== false) {
-			$chunks = explode('.', $tag_name);
-			$first = array_shift($chunks);
-
-			$ret = $this->_findVariableInContext($first, $this->_context);
-			while ($next = array_shift($chunks)) {
-				// Slice off a chunk of context for dot notation traversal.
-				$c = array($ret);
-				$ret = $this->_findVariableInContext($next, $c);
-			}
-			return $ret;
-		} else {
-			return $this->_findVariableInContext($tag_name, $this->_context);
-		}
-	}
-
-	/**
-	 * Get a variable from the context array. Internal helper used by getVariable() to abstract
-	 * variable traversal for dot notation.
-	 *
-	 * @access protected
-	 * @param string $tag_name
-	 * @param array $context
-	 * @throws MustacheException Unknown variable name.
-	 * @return string
-	 */
-	protected function _findVariableInContext($tag_name, $context) {
-		foreach ($context as $view) {
-			if (is_object($view)) {
-				if (method_exists($view, $tag_name)) {
-					return $view->$tag_name();
-				} else if (isset($view->$tag_name)) {
-					return $view->$tag_name;
-				}
-			} else if (is_array($view) && array_key_exists($tag_name, $view)) {
-				return $view[$tag_name];
-			}
-		}
-
-		if ($this->_throwsException(MustacheException::UNKNOWN_VARIABLE)) {
-			throw new MustacheException("Unknown variable: " . $tag_name, MustacheException::UNKNOWN_VARIABLE);
-		} else {
-			return '';
-		}
-	}
-
-	/**
-	 * Retrieve the partial corresponding to the requested tag name.
-	 *
-	 * Silently fails (i.e. returns '') when the requested partial is not found.
-	 *
-	 * @access protected
-	 * @param string $tag_name
-	 * @throws MustacheException Unknown partial name.
-	 * @return string
-	 */
-	protected function _getPartial($tag_name) {
-		if (is_array($this->_partials) && isset($this->_partials[$tag_name])) {
-			return $this->_partials[$tag_name];
-		}
-
-		if ($this->_throwsException(MustacheException::UNKNOWN_PARTIAL)) {
-			throw new MustacheException('Unknown partial: ' . $tag_name, MustacheException::UNKNOWN_PARTIAL);
-		} else {
-			return '';
-		}
-	}
-
-	/**
-	 * Check whether the given $var should be iterated (i.e. in a section context).
-	 *
-	 * @access protected
-	 * @param mixed $var
-	 * @return bool
-	 */
-	protected function _varIsIterable($var) {
-		return $var instanceof Traversable || (is_array($var) && !array_diff_key($var, array_keys(array_keys($var))));
-	}
-}
-
-
-/**
- * MustacheException class.
- *
- * @extends Exception
- */
-class MustacheException extends Exception {
-
-	// An UNKNOWN_VARIABLE exception is thrown when a {{variable}} is not found
-	// in the current context.
-	const UNKNOWN_VARIABLE         = 0;
-
-	// An UNCLOSED_SECTION exception is thrown when a {{#section}} is not closed.
-	const UNCLOSED_SECTION         = 1;
-
-	// An UNEXPECTED_CLOSE_SECTION exception is thrown when {{/section}} appears
-	// without a corresponding {{#section}} or {{^section}}.
-	const UNEXPECTED_CLOSE_SECTION = 2;
-
-	// An UNKNOWN_PARTIAL exception is thrown whenever a {{>partial}} tag appears
-	// with no associated partial.
-	const UNKNOWN_PARTIAL          = 3;
-
-	// An UNKNOWN_PRAGMA exception is thrown whenever a {{%PRAGMA}} tag appears
-	// which can't be handled by this Mustache instance.
-	const UNKNOWN_PRAGMA           = 4;
-
-}

+ 0 - 36
frameworks/PHP/php-fuel/fuel/packages/parser/vendor/markdown/License.text

@@ -1,36 +0,0 @@
-PHP Markdown & Extra  
-Copyright (c) 2004-2009 Michel Fortin  
-<http://michelf.com/>  
-All rights reserved.
-
-Based on Markdown  
-Copyright (c) 2003-2006 John Gruber   
-<http://daringfireball.net/>   
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
-* Redistributions of source code must retain the above copyright notice,
-  this list of conditions and the following disclaimer.
-
-* Redistributions in binary form must reproduce the above copyright
-  notice, this list of conditions and the following disclaimer in the
-  documentation and/or other materials provided with the distribution.
-
-* Neither the name "Markdown" nor the names of its contributors may
-  be used to endorse or promote products derived from this software
-  without specific prior written permission.
-
-This software is provided by the copyright holders and contributors "as
-is" and any express or implied warranties, including, but not limited
-to, the implied warranties of merchantability and fitness for a
-particular purpose are disclaimed. In no event shall the copyright owner
-or contributors be liable for any direct, indirect, incidental, special,
-exemplary, or consequential damages (including, but not limited to,
-procurement of substitute goods or services; loss of use, data, or
-profits; or business interruption) however caused and on any theory of
-liability, whether in contract, strict liability, or tort (including
-negligence or otherwise) arising in any way out of the use of this
-software, even if advised of the possibility of such damage.

+ 0 - 2931
frameworks/PHP/php-fuel/fuel/packages/parser/vendor/markdown/markdown.php

@@ -1,2931 +0,0 @@
-<?php
-#
-# Markdown Extra  -  A text-to-HTML conversion tool for web writers
-#
-# PHP Markdown & Extra
-# Copyright (c) 2004-2012 Michel Fortin
-# <http://michelf.com/projects/php-markdown/>
-#
-# Original Markdown
-# Copyright (c) 2004-2006 John Gruber
-# <http://daringfireball.net/projects/markdown/>
-#
-
-
-define( 'MARKDOWN_VERSION',  "1.0.1o" ); # Sun 8 Jan 2012
-define( 'MARKDOWNEXTRA_VERSION',  "1.2.5" ); # Sun 8 Jan 2012
-
-
-#
-# Global default settings:
-#
-
-# Change to ">" for HTML output
-@define( 'MARKDOWN_EMPTY_ELEMENT_SUFFIX',  " />");
-
-# Define the width of a tab for code blocks.
-@define( 'MARKDOWN_TAB_WIDTH',     4 );
-
-# Optional title attribute for footnote links and backlinks.
-@define( 'MARKDOWN_FN_LINK_TITLE',         "" );
-@define( 'MARKDOWN_FN_BACKLINK_TITLE',     "" );
-
-# Optional class attribute for footnote links and backlinks.
-@define( 'MARKDOWN_FN_LINK_CLASS',         "" );
-@define( 'MARKDOWN_FN_BACKLINK_CLASS',     "" );
-
-
-#
-# WordPress settings:
-#
-
-# Change to false to remove Markdown from posts and/or comments.
-@define( 'MARKDOWN_WP_POSTS',      true );
-@define( 'MARKDOWN_WP_COMMENTS',   true );
-
-
-
-### Standard Function Interface ###
-
-@define( 'MARKDOWN_PARSER_CLASS',  'MarkdownExtra_Parser' );
-
-function Markdown($text) {
-#
-# Initialize the parser and return the result of its transform method.
-#
-	# Setup static parser variable.
-	static $parser;
-	if (!isset($parser)) {
-		$parser_class = MARKDOWN_PARSER_CLASS;
-		$parser = new $parser_class;
-	}
-
-	# Transform text using parser.
-	return $parser->transform($text);
-}
-
-
-### WordPress Plugin Interface ###
-
-/*
-Plugin Name: Markdown Extra
-Plugin URI: http://michelf.com/projects/php-markdown/
-Description: <a href="http://daringfireball.net/projects/markdown/syntax">Markdown syntax</a> allows you to write using an easy-to-read, easy-to-write plain text format. Based on the original Perl version by <a href="http://daringfireball.net/">John Gruber</a>. <a href="http://michelf.com/projects/php-markdown/">More...</a>
-Version: 1.2.5
-Author: Michel Fortin
-Author URI: http://michelf.com/
-*/
-
-if (isset($wp_version)) {
-	# More details about how it works here:
-	# <http://michelf.com/weblog/2005/wordpress-text-flow-vs-markdown/>
-
-	# Post content and excerpts
-	# - Remove WordPress paragraph generator.
-	# - Run Markdown on excerpt, then remove all tags.
-	# - Add paragraph tag around the excerpt, but remove it for the excerpt rss.
-	if (MARKDOWN_WP_POSTS) {
-		remove_filter('the_content',     'wpautop');
-        remove_filter('the_content_rss', 'wpautop');
-		remove_filter('the_excerpt',     'wpautop');
-		add_filter('the_content',     'mdwp_MarkdownPost', 6);
-        add_filter('the_content_rss', 'mdwp_MarkdownPost', 6);
-		add_filter('get_the_excerpt', 'mdwp_MarkdownPost', 6);
-		add_filter('get_the_excerpt', 'trim', 7);
-		add_filter('the_excerpt',     'mdwp_add_p');
-		add_filter('the_excerpt_rss', 'mdwp_strip_p');
-
-		remove_filter('content_save_pre',  'balanceTags', 50);
-		remove_filter('excerpt_save_pre',  'balanceTags', 50);
-		add_filter('the_content',  	  'balanceTags', 50);
-		add_filter('get_the_excerpt', 'balanceTags', 9);
-	}
-
-	# Add a footnote id prefix to posts when inside a loop.
-	function mdwp_MarkdownPost($text) {
-		static $parser;
-		if (!$parser) {
-			$parser_class = MARKDOWN_PARSER_CLASS;
-			$parser = new $parser_class;
-		}
-		if (is_single() || is_page() || is_feed()) {
-			$parser->fn_id_prefix = "";
-		} else {
-			$parser->fn_id_prefix = get_the_ID() . ".";
-		}
-		return $parser->transform($text);
-	}
-
-	# Comments
-	# - Remove WordPress paragraph generator.
-	# - Remove WordPress auto-link generator.
-	# - Scramble important tags before passing them to the kses filter.
-	# - Run Markdown on excerpt then remove paragraph tags.
-	if (MARKDOWN_WP_COMMENTS) {
-		remove_filter('comment_text', 'wpautop', 30);
-		remove_filter('comment_text', 'make_clickable');
-		add_filter('pre_comment_content', 'Markdown', 6);
-		add_filter('pre_comment_content', 'mdwp_hide_tags', 8);
-		add_filter('pre_comment_content', 'mdwp_show_tags', 12);
-		add_filter('get_comment_text',    'Markdown', 6);
-		add_filter('get_comment_excerpt', 'Markdown', 6);
-		add_filter('get_comment_excerpt', 'mdwp_strip_p', 7);
-
-		global $mdwp_hidden_tags, $mdwp_placeholders;
-		$mdwp_hidden_tags = explode(' ',
-			'<p> </p> <pre> </pre> <ol> </ol> <ul> </ul> <li> </li>');
-		$mdwp_placeholders = explode(' ', str_rot13(
-			'pEj07ZbbBZ U1kqgh4w4p pre2zmeN6K QTi31t9pre ol0MP1jzJR '.
-			'ML5IjmbRol ulANi1NsGY J7zRLJqPul liA8ctl16T K9nhooUHli'));
-	}
-
-	function mdwp_add_p($text) {
-		if (!preg_match('{^$|^<(p|ul|ol|dl|pre|blockquote)>}i', $text)) {
-			$text = '<p>'.$text.'</p>';
-			$text = preg_replace('{\n{2,}}', "</p>\n\n<p>", $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' => '<a href="http://daringfireball.net/projects/markdown/syntax">Markdown syntax</a> allows you to write using an easy-to-read, easy-to-write plain text format. Based on the original Perl version by <a href="http://daringfireball.net/">John Gruber</a>. <a href="http://michelf.com/projects/php-markdown/">More...</a>',
-		);
-}
-
-
-### 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
-							  [ ]*
-							(?:
-							  <(.+?)>			# url = $2
-							|
-							  (\S+?)			# url = $3
-							)
-							  [ ]*
-							  \n?				# maybe one newline
-							  [ ]*
-							(?:
-								(?<=\s)			# lookbehind for whitespace
-								["(]
-								(.*?)			# title = $4
-								[")]
-								[ ]*
-							)?	# title is optional
-							(?:\n+|\Z)
-			}xm',
-			array(&$this, '_stripLinkDefinitions_callback'),
-			$text);
-		return $text;
-	}
-	function _stripLinkDefinitions_callback($matches) {
-		$link_id = strtolower($matches[1]);
-		$url = $matches[2] == '' ? $matches[3] : $matches[2];
-		$this->urls[$link_id] = $url;
-		$this->titles[$link_id] =& $matches[4];
-		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 <p>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.:
-		# 	<div>
-		# 		<div>
-		# 		tags for inner block must be indented.
-		# 		</div>
-		# 	</div>
-		#
-		# The outermost tags must start at the left margin for this to match, and
-		# the inner nested divs must be indented.
-		# We need to do this before the next, more liberal match, because the next
-		# match will start at the first `<div>` and stop at the first `</div>`.
-		$text = preg_replace_callback('{(?>
-			(?>
-				(?<=\n\n)		# Starting after a blank line
-				|				# or
-				\A\n?			# the beginning of the doc
-			)
-			(						# save in $1
-
-			  # Match from `\n<tag>` to `</tag>\n`, handling nested tags
-			  # in between.
-
-						[ ]{0,'.$less_than_tab.'}
-						<('.$block_tags_b_re.')# start tag = $2
-						'.$attr.'>			# attributes followed by > and \n
-						'.$content.'		# content, support nesting
-						</\2>				# the matching end tag
-						[ ]*				# trailing spaces/tabs
-						(?=\n+|\Z)	# followed by a newline or end of document
-
-			| # Special version for tags of group a.
-
-						[ ]{0,'.$less_than_tab.'}
-						<('.$block_tags_a_re.')# start tag = $3
-						'.$attr.'>[ ]*\n	# attributes followed by >
-						'.$content2.'		# content, support nesting
-						</\3>				# the matching end tag
-						[ ]*				# trailing spaces/tabs
-						(?=\n+|\Z)	# followed by a newline or end of document
-
-			| # Special case just for <hr />. It was easier to make a special
-			  # case than to make the other regex more complicated.
-
-						[ ]{0,'.$less_than_tab.'}
-						<(hr)				# start tag = $2
-						'.$attr.'			# attributes
-						/?>					# the matching end tag
-						[ ]*
-						(?=\n{2,}|\Z)		# followed by a blank line or end of document
-
-			| # Special case for standalone HTML comments:
-
-					[ ]{0,'.$less_than_tab.'}
-					(?s:
-						<!-- .*? -->
-					)
-					[ ]*
-					(?=\n{2,}|\Z)		# followed by a blank line or end of document
-
-			| # PHP and ASP-style processor instructions (<? and <%)
-
-					[ ]{0,'.$less_than_tab.'}
-					(?s:
-						<([?%])			# $2
-						.*?
-						\2>
-					)
-					[ ]*
-					(?=\n{2,}|\Z)		# followed by a blank line or end of document
-
-			)
-			)}Sxmi',
-			array(&$this, '_hashHTMLBlocks_callback'),
-			$text);
-
-		return $text;
-	}
-	function _hashHTMLBlocks_callback($matches) {
-		$text = $matches[1];
-		$key  = $this->hashBlock($text);
-		return "\n\n$key\n\n";
-	}
-
-
-	function hashPart($text, $boundary = 'X') {
-	#
-	# Called whenever a tag must be hashed when a function insert an atomic
-	# element in the text stream. Passing $text to through this function gives
-	# a unique text-token which will be reverted back when calling unhash.
-	#
-	# The $boundary argument specify what character should be used to surround
-	# the token. By convension, "B" is used for block elements that needs not
-	# to be wrapped into paragraph tags at the end, ":" is used for elements
-	# that are word separators and "X" is used in the general case.
-	#
-		# Swap back any tag hash found in $text so we do not have to `unhash`
-		# multiple times at the end.
-		$text = $this->unhash($text);
-
-		# Then hash the block.
-		static $i = 0;
-		$key = "$boundary\x1A" . ++$i . $boundary;
-		$this->html_hashes[$key] = $text;
-		return $key; # String that will replace the tag.
-	}
-
-
-	function hashBlock($text) {
-	#
-	# Shortcut function for hashPart with block-level boundaries.
-	#
-		return $this->hashPart($text, 'B');
-	}
-
-
-	var $block_gamut = array(
-	#
-	# These are all the transformations that form block-level
-	# tags like paragraphs, headers, and list items.
-	#
-		"doHeaders"         => 10,
-		"doHorizontalRules" => 20,
-
-		"doLists"           => 40,
-		"doCodeBlocks"      => 50,
-		"doBlockQuotes"     => 60,
-		);
-
-	function runBlockGamut($text) {
-	#
-	# Run block gamut tranformations.
-	#
-		# We need to escape raw HTML in Markdown source before doing anything
-		# else. This need to be done for each block, and not only at the
-		# begining in the Markdown function since hashed blocks can be part of
-		# list items and could have been indented. Indented blocks would have
-		# been seen as a code block in a previous pass of hashHTMLBlocks.
-		$text = $this->hashHTMLBlocks($text);
-
-		return $this->runBasicBlockGamut($text);
-	}
-
-	function runBasicBlockGamut($text) {
-	#
-	# Run block gamut tranformations, without hashing HTML blocks. This is
-	# useful when HTML blocks are known to be already hashed, like in the first
-	# whole-document pass.
-	#
-		foreach ($this->block_gamut as $method => $priority) {
-			$text = $this->$method($text);
-		}
-
-		# Finally form paragraph and restore hashed blocks.
-		$text = $this->formParagraphs($text);
-
-		return $text;
-	}
-
-
-	function doHorizontalRules($text) {
-		# Do Horizontal Rules:
-		return preg_replace(
-			'{
-				^[ ]{0,3}	# Leading space
-				([-*_])		# $1: First marker
-				(?>			# Repeated marker group
-					[ ]{0,2}	# Zero, one, or two spaces.
-					\1			# Marker character
-				){2,}		# Group repeated at least twice
-				[ ]*		# Tailing spaces
-				$			# End of line.
-			}mx',
-			"\n".$this->hashBlock("<hr$this->empty_element_suffix")."\n",
-			$text);
-	}
-
-
-	var $span_gamut = array(
-	#
-	# These are all the transformations that occur *within* block-level
-	# tags like paragraphs, headers, and list items.
-	#
-		# Process character escapes, code spans, and inline HTML
-		# in one shot.
-		"parseSpan"           => -30,
-
-		# Process anchor and image tags. Images must come first,
-		# because ![foo][f] looks like an anchor.
-		"doImages"            =>  10,
-		"doAnchors"           =>  20,
-
-		# Make links out of things like `<http://example.com/>`
-		# Must come after doAnchors, because you can use < and >
-		# delimiters in inline links like [this](<url>).
-		"doAutoLinks"         =>  30,
-		"encodeAmpsAndAngles" =>  40,
-
-		"doItalicsAndBold"    =>  50,
-		"doHardBreaks"        =>  60,
-		);
-
-	function runSpanGamut($text) {
-	#
-	# Run span gamut tranformations.
-	#
-		foreach ($this->span_gamut as $method => $priority) {
-			$text = $this->$method($text);
-		}
-
-		return $text;
-	}
-
-
-	function doHardBreaks($text) {
-		# Do hard breaks:
-		return preg_replace_callback('/ {2,}\n/',
-			array(&$this, '_doHardBreaks_callback'), $text);
-	}
-	function _doHardBreaks_callback($matches) {
-		return $this->hashPart("<br$this->empty_element_suffix\n");
-	}
-
-
-	function doAnchors($text) {
-	#
-	# Turn Markdown link shortcuts into XHTML <a> tags.
-	#
-		if ($this->in_anchor) return $text;
-		$this->in_anchor = true;
-
-		#
-		# First, handle reference-style links: [link text] [id]
-		#
-		$text = preg_replace_callback('{
-			(					# wrap whole match in $1
-			  \[
-				('.$this->nested_brackets_re.')	# link text = $2
-			  \]
-
-			  [ ]?				# one optional space
-			  (?:\n[ ]*)?		# one optional newline followed by spaces
-
-			  \[
-				(.*?)		# id = $3
-			  \]
-			)
-			}xs',
-			array(&$this, '_doAnchors_reference_callback'), $text);
-
-		#
-		# Next, inline-style links: [link text](url "optional title")
-		#
-		$text = preg_replace_callback('{
-			(				# wrap whole match in $1
-			  \[
-				('.$this->nested_brackets_re.')	# link text = $2
-			  \]
-			  \(			# literal paren
-				[ \n]*
-				(?:
-					<(.+?)>	# href = $3
-				|
-					('.$this->nested_url_parenthesis_re.')	# href = $4
-				)
-				[ \n]*
-				(			# $5
-				  ([\'"])	# quote char = $6
-				  (.*?)		# Title = $7
-				  \6		# matching quote
-				  [ \n]*	# ignore any spaces/tabs between closing quote and )
-				)?			# title is optional
-			  \)
-			)
-			}xs',
-			array(&$this, '_doAnchors_inline_callback'), $text);
-
-		#
-		# Last, handle reference-style shortcuts: [link text]
-		# These must come last in case you've also got [link text][1]
-		# or [link text](/foo)
-		#
-		$text = preg_replace_callback('{
-			(					# wrap whole match in $1
-			  \[
-				([^\[\]]+)		# link text = $2; can\'t contain [ or ]
-			  \]
-			)
-			}xs',
-			array(&$this, '_doAnchors_reference_callback'), $text);
-
-		$this->in_anchor = false;
-		return $text;
-	}
-	function _doAnchors_reference_callback($matches) {
-		$whole_match =  $matches[1];
-		$link_text   =  $matches[2];
-		$link_id     =& $matches[3];
-
-		if ($link_id == "") {
-			# for shortcut links like [this][] or [this].
-			$link_id = $link_text;
-		}
-
-		# lower-case and turn embedded newlines into spaces
-		$link_id = strtolower($link_id);
-		$link_id = preg_replace('{[ ]?\n}', ' ', $link_id);
-
-		if (isset($this->urls[$link_id])) {
-			$url = $this->urls[$link_id];
-			$url = $this->encodeAttribute($url);
-
-			$result = "<a href=\"$url\"";
-			if ( isset( $this->titles[$link_id] ) ) {
-				$title = $this->titles[$link_id];
-				$title = $this->encodeAttribute($title);
-				$result .=  " title=\"$title\"";
-			}
-
-			$link_text = $this->runSpanGamut($link_text);
-			$result .= ">$link_text</a>";
-			$result = $this->hashPart($result);
-		}
-		else {
-			$result = $whole_match;
-		}
-		return $result;
-	}
-	function _doAnchors_inline_callback($matches) {
-		$whole_match	=  $matches[1];
-		$link_text		=  $this->runSpanGamut($matches[2]);
-		$url			=  $matches[3] == '' ? $matches[4] : $matches[3];
-		$title			=& $matches[7];
-
-		$url = $this->encodeAttribute($url);
-
-		$result = "<a href=\"$url\"";
-		if (isset($title)) {
-			$title = $this->encodeAttribute($title);
-			$result .=  " title=\"$title\"";
-		}
-
-		$link_text = $this->runSpanGamut($link_text);
-		$result .= ">$link_text</a>";
-
-		return $this->hashPart($result);
-	}
-
-
-	function doImages($text) {
-	#
-	# Turn Markdown image shortcuts into <img> tags.
-	#
-		#
-		# First, handle reference-style labeled images: ![alt text][id]
-		#
-		$text = preg_replace_callback('{
-			(				# wrap whole match in $1
-			  !\[
-				('.$this->nested_brackets_re.')		# alt text = $2
-			  \]
-
-			  [ ]?				# one optional space
-			  (?:\n[ ]*)?		# one optional newline followed by spaces
-
-			  \[
-				(.*?)		# id = $3
-			  \]
-
-			)
-			}xs',
-			array(&$this, '_doImages_reference_callback'), $text);
-
-		#
-		# Next, handle inline images:  ![alt text](url "optional title")
-		# Don't forget: encode * and _
-		#
-		$text = preg_replace_callback('{
-			(				# wrap whole match in $1
-			  !\[
-				('.$this->nested_brackets_re.')		# alt text = $2
-			  \]
-			  \s?			# One optional whitespace character
-			  \(			# literal paren
-				[ \n]*
-				(?:
-					<(\S*)>	# src url = $3
-				|
-					('.$this->nested_url_parenthesis_re.')	# src url = $4
-				)
-				[ \n]*
-				(			# $5
-				  ([\'"])	# quote char = $6
-				  (.*?)		# title = $7
-				  \6		# matching quote
-				  [ \n]*
-				)?			# title is optional
-			  \)
-			)
-			}xs',
-			array(&$this, '_doImages_inline_callback'), $text);
-
-		return $text;
-	}
-	function _doImages_reference_callback($matches) {
-		$whole_match = $matches[1];
-		$alt_text    = $matches[2];
-		$link_id     = strtolower($matches[3]);
-
-		if ($link_id == "") {
-			$link_id = strtolower($alt_text); # for shortcut links like ![this][].
-		}
-
-		$alt_text = $this->encodeAttribute($alt_text);
-		if (isset($this->urls[$link_id])) {
-			$url = $this->encodeAttribute($this->urls[$link_id]);
-			$result = "<img src=\"$url\" alt=\"$alt_text\"";
-			if (isset($this->titles[$link_id])) {
-				$title = $this->titles[$link_id];
-				$title = $this->encodeAttribute($title);
-				$result .=  " title=\"$title\"";
-			}
-			$result .= $this->empty_element_suffix;
-			$result = $this->hashPart($result);
-		}
-		else {
-			# If there's no such link ID, leave intact:
-			$result = $whole_match;
-		}
-
-		return $result;
-	}
-	function _doImages_inline_callback($matches) {
-		$whole_match	= $matches[1];
-		$alt_text		= $matches[2];
-		$url			= $matches[3] == '' ? $matches[4] : $matches[3];
-		$title			=& $matches[7];
-
-		$alt_text = $this->encodeAttribute($alt_text);
-		$url = $this->encodeAttribute($url);
-		$result = "<img src=\"$url\" alt=\"$alt_text\"";
-		if (isset($title)) {
-			$title = $this->encodeAttribute($title);
-			$result .=  " title=\"$title\""; # $title already quoted
-		}
-		$result .= $this->empty_element_suffix;
-
-		return $this->hashPart($result);
-	}
-
-
-	function doHeaders($text) {
-		# Setext-style headers:
-		#	  Header 1
-		#	  ========
-		#
-		#	  Header 2
-		#	  --------
-		#
-		$text = preg_replace_callback('{ ^(.+?)[ ]*\n(=+|-+)[ ]*\n+ }mx',
-			array(&$this, '_doHeaders_callback_setext'), $text);
-
-		# atx-style headers:
-		#	# Header 1
-		#	## Header 2
-		#	## Header 2 with closing hashes ##
-		#	...
-		#	###### Header 6
-		#
-		$text = preg_replace_callback('{
-				^(\#{1,6})	# $1 = string of #\'s
-				[ ]*
-				(.+?)		# $2 = Header text
-				[ ]*
-				\#*			# optional closing #\'s (not counted)
-				\n+
-			}xm',
-			array(&$this, '_doHeaders_callback_atx'), $text);
-
-		return $text;
-	}
-	function _doHeaders_callback_setext($matches) {
-		# Terrible hack to check we haven't found an empty list item.
-		if ($matches[2] == '-' && preg_match('{^-(?: |$)}', $matches[1]))
-			return $matches[0];
-
-		$level = $matches[2]{0} == '=' ? 1 : 2;
-		$block = "<h$level>".$this->runSpanGamut($matches[1])."</h$level>";
-		return "\n" . $this->hashBlock($block) . "\n\n";
-	}
-	function _doHeaders_callback_atx($matches) {
-		$level = strlen($matches[1]);
-		$block = "<h$level>".$this->runSpanGamut($matches[2])."</h$level>";
-		return "\n" . $this->hashBlock($block) . "\n\n";
-	}
-
-
-	function doLists($text) {
-	#
-	# Form HTML ordered (numbered) and unordered (bulleted) lists.
-	#
-		$less_than_tab = $this->tab_width - 1;
-
-		# Re-usable patterns to match list item bullets and number markers:
-		$marker_ul_re  = '[*+-]';
-		$marker_ol_re  = '\d+[\.]';
-		$marker_any_re = "(?:$marker_ul_re|$marker_ol_re)";
-
-		$markers_relist = array(
-			$marker_ul_re => $marker_ol_re,
-			$marker_ol_re => $marker_ul_re,
-			);
-
-		foreach ($markers_relist as $marker_re => $other_marker_re) {
-			# Re-usable pattern to match any entirel ul or ol list:
-			$whole_list_re = '
-				(								# $1 = whole list
-				  (								# $2
-					([ ]{0,'.$less_than_tab.'})	# $3 = number of spaces
-					('.$marker_re.')			# $4 = first list item marker
-					[ ]+
-				  )
-				  (?s:.+?)
-				  (								# $5
-					  \z
-					|
-					  \n{2,}
-					  (?=\S)
-					  (?!						# Negative lookahead for another list item marker
-						[ ]*
-						'.$marker_re.'[ ]+
-					  )
-					|
-					  (?=						# Lookahead for another kind of list
-					    \n
-						\3						# Must have the same indentation
-						'.$other_marker_re.'[ ]+
-					  )
-				  )
-				)
-			'; // mx
-
-			# We use a different prefix before nested lists than top-level lists.
-			# See extended comment in _ProcessListItems().
-
-			if ($this->list_level) {
-				$text = preg_replace_callback('{
-						^
-						'.$whole_list_re.'
-					}mx',
-					array(&$this, '_doLists_callback'), $text);
-			}
-			else {
-				$text = preg_replace_callback('{
-						(?:(?<=\n)\n|\A\n?) # Must eat the newline
-						'.$whole_list_re.'
-					}mx',
-					array(&$this, '_doLists_callback'), $text);
-			}
-		}
-
-		return $text;
-	}
-	function _doLists_callback($matches) {
-		# Re-usable patterns to match list item bullets and number markers:
-		$marker_ul_re  = '[*+-]';
-		$marker_ol_re  = '\d+[\.]';
-		$marker_any_re = "(?:$marker_ul_re|$marker_ol_re)";
-
-		$list = $matches[1];
-		$list_type = preg_match("/$marker_ul_re/", $matches[4]) ? "ul" : "ol";
-
-		$marker_any_re = ( $list_type == "ul" ? $marker_ul_re : $marker_ol_re );
-
-		$list .= "\n";
-		$result = $this->processListItems($list, $marker_any_re);
-
-		$result = $this->hashBlock("<$list_type>\n" . $result . "</$list_type>");
-		return "\n". $result ."\n\n";
-	}
-
-	var $list_level = 0;
-
-	function processListItems($list_str, $marker_any_re) {
-	#
-	#	Process the contents of a single ordered or unordered list, splitting it
-	#	into individual list items.
-	#
-		# The $this->list_level global keeps track of when we're inside a list.
-		# Each time we enter a list, we increment it; when we leave a list,
-		# we decrement. If it's zero, we're not in a list anymore.
-		#
-		# We do this because when we're not inside a list, we want to treat
-		# something like this:
-		#
-		#		I recommend upgrading to version
-		#		8. Oops, now this line is treated
-		#		as a sub-list.
-		#
-		# As a single paragraph, despite the fact that the second line starts
-		# with a digit-period-space sequence.
-		#
-		# Whereas when we're inside a list (or sub-list), that line will be
-		# treated as the start of a sub-list. What a kludge, huh? This is
-		# an aspect of Markdown's syntax that's hard to parse perfectly
-		# without resorting to mind-reading. Perhaps the solution is to
-		# change the syntax rules such that sub-lists must start with a
-		# starting cardinal number; e.g. "1." or "a.".
-
-		$this->list_level++;
-
-		# trim trailing blank lines:
-		$list_str = preg_replace("/\n{2,}\\z/", "\n", $list_str);
-
-		$list_str = preg_replace_callback('{
-			(\n)?							# leading line = $1
-			(^[ ]*)							# leading whitespace = $2
-			('.$marker_any_re.'				# list marker and space = $3
-				(?:[ ]+|(?=\n))	# space only required if item is not empty
-			)
-			((?s:.*?))						# list item text   = $4
-			(?:(\n+(?=\n))|\n)				# tailing blank line = $5
-			(?= \n* (\z | \2 ('.$marker_any_re.') (?:[ ]+|(?=\n))))
-			}xm',
-			array(&$this, '_processListItems_callback'), $list_str);
-
-		$this->list_level--;
-		return $list_str;
-	}
-	function _processListItems_callback($matches) {
-		$item = $matches[4];
-		$leading_line =& $matches[1];
-		$leading_space =& $matches[2];
-		$marker_space = $matches[3];
-		$tailing_blank_line =& $matches[5];
-
-		if ($leading_line || $tailing_blank_line ||
-			preg_match('/\n{2,}/', $item))
-		{
-			# Replace marker with the appropriate whitespace indentation
-			$item = $leading_space . str_repeat(' ', strlen($marker_space)) . $item;
-			$item = $this->runBlockGamut($this->outdent($item)."\n");
-		}
-		else {
-			# Recursion for sub-lists:
-			$item = $this->doLists($this->outdent($item));
-			$item = preg_replace('/\n+$/', '', $item);
-			$item = $this->runSpanGamut($item);
-		}
-
-		return "<li>" . $item . "</li>\n";
-	}
-
-
-	function doCodeBlocks($text) {
-	#
-	#	Process Markdown `<pre><code>` 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 = "<pre><code>$codeblock\n</code></pre>";
-		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>$code</code>");
-	}
-
-
-	var $em_relist = array(
-		''  => '(?:(?<!\*)\*(?!\*)|(?<!_)_(?!_))(?=\S|$)(?![\.,:;]\s)',
-		'*' => '(?<=\S|^)(?<!\*)\*(?!\*)',
-		'_' => '(?<=\S|^)(?<!_)_(?!_)',
-		);
-	var $strong_relist = array(
-		''   => '(?:(?<!\*)\*\*(?!\*)|(?<!_)__(?!_))(?=\S|$)(?![\.,:;]\s)',
-		'**' => '(?<=\S|^)(?<!\*)\*\*(?!\*)',
-		'__' => '(?<=\S|^)(?<!_)__(?!_)',
-		);
-	var $em_strong_relist = array(
-		''    => '(?:(?<!\*)\*\*\*(?!\*)|(?<!_)___(?!_))(?=\S|$)(?![\.,:;]\s)',
-		'***' => '(?<=\S|^)(?<!\*)\*\*\*(?!\*)',
-		'___' => '(?<=\S|^)(?<!_)___(?!_)',
-		);
-	var $em_strong_prepared_relist;
-
-	function prepareItalicsAndBold() {
-	#
-	# Prepare regular expressions for searching emphasis tokens in any
-	# context.
-	#
-		foreach ($this->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 search 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 = "<strong><em>$span</em></strong>";
-					$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 = "<strong>$span</strong>";
-					$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 = "<em>$span</em>";
-						$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 <pre> content,
-		# so we need to fix that:
-		$bq = preg_replace_callback('{(\s*<pre>.+?</pre>)}sx',
-			array(&$this, '_doBlockQuotes_callback2'), $bq);
-
-		return "\n". $this->hashBlock("<blockquote>\n$bq\n</blockquote>")."\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 <p> 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 <p> 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('/^([ ]*)/', "<p>", $value);
-				$value .= "</p>";
-				$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 = <div> tag
-//					  <div  \s+
-//					  [^>]*
-//					  \b
-//					  markdown\s*=\s*  ([\'"])	#	$2 = attr quote char
-//					  1
-//					  \2
-//					  [^>]*
-//					  >
-//					)
-//					(							# $3 = contents
-//					.*
-//					)
-//					(</div>)					# $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('"', '&quot;', $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('&', '&amp;', $text);
-		} else {
-			# Ampersand-encoding based entirely on Nat Irons's Amputator
-			# MT plugin: <http://bumppo.net/projects/amputator/>
-			$text = preg_replace('/&(?!#?[xX]?(?:[0-9a-fA-F]+|\w+);)/',
-								'&amp;', $text);;
-		}
-		# Encode remaining <'s
-		$text = str_replace('<', '&lt;', $text);
-
-		return $text;
-	}
-
-
-	function doAutoLinks($text) {
-		$text = preg_replace_callback('{<((https?|ftp|dict):[^\'">\s]+)>}i',
-			array(&$this, '_doAutoLinks_url_callback'), $text);
-
-		# Email addresses: <[email protected]>
-		$text = preg_replace_callback('{
-			<
-			(?:mailto:)?
-			(
-				(?:
-					[-!#$%&\'*+/=?^_`.{|}~\w\x80-\xFF]+
-				|
-					".*?"
-				)
-				\@
-				(?:
-					[-a-z0-9\x80-\xFF]+(\.[-a-z0-9\x80-\xFF]+)*\.[a-z]+
-				|
-					\[[\d.a-fA-F:]+\]	# IPv4 & IPv6
-				)
-			)
-			>
-			}xi',
-			array(&$this, '_doAutoLinks_email_callback'), $text);
-
-		return $text;
-	}
-	function _doAutoLinks_url_callback($matches) {
-		$url = $this->encodeAttribute($matches[1]);
-		$link = "<a href=\"$url\">$url</a>";
-		return $this->hashPart($link);
-	}
-	function _doAutoLinks_email_callback($matches) {
-		$address = $matches[1];
-		$link = $this->encodeEmailAddress($address);
-		return $this->hashPart($link);
-	}
-
-
-	function encodeEmailAddress($addr) {
-	#
-	#	Input: an email address, e.g. "[email protected]"
-	#
-	#	Output: the email address as a mailto link, with each character
-	#		of the address encoded as either a decimal or hex entity, in
-	#		the hopes of foiling most address harvesting spam bots. E.g.:
-	#
-	#	  <p><a href="&#109;&#x61;&#105;&#x6c;&#116;&#x6f;&#58;&#x66;o&#111;
-	#        &#x40;&#101;&#x78;&#97;&#x6d;&#112;&#x6c;&#101;&#46;&#x63;&#111;
-	#        &#x6d;">&#x66;o&#111;&#x40;&#101;&#x78;&#97;&#x6d;&#112;&#x6c;
-	#        &#101;&#46;&#x63;&#111;&#x6d;</a></p>
-	#
-	#	Based by a filter by Matthew Wickline, posted to BBEdit-Talk.
-	#   With some optimizations by Milian Wolff.
-	#
-		$addr = "mailto:" . $addr;
-		$chars = preg_split('/(?<!^)(?!$)/', $addr);
-		$seed = (int)abs(crc32($addr) / strlen($addr)); # Deterministic seed.
-
-		foreach ($chars as $key => $char) {
-			$ord = ord($char);
-			# Ignore non-ascii chars.
-			if ($ord < 128) {
-				$r = ($seed * (1 + $key)) % 100; # Pseudo-random function.
-				# roughly 10% raw, 45% hex, 45% dec
-				# '@' *must* be encoded. I insist.
-				if ($r > 90 && $char != '@') /* do nothing */;
-				else if ($r < 45) $chars[$key] = '&#x'.dechex($ord).';';
-				else              $chars[$key] = '&#'.$ord.';';
-			}
-		}
-
-		$addr = implode('', $chars);
-		$text = implode('', array_slice($chars, 7)); # text without `mailto:`
-		$addr = "<a href=\"$addr\">$text</a>";
-
-		return $addr;
-	}
-
-
-	function parseSpan($str) {
-	#
-	# Take the string $str and parse it into tokens, hashing embeded HTML,
-	# escaped characters and handling code spans.
-	#
-		$output = '';
-
-		$span_re = '{
-				(
-					\\\\'.$this->escape_chars_re.'
-				|
-					(?<![`\\\\])
-					`+						# code span marker
-			'.( $this->no_markup ? '' : '
-				|
-					<!--    .*?     -->		# comment
-				|
-					<\?.*?\?> | <%.*?%>		# processing instruction
-				|
-					<[/!$]?[-a-zA-Z0-9:_]+	# regular tags
-					(?>
-						\s
-						(?>[^"\'>]+|"[^"]*"|\'[^\']*\')*
-					)?
-					>
-			').'
-				)
-				}xs';
-
-		while (1) {
-			#
-			# Each loop iteration seach for either the next tag, the next
-			# openning code span marker, or the next escaped character.
-			# Each token is then passed to handleSpanToken.
-			#
-			$parts = preg_split($span_re, $str, 2, PREG_SPLIT_DELIM_CAPTURE);
-
-			# Create token from text preceding tag.
-			if ($parts[0] != "") {
-				$output .= $parts[0];
-			}
-
-			# Check if we reach the end.
-			if (isset($parts[1])) {
-				$output .= $this->handleSpanToken($parts[1], $parts[2]);
-				$str = $parts[2];
-			}
-			else {
-				break;
-			}
-		}
-
-		return $output;
-	}
-
-
-	function handleSpanToken($token, &$str) {
-	#
-	# Handle $token provided by parseSpan by determining its nature and
-	# returning the corresponding value that should replace it.
-	#
-		switch ($token{0}) {
-			case "\\":
-				return $this->hashPart("&#". ord($token{1}). ";");
-			case "`":
-				# Search for end marker in remaining text.
-				if (preg_match('/^(.*?[^`])'.preg_quote($token).'(?!`)(.*)$/sm',
-					$str, $matches))
-				{
-					$str = $matches[2];
-					$codespan = $this->makeCodeSpan($matches[1]);
-					return $this->hashPart($codespan);
-				}
-				return $token; // return as text since no ending marker found.
-			default:
-				return $this->hashPart($token);
-		}
-	}
-
-
-	function outdent($text) {
-	#
-	# Remove one level of line-leading tabs or spaces
-	#
-		return preg_replace('/^(\t|[ ]{1,'.$this->tab_width.'})/m', '', $text);
-	}
-
-
-	# String length function for detab. `_initDetab` will create a function to
-	# hanlde UTF-8 if the default function does not exist.
-	var $utf8_strlen = 'mb_strlen';
-
-	function detab($text) {
-	#
-	# Replace tabs with the appropriate amount of space.
-	#
-		# For each line we separate the line in blocks delemited by
-		# tab characters. Then we reconstruct every line by adding the
-		# appropriate number of space between each blocks.
-
-		$text = preg_replace_callback('/^.*\t.*$/m',
-			array(&$this, '_detab_callback'), $text);
-
-		return $text;
-	}
-	function _detab_callback($matches) {
-		$line = $matches[0];
-		$strlen = $this->utf8_strlen; # strlen function for UTF-8.
-
-		# Split in blocks.
-		$blocks = explode("\t", $line);
-		# Add each blocks to the line.
-		$line = $blocks[0];
-		unset($blocks[0]); # Do not add first block twice.
-		foreach ($blocks as $block) {
-			# Calculate amount of space, insert spaces, insert block.
-			$amount = $this->tab_width -
-				$strlen($line, 'UTF-8') % $this->tab_width;
-			$line .= str_repeat(" ", $amount) . $block;
-		}
-		return $line;
-	}
-	function _initDetab() {
-	#
-	# Check for the availability of the function in the `utf8_strlen` property
-	# (initially `mb_strlen`). If the function is not available, create a
-	# function that will loosely count the number of UTF-8 characters with a
-	# regular expression.
-	#
-		if (function_exists($this->utf8_strlen)) return;
-		$this->utf8_strlen = create_function('$text', 'return preg_match_all(
-			"/[\\\\x00-\\\\xBF]|[\\\\xC0-\\\\xFF][\\\\x80-\\\\xBF]*/",
-			$text, $m);');
-	}
-
-
-	function unhash($text) {
-	#
-	# Swap back in all the tags hashed by _HashHTMLBlocks.
-	#
-		return preg_replace_callback('/(.)\x1A[0-9]+\1/',
-			array(&$this, '_unhash_callback'), $text);
-	}
-	function _unhash_callback($matches) {
-		return $this->html_hashes[$matches[0]];
-	}
-
-}
-
-
-#
-# Markdown Extra Parser Class
-#
-
-class MarkdownExtra_Parser extends Markdown_Parser {
-
-	# Prefix for footnote ids.
-	var $fn_id_prefix = "";
-
-	# Optional title attribute for footnote links and backlinks.
-	var $fn_link_title = MARKDOWN_FN_LINK_TITLE;
-	var $fn_backlink_title = MARKDOWN_FN_BACKLINK_TITLE;
-
-	# Optional class attribute for footnote links and backlinks.
-	var $fn_link_class = MARKDOWN_FN_LINK_CLASS;
-	var $fn_backlink_class = MARKDOWN_FN_BACKLINK_CLASS;
-
-	# Predefined abbreviations.
-	var $predef_abbr = array();
-
-
-	function MarkdownExtra_Parser() {
-	#
-	# Constructor function. Initialize the parser object.
-	#
-		# Add extra escapable characters before parent constructor
-		# initialize the table.
-		$this->escape_chars .= ':|';
-
-		# Insert extra document, block, and span transformations.
-		# Parent constructor will do the sorting.
-		$this->document_gamut += array(
-			"doFencedCodeBlocks" => 5,
-			"stripFootnotes"     => 15,
-			"stripAbbreviations" => 25,
-			"appendFootnotes"    => 50,
-			);
-		$this->block_gamut += array(
-			"doFencedCodeBlocks" => 5,
-			"doTables"           => 15,
-			"doDefLists"         => 45,
-			);
-		$this->span_gamut += array(
-			"doFootnotes"        => 5,
-			"doAbbreviations"    => 70,
-			);
-
-		parent::Markdown_Parser();
-	}
-
-
-	# Extra variables used during extra transformations.
-	var $footnotes = array();
-	var $footnotes_ordered = array();
-	var $abbr_desciptions = array();
-	var $abbr_word_re = '';
-
-	# Give the current footnote number.
-	var $footnote_counter = 1;
-
-
-	function setup() {
-	#
-	# Setting up Extra-specific variables.
-	#
-		parent::setup();
-
-		$this->footnotes = array();
-		$this->footnotes_ordered = array();
-		$this->abbr_desciptions = array();
-		$this->abbr_word_re = '';
-		$this->footnote_counter = 1;
-
-		foreach ($this->predef_abbr as $abbr_word => $abbr_desc) {
-			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);
-		}
-	}
-
-	function teardown() {
-	#
-	# Clearing Extra-specific variables.
-	#
-		$this->footnotes = array();
-		$this->footnotes_ordered = array();
-		$this->abbr_desciptions = array();
-		$this->abbr_word_re = '';
-
-		parent::teardown();
-	}
-
-
-	### HTML Block Parser ###
-
-	# Tags that are always treated as block tags:
-	var $block_tags_re = 'p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|address|form|fieldset|iframe|hr|legend';
-
-	# Tags treated as block tags only if the opening tag is alone on it's line:
-	var $context_block_tags_re = 'script|noscript|math|ins|del';
-
-	# Tags where markdown="1" default to span mode:
-	var $contain_span_tags_re = 'p|h[1-6]|li|dd|dt|td|th|legend|address';
-
-	# Tags which must not have their contents modified, no matter where
-	# they appear:
-	var $clean_tags_re = 'script|math';
-
-	# Tags that do not need to be closed.
-	var $auto_close_tags_re = 'hr|img';
-
-
-	function hashHTMLBlocks($text) {
-	#
-	# Hashify HTML Blocks and "clean tags".
-	#
-	# 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 <p>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:
-	#
-	#     <div>
-	#         <div markdown="1">
-	#         Hello World.  <-- Is this a Markdown code block or text?
-	#         </div>  <-- Is this a Markdown code block or a real tag?
-	#     <div>
-	#
-	#     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\[.*?\]\]>	# 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 )
-					[ ]{0,'.($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))*?(?<!`)'.$tag_re.'(?!`)}',
-					$text, $matches))
-				{
-					# End marker found: pass text unchanged until marker.
-					$parsed .= $tag . $matches[0];
-					$text = substr($text, strlen($matches[0]));
-				}
-				else {
-					# Unmatched marker: just skip it.
-					$parsed .= $tag;
-				}
-			}
-			#
-			# Check for: Fenced code block marker.
-			#
-			else if (preg_match('{^\n?[ ]{0,'.($indent+3).'}~}', $tag)) {
-				# Fenced code block marker: find matching end marker.
-				$tag_re = preg_quote(trim($tag));
-				if (preg_match('{^(?>.*\n)+?[ ]{0,'.($indent).'}'.$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: Indented code block.
-			#
-			else if ($tag{0} == "\n" || $tag{0} == " ") {
-				# Indented code block: pass it unchanged, will be handled
-				# later.
-				$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\[.*?\]\]>	# 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 <hr/>)
-			#			 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 = "<h$level$attr>".$this->runSpanGamut($matches[1])."</h$level>";
-		return "\n" . $this->hashBlock($block) . "\n\n";
-	}
-	function _doHeaders_callback_atx($matches) {
-		$level = strlen($matches[1]);
-		$attr  = $this->_doHeaders_attr($id =& $matches[3]);
-		$block = "<h$level$attr>".$this->runSpanGamut($matches[2])."</h$level>";
-		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 = "<table>\n";
-		$text .= "<thead>\n";
-		$text .= "<tr>\n";
-		foreach ($headers as $n => $header)
-			$text .= "  <th$attr[$n]>".$this->runSpanGamut(trim($header))."</th>\n";
-		$text .= "</tr>\n";
-		$text .= "</thead>\n";
-
-		# Split content by row.
-		$rows = explode("\n", trim($content, "\n"));
-
-		$text .= "<tbody>\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 .= "<tr>\n";
-			foreach ($row_cells as $n => $cell)
-				$text .= "  <td$attr[$n]>".$this->runSpanGamut(trim($cell))."</td>\n";
-			$text .= "</tr>\n";
-		}
-		$text .= "</tbody>\n";
-		$text .= "</table>";
-
-		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 = "<dl>\n" . $result . "\n</dl>";
-		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.'} [:][ ]	|
-					<dt> | \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<dt>" . $term . "</dt>";
-		}
-		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<dd>" . $def . "</dd>\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 = "<pre><code>$codeblock</code></pre>";
-		return "\n\n".$this->hashBlock($codeblock)."\n\n";
-	}
-	function _doFencedCodeBlocks_newlines($matches) {
-		return str_repeat("<br$this->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(
-		''  => '(?:(?<!\*)\*(?!\*)|(?<![a-zA-Z0-9_])_(?!_))(?=\S|$)(?![\.,:;]\s)',
-		'*' => '(?<=\S|^)(?<!\*)\*(?!\*)',
-		'_' => '(?<=\S|^)(?<!_)_(?![a-zA-Z0-9_])',
-		);
-	var $strong_relist = array(
-		''   => '(?:(?<!\*)\*\*(?!\*)|(?<![a-zA-Z0-9_])__(?!_))(?=\S|$)(?![\.,:;]\s)',
-		'**' => '(?<=\S|^)(?<!\*)\*\*(?!\*)',
-		'__' => '(?<=\S|^)(?<!_)__(?![a-zA-Z0-9_])',
-		);
-	var $em_strong_relist = array(
-		''    => '(?:(?<!\*)\*\*\*(?!\*)|(?<![a-zA-Z0-9_])___(?!_))(?=\S|$)(?![\.,:;]\s)',
-		'***' => '(?<=\S|^)(?<!\*)\*\*\*(?!\*)',
-		'___' => '(?<=\S|^)(?<!_)___(?![a-zA-Z0-9_])',
-		);
-
-
-	function formParagraphs($text) {
-	#
-	#	Params:
-	#		$text - string to process with html <p> 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 <p> 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 = "<p>$value</p>";
-			}
-			$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 .= "<div class=\"footnotes\">\n";
-			$text .= "<hr". $this->empty_element_suffix ."\n";
-			$text .= "<ol>\n\n";
-
-			$attr = " rev=\"footnote\"";
-			if ($this->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 = "<a href=\"#fnref:$note_id\"$attr>&#8617;</a>";
-				if (preg_match('{</p>$}', $footnote)) {
-					$footnote = substr($footnote, 0, -4) . "&#160;$backlink</p>";
-				} else {
-					$footnote .= "\n\n<p>$backlink</p>";
-				}
-
-				$text .= "<li id=\"fn:$note_id\">\n";
-				$text .= $footnote . "\n";
-				$text .= "</li>\n\n";
-			}
-
-			$text .= "</ol>\n";
-			$text .= "</div>";
-		}
-		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
-				"<sup id=\"fnref:$node_id\">".
-				"<a href=\"#fn:$node_id\"$attr>$num</a>".
-				"</sup>";
-		}
-
-		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 <abbr> elements.
-	#
-		if ($this->abbr_word_re) {
-			// cannot use the /x modifier because abbr_word_re may
-			// contain significant spaces:
-			$text = preg_replace_callback('{'.
-				'(?<![\w\x1A])'.
-				'(?:'.$this->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>$abbr</abbr>");
-			} else {
-				$desc = $this->encodeAttribute($desc);
-				return $this->hashPart("<abbr title=\"$desc\">$abbr</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 <div> and <table> as well).
-
-For more information about Markdown's syntax, see:
-
-<http://daringfireball.net/projects/markdown/>
-
-
-Bugs
-----
-
-To file bug reports please send email to:
-
-<[email protected]>
-
-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-2009 Michel Fortin
-<http://michelf.com/>
-All rights reserved.
-
-Based on Markdown
-Copyright (c) 2003-2006 John Gruber
-<http://daringfireball.net/>
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
-*	Redistributions of source code must retain the above copyright notice,
-	this list of conditions and the following disclaimer.
-
-*	Redistributions in binary form must reproduce the above copyright
-	notice, this list of conditions and the following disclaimer in the
-	documentation and/or other materials provided with the distribution.
-
-*	Neither the name "Markdown" nor the names of its contributors may
-	be used to endorse or promote products derived from this software
-	without specific prior written permission.
-
-This software is provided by the copyright holders and contributors "as
-is" and any express or implied warranties, including, but not limited
-to, the implied warranties of merchantability and fitness for a
-particular purpose are disclaimed. In no event shall the copyright owner
-or contributors be liable for any direct, indirect, incidental, special,
-exemplary, or consequential damages (including, but not limited to,
-procurement of substitute goods or services; loss of use, data, or
-profits; or business interruption) however caused and on any theory of
-liability, whether in contract, strict liability, or tort (including
-negligence or otherwise) arising in any way out of the use of this
-software, even if advised of the possibility of such damage.
-
-*/