<?php
/**
 * File Name: pradolite.php
 * Last Update: 2008/04/21 11:26:54
 * Generated By: buildscripts/phpbuilder/build.php
 *
 * This file is used in lieu of prado.php to boost PRADO application performance.
 * It is generated by expanding prado.php with included files.
 * Comments and trace statements are stripped off.
 *
 * Do not modify this file manually.
 */

if(!defined('PRADO_DIR'))
	define('PRADO_DIR',dirname(__FILE__));
if(!defined('PRADO_CHMOD'))
	define('PRADO_CHMOD',0777);
class PradoBase
{
	const CLASS_FILE_EXT='.php';
	private static $_aliases=array('System'=>PRADO_DIR);
	private static $_usings=array();
	private static $_application=null;
	private static $_logger=null;
	public static function getVersion()
	{
		return '3.1.2';
	}
	public static function initErrorHandlers()
	{
		set_error_handler(array('PradoBase','phpErrorHandler'),error_reporting());
		set_exception_handler(array('PradoBase','exceptionHandler'));
	}
	public static function autoload($className)
	{
		include_once($className.self::CLASS_FILE_EXT);
		if(!class_exists($className,false) && !interface_exists($className,false))
			self::fatalError("Class file for '$className' cannot be found.");
	}
	public static function poweredByPrado($logoType=0)
	{
		$logoName=$logoType==1?'powered2':'powered';
		if(self::$_application!==null)
		{
			$am=self::$_application->getAssetManager();
			$url=$am->publishFilePath(self::getPathOfNamespace('System.'.$logoName,'.gif'));
		}
		else
			$url='http://www.pradosoft.com/images/'.$logoName.'.gif';
		return '<a title="Powered by PRADO" href="http://www.pradosoft.com/" target="_blank"><img src="'.$url.'" style="border-width:0px;" alt="Powered by PRADO" /></a>';
	}
	public static function phpErrorHandler($errno,$errstr,$errfile,$errline)
	{
		if(error_reporting()!=0)
			throw new TPhpErrorException($errno,$errstr,$errfile,$errline);
	}
	public static function exceptionHandler($exception)
	{
		if(self::$_application!==null && ($errorHandler=self::$_application->getErrorHandler())!==null)
		{
			$errorHandler->handleError(null,$exception);
		}
		else
		{
			echo $exception;
		}
		exit(1);
	}
	public static function setApplication($application)
	{
		if(self::$_application!==null)
			throw new TInvalidOperationException('prado_application_singleton_required');
		self::$_application=$application;
	}
	public static function getApplication()
	{
		return self::$_application;
	}
	public static function getFrameworkPath()
	{
		return PRADO_DIR;
	}
	public static function serialize($data)
	{
		$arr[0]=$data;
		return serialize($arr);
	}
	public static function unserialize($str)
	{
		$arr=unserialize($str);
		return isset($arr[0])?$arr[0]:null;
	}
	public static function createComponent($type)
	{
		self::using($type);
		if(($pos=strrpos($type,'.'))!==false)
			$type=substr($type,$pos+1);
		if(($n=func_num_args())>1)
		{
			$args=func_get_args();
			$s='$args[1]';
			for($i=2;$i<$n;++$i)
				$s.=",\$args[$i]";
			eval("\$component=new $type($s);");
			return $component;
		}
		else
			return new $type;
	}
	public static function using($namespace,$checkClassExistence=true)
	{
		if(isset(self::$_usings[$namespace]) || class_exists($namespace,false))
			return;
		if(($pos=strrpos($namespace,'.'))===false)  
		{
			try
			{
				include_once($namespace.self::CLASS_FILE_EXT);
			}
			catch(Exception $e)
			{
				if($checkClassExistence && !class_exists($namespace,false))
					throw new TInvalidOperationException('prado_component_unknown',$namespace,$e->getMessage());
				else
					throw $e;
			}
		}
		else if(($path=self::getPathOfNamespace($namespace,self::CLASS_FILE_EXT))!==null)
		{
			$className=substr($namespace,$pos+1);
			if($className==='*')  
			{
				self::$_usings[$namespace]=$path;
				set_include_path(get_include_path().PATH_SEPARATOR.$path);
			}
			else  
			{
				self::$_usings[$namespace]=$path;
				if(!$checkClassExistence || !class_exists($className,false))
				{
					try
					{
						include_once($path);
					}
					catch(Exception $e)
					{
						if($checkClassExistence && !class_exists($className,false))
							throw new TInvalidOperationException('prado_component_unknown',$className,$e->getMessage());
						else
							throw $e;
					}
				}
			}
		}
		else
			throw new TInvalidDataValueException('prado_using_invalid',$namespace);
	}
	public static function getPathOfNamespace($namespace,$ext='')
	{
		if(isset(self::$_usings[$namespace]))
			return self::$_usings[$namespace];
		else if(isset(self::$_aliases[$namespace]))
			return self::$_aliases[$namespace];
		else
		{
			$segs=explode('.',$namespace);
			$alias=array_shift($segs);
			if(($file=array_pop($segs))!==null && ($root=self::getPathOfAlias($alias))!==null)
				return rtrim($root.DIRECTORY_SEPARATOR.implode(DIRECTORY_SEPARATOR ,$segs),'/\\').(($file==='*')?'':DIRECTORY_SEPARATOR.$file.$ext);
			else
				return null;
		}
	}
	public static function getPathOfAlias($alias)
	{
		return isset(self::$_aliases[$alias])?self::$_aliases[$alias]:null;
	}
	protected static function getPathAliases()
	{
		return self::$_aliases;
	}
	public static function setPathOfAlias($alias,$path)
	{
		if(isset(self::$_aliases[$alias]))
			throw new TInvalidOperationException('prado_alias_redefined',$alias);
		else if(($rp=realpath($path))!==false && is_dir($rp))
		{
			if(strpos($alias,'.')===false)
				self::$_aliases[$alias]=$rp;
			else
				throw new TInvalidDataValueException('prado_aliasname_invalid',$alias);
		}
		else
			throw new TInvalidDataValueException('prado_alias_invalid',$alias,$path);
	}
	public static function fatalError($msg)
	{
		echo '<h1>Fatal Error</h1>';
		echo '<p>'.$msg.'</p>';
		if(!function_exists('debug_backtrace'))
			return;
		echo '<h2>Debug Backtrace</h2>';
		echo '<pre>';
		$index=-1;
		foreach(debug_backtrace() as $t)
		{
			$index++;
			if($index==0)  
				continue;
			echo '#'.$index.' ';
			if(isset($t['file']))
				echo basename($t['file']) . ':' . $t['line'];
			else
			   echo '<PHP inner-code>';
			echo ' -- ';
			if(isset($t['class']))
				echo $t['class'] . $t['type'];
			echo $t['function'] . '(';
			if(isset($t['args']) && sizeof($t['args']) > 0)
			{
				$count=0;
				foreach($t['args'] as $item)
				{
					if(is_string($item))
					{
						$str=htmlentities(str_replace("\r\n", "", $item), ENT_QUOTES);
						if (strlen($item) > 70)
							echo "'". substr($str, 0, 70) . "...'";
						else
							echo "'" . $str . "'";
					}
					else if (is_int($item) || is_float($item))
						echo $item;
					else if (is_object($item))
						echo get_class($item);
					else if (is_array($item))
						echo 'array(' . count($item) . ')';
					else if (is_bool($item))
						echo $item ? 'true' : 'false';
					else if (is_null($item))
						echo 'NULL';
					else if (is_resource($item))
						echo get_resource_type($item);
					$count++;
					if (count($t['args']) > $count)
						echo ', ';
				}
			}
			echo ")\n";
		}
		echo '</pre>';
		exit(1);
	}
	public static function getUserLanguages()
	{
		static $languages=null;
		if($languages===null)
		{
			if(!isset($_SERVER['HTTP_ACCEPT_LANGUAGE']))
				$languages[0]='en';
			else
			{
				$languages=array();
				foreach(explode(',',$_SERVER['HTTP_ACCEPT_LANGUAGE']) as $language)
				{
					$array=split(';q=',trim($language));
					$languages[trim($array[0])]=isset($array[1])?(float)$array[1]:1.0;
				}
				arsort($languages);
				$languages=array_keys($languages);
				if(empty($languages))
					$languages[0]='en';
			}
		}
		return $languages;
	}
	public static function getPreferredLanguage()
	{
		static $language=null;
		if($language===null)
		{
			$langs=Prado::getUserLanguages();
			$lang=explode('-',$langs[0]);
			if(empty($lang[0]) || !ctype_alpha($lang[0]))
				$language='en';
			else
				$language=$lang[0];
		}
		return $language;
	}
	public static function trace($msg,$category='Uncategorized')
	{
		if(self::$_application && self::$_application->getMode()===TApplicationMode::Performance)
			return;
		if(!self::$_application || self::$_application->getMode()===TApplicationMode::Debug)
		{
			$trace=debug_backtrace();
			if(isset($trace[0]['file']) && isset($trace[0]['line']))
				$msg.=" (line {$trace[0]['line']}, {$trace[0]['file']})";
			$level=TLogger::DEBUG;
		}
		else
			$level=TLogger::INFO;
		self::log($msg,$level,$category);
	}
	public static function log($msg,$level=TLogger::INFO,$category='Uncategorized')
	{
		if(self::$_logger===null)
			self::$_logger=new TLogger;
		self::$_logger->log($msg,$level,$category);
	}
	public static function getLogger()
	{
		if(self::$_logger===null)
			self::$_logger=new TLogger;
		return self::$_logger;
	}
	public static function varDump($var,$depth=10,$highlight=false)
	{
		Prado::using('System.Util.TVarDumper');
		return TVarDumper::dump($var,$depth,$highlight);
	}
	public static function localize($text, $parameters=array(), $catalogue=null, $charset=null)
	{
		Prado::using('System.I18N.Translation');
		$app = Prado::getApplication()->getGlobalization(false);
		$params = array();
		foreach($parameters as $key => $value)
			$params['{'.$key.'}'] = $value;
		if($app===null || ($config = $app->getTranslationConfiguration())===null)
			return strtr($text, $params);
		Translation::init();
		if(empty($catalogue) && isset($config['catalogue']))
			$catalogue = $config['catalogue'];
		$appCharset = $app===null ? '' : $app->getCharset();
		$defaultCharset = ($app===null) ? 'UTF-8' : $app->getDefaultCharset();
		if(empty($charset)) $charset = $appCharset;
		if(empty($charset)) $charset = $defaultCharset;
		return Translation::formatter()->format($text,$params,$catalogue,$charset);
	}
}
class TReflectionClass extends ReflectionClass
{
}
PradoBase::using('System.TComponent');
PradoBase::using('System.Exceptions.TException');
PradoBase::using('System.Util.TLogger');
if(!class_exists('Prado',false))
{
	class Prado extends PradoBase
	{
	}
}
spl_autoload_register(array('Prado','autoload'));
Prado::initErrorHandlers();
interface IModule
{
	public function init($config);
	public function getID();
	public function setID($id);
}
interface IService
{
	public function init($config);
	public function getID();
	public function setID($id);
	public function getEnabled();
	public function setEnabled($value);
	public function run();
}
interface ITextWriter
{
	public function write($str);
	public function flush();
}
interface IUser
{
	public function getName();
	public function setName($value);
	public function getIsGuest();
	public function setIsGuest($value);
	public function getRoles();
	public function setRoles($value);
	public function isInRole($role);
	public function saveToString();
	public function loadFromString($string);
}
interface IStatePersister
{
	public function load();
	public function save($state);
}
interface ICache
{
	public function get($id);
	public function set($id,$value,$expire=0,$dependency=null);
	public function add($id,$value,$expire=0,$dependency=null);
	public function delete($id);
	public function flush();
}
interface ICacheDependency
{
	public function getHasChanged();
}
interface IRenderable
{
	public function render($writer);
}
interface IBindable
{
	public function dataBind();
}
interface IStyleable
{
	public function getHasStyle();
	public function getStyle();
	public function clearStyle();
}
interface IActiveControl
{
	public function getActiveControl();
}
interface ICallbackEventHandler
{
	public function raiseCallbackEvent($eventArgument);
}
interface IDataRenderer
{
	public function getData();
	public function setData($value);
}
class TApplicationComponent extends TComponent
{
	public function getApplication()
	{
		return Prado::getApplication();
	}
	public function getService()
	{
		return Prado::getApplication()->getService();
	}
	public function getRequest()
	{
		return Prado::getApplication()->getRequest();
	}
	public function getResponse()
	{
		return Prado::getApplication()->getResponse();
	}
	public function getSession()
	{
		return Prado::getApplication()->getSession();
	}
	public function getUser()
	{
		return Prado::getApplication()->getUser();
	}
	public function publishAsset($assetPath,$className=null)
	{
		if($className===null)
			$className=get_class($this);
		$class=new ReflectionClass($className);
		$fullPath=dirname($class->getFileName()).DIRECTORY_SEPARATOR.$assetPath;
		return $this->publishFilePath($fullPath);
	}
	public function publishFilePath($fullPath)
	{
		return Prado::getApplication()->getAssetManager()->publishFilePath($fullPath);
	}
}
abstract class TModule extends TApplicationComponent implements IModule
{
	private $_id;
	public function init($config)
	{
	}
	public function getID()
	{
		return $this->_id;
	}
	public function setID($value)
	{
		$this->_id=$value;
	}
}
abstract class TService extends TApplicationComponent implements IService
{
	private $_id;
	private $_enabled=true;
	public function init($config)
	{
	}
	public function getID()
	{
		return $this->_id;
	}
	public function setID($value)
	{
		$this->_id=$value;
	}
	public function getEnabled()
	{
		return $this->_enabled;
	}
	public function setEnabled($value)
	{
		$this->_enabled=TPropertyValue::ensureBoolean($value);
	}
	public function run()
	{
	}
}
class TErrorHandler extends TModule
{
	const ERROR_FILE_NAME='error';
	const EXCEPTION_FILE_NAME='exception';
	const SOURCE_LINES=12;
	private $_templatePath=null;
	public function init($config)
	{
		$this->getApplication()->setErrorHandler($this);
		if($this->_templatePath===null)
			$this->_templatePath=Prado::getFrameworkPath().'/Exceptions/templates';
	}
	public function getErrorTemplatePath()
	{
		return $this->_templatePath;
	}
	public function setErrorTemplatePath($value)
	{
		if(($templatePath=Prado::getPathOfNamespace($value))!==null && is_dir($templatePath))
			$this->_templatePath=$templatePath;
		else
			throw new TConfigurationException('errorhandler_errortemplatepath_invalid',$value);
	}
	public function handleError($sender,$param)
	{
		static $handling=false;
		restore_error_handler();
		restore_exception_handler();
		if($handling)
			$this->handleRecursiveError($param);
		else
		{
			$handling=true;
			if(($response=$this->getResponse())!==null)
				$response->clear();
			if(!headers_sent())
				header('Content-Type: text/html; charset=UTF-8');
			if($param instanceof THttpException)
				$this->handleExternalError($param->getStatusCode(),$param);
			else if($this->getApplication()->getMode()===TApplicationMode::Debug)
				$this->displayException($param);
			else
				$this->handleExternalError(500,$param);
		}
	}
	protected function handleExternalError($statusCode,$exception)
	{
		if(!($exception instanceof THttpException))
			error_log($exception->__toString());
		$content=$this->getErrorTemplate($statusCode,$exception);
		$serverAdmin=isset($_SERVER['SERVER_ADMIN'])?$_SERVER['SERVER_ADMIN']:'';
		if($this->getApplication()->getMode()===TApplicationMode::Debug)
			$version=$_SERVER['SERVER_SOFTWARE'].' <a href="http://www.pradosoft.com/">PRADO</a>/'.Prado::getVersion();
		else
			$version='';
		$tokens=array(
			'%%StatusCode%%' => "$statusCode",
			'%%ErrorMessage%%' => htmlspecialchars($exception->getMessage()),
			'%%ServerAdmin%%' => $serverAdmin,
			'%%Version%%' => $version,
			'%%Time%%' => @strftime('%Y-%m-%d %H:%M',time())
		);
		header("HTTP/1.0 $statusCode ".$exception->getErrorMessage());
		echo strtr($content,$tokens);
	}
	protected function handleRecursiveError($exception)
	{
		if($this->getApplication()->getMode()===TApplicationMode::Debug)
		{
			echo "<html><head><title>Recursive Error</title></head>\n";
			echo "<body><h1>Recursive Error</h1>\n";
			echo "<pre>".$exception->__toString()."</pre>\n";
			echo "</body></html>";
		}
		else
		{
			error_log("Error happened while processing an existing error:\n".$exception->__toString());
			header('HTTP/1.0 500 Internal Error');
		}
	}
	protected function displayException($exception)
	{
		if(php_sapi_name()==='cli')
		{
			echo $exception->getMessage()."\n";
			echo $exception->getTraceAsString();
			return;
		}
		if($exception instanceof TTemplateException)
		{
			$fileName=$exception->getTemplateFile();
			$lines=empty($fileName)?explode("\n",$exception->getTemplateSource()):@file($fileName);
			$source=$this->getSourceCode($lines,$exception->getLineNumber());
			if($fileName==='')
				$fileName='---embedded template---';
			$errorLine=$exception->getLineNumber();
		}
		else
		{
			if(($trace=$this->getExactTrace($exception))!==null)
			{
				$fileName=$trace['file'];
				$errorLine=$trace['line'];
			}
			else
			{
				$fileName=$exception->getFile();
				$errorLine=$exception->getLine();
			}
			$source=$this->getSourceCode(@file($fileName),$errorLine);
		}
		if($this->getApplication()->getMode()===TApplicationMode::Debug)
			$version=$_SERVER['SERVER_SOFTWARE'].' <a href="http://www.pradosoft.com/">PRADO</a>/'.Prado::getVersion();
		else
			$version='';
		$tokens=array(
			'%%ErrorType%%' => get_class($exception),
			'%%ErrorMessage%%' => $this->addLink(htmlspecialchars($exception->getMessage())),
			'%%SourceFile%%' => htmlspecialchars($fileName).' ('.$errorLine.')',
			'%%SourceCode%%' => $source,
			'%%StackTrace%%' => htmlspecialchars($exception->getTraceAsString()),
			'%%Version%%' => $version,
			'%%Time%%' => @strftime('%Y-%m-%d %H:%M',time())
		);
		$content=$this->getExceptionTemplate($exception);
		echo strtr($content,$tokens);
	}
	protected function getExceptionTemplate($exception)
	{
		$lang=Prado::getPreferredLanguage();
		$exceptionFile=Prado::getFrameworkPath().'/Exceptions/templates/'.self::EXCEPTION_FILE_NAME.'-'.$lang.'.html';
		if(!is_file($exceptionFile))
			$exceptionFile=Prado::getFrameworkPath().'/Exceptions/templates/'.self::EXCEPTION_FILE_NAME.'.html';
		if(($content=@file_get_contents($exceptionFile))===false)
			die("Unable to open exception template file '$exceptionFile'.");
		return $content;
	}
	protected function getErrorTemplate($statusCode,$exception)
	{
		$base=$this->getErrorTemplatePath().DIRECTORY_SEPARATOR.self::ERROR_FILE_NAME;
		$lang=Prado::getPreferredLanguage();
		if(is_file("$base$statusCode-$lang.html"))
			$errorFile="$base$statusCode-$lang.html";
		else if(is_file("$base$statusCode.html"))
			$errorFile="$base$statusCode.html";
		else if(is_file("$base-$lang.html"))
			$errorFile="$base-$lang.html";
		else
			$errorFile="$base.html";
		if(($content=@file_get_contents($errorFile))===false)
			die("Unable to open error template file '$errorFile'.");
		return $content;
	}
	private function getExactTrace($exception)
	{
		$trace=$exception->getTrace();
		$result=null;
		if($exception instanceof TPhpErrorException)
			$result=isset($trace[0]['file'])?$trace[0]:$trace[1];
		else if($exception instanceof TInvalidOperationException)
		{
			if(($result=$this->getPropertyAccessTrace($trace,'__get'))===null)
				$result=$this->getPropertyAccessTrace($trace,'__set');
		}
		if($result!==null && strpos($result['file'],': eval()\'d code')!==false)
			return null;
		return $result;
	}
	private function getPropertyAccessTrace($trace,$pattern)
	{
		$result=null;
		foreach($trace as $t)
		{
			if(isset($t['function']) && $t['function']===$pattern)
				$result=$t;
			else
				break;
		}
		return $result;
	}
	private function getSourceCode($lines,$errorLine)
	{
		$beginLine=$errorLine-self::SOURCE_LINES>=0?$errorLine-self::SOURCE_LINES:0;
		$endLine=$errorLine+self::SOURCE_LINES<=count($lines)?$errorLine+self::SOURCE_LINES:count($lines);
		$source='';
		for($i=$beginLine;$i<$endLine;++$i)
		{
			if($i===$errorLine-1)
			{
				$line=htmlspecialchars(sprintf("%04d: %s",$i+1,str_replace("\t",'    ',$lines[$i])));
				$source.="<div class=\"error\">".$line."</div>";
			}
			else
				$source.=htmlspecialchars(sprintf("%04d: %s",$i+1,str_replace("\t",'    ',$lines[$i])));
		}
		return $source;
	}
	private function addLink($message)
	{
		$baseUrl='http://www.pradosoft.com/docs/classdoc';
		return preg_replace('/\b(T[A-Z]\w+)\b/',"<a href=\"$baseUrl/\${1}\" target=\"_blank\">\${1}</a>",$message);
	}
}
class TList extends TComponent implements IteratorAggregate,ArrayAccess,Countable
{
	private $_d=array();
	private $_c=0;
	private $_r=false;
	public function __construct($data=null,$readOnly=false)
	{
		if($data!==null)
			$this->copyFrom($data);
		$this->setReadOnly($readOnly);
	}
	public function getReadOnly()
	{
		return $this->_r;
	}
	protected function setReadOnly($value)
	{
		$this->_r=TPropertyValue::ensureBoolean($value);
	}
	public function getIterator()
	{
		return new TListIterator($this->_d);
	}
	public function count()
	{
		return $this->getCount();
	}
	public function getCount()
	{
		return $this->_c;
	}
	public function itemAt($index)
	{
		if($index>=0 && $index<$this->_c)
			return $this->_d[$index];
		else
			throw new TInvalidDataValueException('list_index_invalid',$index);
	}
	public function add($item)
	{
		$this->insertAt($this->_c,$item);
		return $this->_c-1;
	}
	public function insertAt($index,$item)
	{
		if(!$this->_r)
		{
			if($index===$this->_c)
				$this->_d[$this->_c++]=$item;
			else if($index>=0 && $index<$this->_c)
			{
				array_splice($this->_d,$index,0,array($item));
				$this->_c++;
			}
			else
				throw new TInvalidDataValueException('list_index_invalid',$index);
		}
		else
			throw new TInvalidOperationException('list_readonly',get_class($this));
	}
	public function remove($item)
	{
		if(($index=$this->indexOf($item))>=0)
		{
			$this->removeAt($index);
			return $index;
		}
		else
			throw new TInvalidDataValueException('list_item_inexistent');
	}
	public function removeAt($index)
	{
		if(!$this->_r)
		{
			if($index>=0 && $index<$this->_c)
			{
				$this->_c--;
				if($index===$this->_c)
					return array_pop($this->_d);
				else
				{
					$item=$this->_d[$index];
					array_splice($this->_d,$index,1);
					return $item;
				}
			}
			else
				throw new TInvalidDataValueException('list_index_invalid',$index);
		}
		else
			throw new TInvalidOperationException('list_readonly',get_class($this));
	}
	public function clear()
	{
		for($i=$this->_c-1;$i>=0;--$i)
			$this->removeAt($i);
	}
	public function contains($item)
	{
		return $this->indexOf($item)>=0;
	}
	public function indexOf($item)
	{
		if(($index=array_search($item,$this->_d,true))===false)
			return -1;
		else
			return $index;
	}
	public function toArray()
	{
		return $this->_d;
	}
	public function copyFrom($data)
	{
		if(is_array($data) || ($data instanceof Traversable))
		{
			if($this->_c>0)
				$this->clear();
			foreach($data as $item)
				$this->add($item);
		}
		else if($data!==null)
			throw new TInvalidDataTypeException('list_data_not_iterable');
	}
	public function mergeWith($data)
	{
		if(is_array($data) || ($data instanceof Traversable))
		{
			foreach($data as $item)
				$this->add($item);
		}
		else if($data!==null)
			throw new TInvalidDataTypeException('list_data_not_iterable');
	}
	public function offsetExists($offset)
	{
		return ($offset>=0 && $offset<$this->_c);
	}
	public function offsetGet($offset)
	{
		return $this->itemAt($offset);
	}
	public function offsetSet($offset,$item)
	{
		if($offset===null || $offset===$this->_c)
			$this->insertAt($this->_c,$item);
		else
		{
			$this->removeAt($offset);
			$this->insertAt($offset,$item);
		}
	}
	public function offsetUnset($offset)
	{
		$this->removeAt($offset);
	}
}
class TListIterator implements Iterator
{
	private $_d;
	private $_i;
	private $_c;
	public function __construct(&$data)
	{
		$this->_d=&$data;
		$this->_i=0;
		$this->_c=count($this->_d);
	}
	public function rewind()
	{
		$this->_i=0;
	}
	public function key()
	{
		return $this->_i;
	}
	public function current()
	{
		return $this->_d[$this->_i];
	}
	public function next()
	{
		$this->_i++;
	}
	public function valid()
	{
		return $this->_i<$this->_c;
	}
}
abstract class TCache extends TModule implements ICache, ArrayAccess
{
	private $_prefix=null;
	private $_primary=true;
	public function init($config)
	{
		if($this->_prefix===null)
			$this->_prefix=$this->getApplication()->getUniqueID();
		if($this->_primary)
		{
			if($this->getApplication()->getCache()===null)
				$this->getApplication()->setCache($this);
			else
				throw new TConfigurationException('cache_primary_duplicated',get_class($this));
		}
	}
	public function getPrimaryCache()
	{
		return $this->_primary;
	}
	public function setPrimaryCache($value)
	{
		$this->_primary=TPropertyValue::ensureBoolean($value);
	}
	public function getKeyPrefix()
	{
		return $this->_prefix;
	}
	public function setKeyPrefix($value)
	{
		$this->_prefix=$value;
	}
	protected function generateUniqueKey($key)
	{
		return md5($this->_prefix.$key);
	}
	public function get($id)
	{
		if(($value=$this->getValue($this->generateUniqueKey($id)))!==false)
		{
			$data=unserialize($value);
			if(!is_array($data))
				return false;
			if(!($data[1] instanceof ICacheDependency) || !$data[1]->getHasChanged())
				return $data[0];
		}
		return false;
	}
	public function set($id,$value,$expire=0,$dependency=null)
	{
		$data=array($value,$dependency);
		return $this->setValue($this->generateUniqueKey($id),serialize($data),$expire);
	}
	public function add($id,$value,$expire=0,$dependency=null)
	{
		$data=array($value,$dependency);
		return $this->addValue($this->generateUniqueKey($id),serialize($data),$expire);
	}
	public function delete($id)
	{
		return $this->deleteValue($this->generateUniqueKey($id));
	}
	public function flush()
	{
		throw new TNotSupportedException('cache_flush_unsupported');
	}
	abstract protected function getValue($key);
	abstract protected function setValue($key,$value,$expire);
	abstract protected function addValue($key,$value,$expire);
	abstract protected function deleteValue($key);
	public function offsetExists($id)
	{
		return $this->get($id) !== false;
	}
	public function offsetGet($id)
	{
		return $this->get($id);
	}
	public function offsetSet($id, $value)
	{
		$this->set($id, $value);
	}
	public function offsetUnset($id)
	{
		$this->delete($id);
	}
}
abstract class TCacheDependency extends TComponent implements ICacheDependency
{
}
class TFileCacheDependency extends TCacheDependency
{
	private $_fileName;
	private $_timestamp;
	public function __construct($fileName)
	{
		$this->setFileName($fileName);
	}
	public function getFileName()
	{
		return $this->_fileName;
	}
	public function setFileName($value)
	{
		$this->_fileName=$value;
		$this->_timestamp=@filemtime($value);
	}
	public function getTimestamp()
	{
		return $this->_timestamp;
	}
	public function getHasChanged()
	{
		return @filemtime($this->_fileName)!==$this->_timestamp;
	}
}
class TDirectoryCacheDependency extends TCacheDependency
{
	private $_recursiveCheck=true;
	private $_recursiveLevel=-1;
	private $_timestamps;
	private $_directory;
	public function __construct($directory)
	{
		$this->setDirectory($directory);
	}
	public function getDirectory()
	{
		return $this->_directory;
	}
	public function setDirectory($directory)
	{
		if(($path=realpath($directory))===false || !is_dir($path))
			throw new TInvalidDataValueException('directorycachedependency_directory_invalid',$directory);
		$this->_directory=$path;
		$this->_timestamps=$this->generateTimestamps($path);
	}
	public function getRecursiveCheck()
	{
		return $this->_recursiveCheck;
	}
	public function setRecursiveCheck($value)
	{
		$this->_recursiveCheck=TPropertyValue::ensureBoolean($value);
	}
	public function getRecursiveLevel()
	{
		return $this->_recursiveLevel;
	}
	public function setRecursiveLevel($value)
	{
		$this->_recursiveLevel=TPropertyValue::ensureInteger($value);
	}
	public function getHasChanged()
	{
		return $this->generateTimestamps($this->_directory)!=$this->_timestamps;
	}
	protected function validateFile($fileName)
	{
		return true;
	}
	protected function validateDirectory($directory)
	{
		return true;
	}
	protected function generateTimestamps($directory,$level=0)
	{
		if(($dir=opendir($directory))===false)
			throw new TIOException('directorycachedependency_directory_invalid',$directory);
		$timestamps=array();
		while(($file=readdir($dir))!==false)
		{
			$path=$directory.DIRECTORY_SEPARATOR.$file;
			if($file==='.' || $file==='..')
				continue;
			else if(is_dir($path))
			{
				if(($this->_recursiveLevel<0 || $level<$this->_recursiveLevel) && $this->validateDirectory($path))
					$timestamps=array_merge($this->generateTimestamps($path,$level+1));
			}
			else if($this->validateFile($path))
				$timestamps[$path]=filemtime($path);
		}
		closedir($dir);
		return $timestamps;
	}
}
class TGlobalStateCacheDependency extends TCacheDependency
{
	private $_stateName;
	private $_stateValue;
	public function __construct($name)
	{
		$this->setStateName($name);
	}
	public function getStateName()
	{
		return $this->_stateName;
	}
	public function setStateName($value)
	{
		$this->_stateName=$value;
		$this->_stateValue=Prado::getApplication()->getGlobalState($value);
	}
	public function getHasChanged()
	{
		return $this->_stateValue!==Prado::getApplication()->getGlobalState($this->_stateName);
	}
}
class TChainedCacheDependency extends TCacheDependency
{
	private $_dependencies=null;
	public function getDependencies()
	{
		if($this->_dependencies===null)
			$this->_dependencies=new TCacheDependencyList;
		return $this->_dependencies;
	}
	public function getHasChanged()
	{
		if($this->_dependencies!==null)
		{
			foreach($this->_dependencies as $dependency)
				if($dependency->getHasChanged())
					return true;
		}
		return false;
	}
}
class TApplicationStateCacheDependency extends TCacheDependency
{
	public function getHasChanged()
	{
		return Prado::getApplication()->getMode()!==TApplicationMode::Performance;
	}
}
class TCacheDependencyList extends TList
{
	public function insertAt($index,$item)
	{
		if($item instanceof ICacheDependency)
			parent::insertAt($index,$item);
		else
			throw new TInvalidDataTypeException('cachedependencylist_cachedependency_required');
	}
}
class TTextWriter extends TComponent implements ITextWriter
{
	private $_str='';
	public function flush()
	{
		$str=$this->_str;
		$this->_str='';
		return $str;
	}
	public function write($str)
	{
		$this->_str.=$str;
	}
	public function writeLine($str='')
	{
		$this->write($str."\n");
	}
}
class TMap extends TComponent implements IteratorAggregate,ArrayAccess,Countable
{
	private $_d=array();
	private $_r=false;
	public function __construct($data=null,$readOnly=false)
	{
		if($data!==null)
			$this->copyFrom($data);
		$this->setReadOnly($readOnly);
	}
	public function getReadOnly()
	{
		return $this->_r;
	}
	protected function setReadOnly($value)
	{
		$this->_r=TPropertyValue::ensureBoolean($value);
	}
	public function getIterator()
	{
		return new TMapIterator($this->_d);
	}
	public function count()
	{
		return $this->getCount();
	}
	public function getCount()
	{
		return count($this->_d);
	}
	public function getKeys()
	{
		return array_keys($this->_d);
	}
	public function itemAt($key)
	{
		return isset($this->_d[$key]) ? $this->_d[$key] : null;
	}
	public function add($key,$value)
	{
		if(!$this->_r)
			$this->_d[$key]=$value;
		else
			throw new TInvalidOperationException('map_readonly',get_class($this));
	}
	public function remove($key)
	{
		if(!$this->_r)
		{
			if(isset($this->_d[$key]) || array_key_exists($key,$this->_d))
			{
				$value=$this->_d[$key];
				unset($this->_d[$key]);
				return $value;
			}
			else
				return null;
		}
		else
			throw new TInvalidOperationException('map_readonly',get_class($this));
	}
	public function clear()
	{
		foreach(array_keys($this->_d) as $key)
			$this->remove($key);
	}
	public function contains($key)
	{
		return isset($this->_d[$key]) || array_key_exists($key,$this->_d);
	}
	public function toArray()
	{
		return $this->_d;
	}
	public function copyFrom($data)
	{
		if(is_array($data) || $data instanceof Traversable)
		{
			if($this->getCount()>0)
				$this->clear();
			foreach($data as $key=>$value)
				$this->add($key,$value);
		}
		else if($data!==null)
			throw new TInvalidDataTypeException('map_data_not_iterable');
	}
	public function mergeWith($data)
	{
		if(is_array($data) || $data instanceof Traversable)
		{
			foreach($data as $key=>$value)
				$this->add($key,$value);
		}
		else if($data!==null)
			throw new TInvalidDataTypeException('map_data_not_iterable');
	}
	public function offsetExists($offset)
	{
		return $this->contains($offset);
	}
	public function offsetGet($offset)
	{
		return $this->itemAt($offset);
	}
	public function offsetSet($offset,$item)
	{
		$this->add($offset,$item);
	}
	public function offsetUnset($offset)
	{
		$this->remove($offset);
	}
}
class TMapIterator implements Iterator
{
	private $_d;
	private $_keys;
	private $_key;
	public function __construct(&$data)
	{
		$this->_d=&$data;
		$this->_keys=array_keys($data);
	}
	public function rewind()
	{
		$this->_key=reset($this->_keys);
	}
	public function key()
	{
		return $this->_key;
	}
	public function current()
	{
		return $this->_d[$this->_key];
	}
	public function next()
	{
		$this->_key=next($this->_keys);
	}
	public function valid()
	{
		return $this->_key!==false;
	}
}
class TStack extends TComponent implements IteratorAggregate,Countable
{
	private $_d=array();
	private $_c=0;
	public function __construct($data=null)
	{
		if($data!==null)
			$this->copyFrom($data);
	}
	public function toArray()
	{
		return $this->_d;
	}
	public function copyFrom($data)
	{
		if(is_array($data) || ($data instanceof Traversable))
		{
			$this->clear();
			foreach($data as $item)
			{
				$this->_d[]=$item;
				++$this->_c;
			}
		}
		else if($data!==null)
			throw new TInvalidDataTypeException('stack_data_not_iterable');
	}
	public function clear()
	{
		$this->_c=0;
		$this->_d=array();
	}
	public function contains($item)
	{
		return array_search($item,$this->_d,true)!==false;
	}
	public function peek()
	{
		if($this->_c===0)
			throw new TInvalidOperationException('stack_empty');
		else
			return $this->_d[$this->_c-1];
	}
	public function pop()
	{
		if($this->_c===0)
			throw new TInvalidOperationException('stack_empty');
		else
		{
			--$this->_c;
			return array_pop($this->_d);
		}
	}
	public function push($item)
	{
		++$this->_c;
		array_push($this->_d,$item);
	}
	public function getIterator()
	{
		return new TStackIterator($this->_d);
	}
	public function getCount()
	{
		return $this->_c;
	}
	public function count()
	{
		return $this->getCount();
	}
}
class TStackIterator implements Iterator
{
	private $_d;
	private $_i;
	private $_c;
	public function __construct(&$data)
	{
		$this->_d=&$data;
		$this->_i=0;
		$this->_c=count($this->_d);
	}
	public function rewind()
	{
		$this->_i=0;
	}
	public function key()
	{
		return $this->_i;
	}
	public function current()
	{
		return $this->_d[$this->_i];
	}
	public function next()
	{
		$this->_i++;
	}
	public function valid()
	{
		return $this->_i<$this->_c;
	}
}
class TXmlElement extends TComponent
{
	private $_parent=null;
	private $_tagName='unknown';
	private $_value='';
	private $_elements=null;
	private $_attributes=null;
	public function __construct($tagName)
	{
		$this->setTagName($tagName);
	}
	public function getParent()
	{
		return $this->_parent;
	}
	public function setParent($parent)
	{
		$this->_parent=$parent;
	}
	public function getTagName()
	{
		return $this->_tagName;
	}
	public function setTagName($tagName)
	{
		$this->_tagName=$tagName;
	}
	public function getValue()
	{
		return $this->_value;
	}
	public function setValue($value)
	{
		$this->_value=$value;
	}
	public function getHasElement()
	{
		return $this->_elements!==null && $this->_elements->getCount()>0;
	}
	public function getHasAttribute()
	{
		return $this->_attributes!==null && $this->_attributes->getCount()>0;
	}
	public function getAttribute($name)
	{
		if($this->_attributes!==null)
			return $this->_attributes->itemAt($name);
		else
			return null;
	}
	public function setAttribute($name,$value)
	{
		$this->getAttributes()->add($name,$value);
	}
	public function getElements()
	{
		if(!$this->_elements)
			$this->_elements=new TXmlElementList($this);
		return $this->_elements;
	}
	public function getAttributes()
	{
		if(!$this->_attributes)
			$this->_attributes=new TMap;
		return $this->_attributes;
	}
	public function getElementByTagName($tagName)
	{
		if($this->_elements)
		{
			foreach($this->_elements as $element)
				if($element->_tagName===$tagName)
					return $element;
		}
		return null;
	}
	public function getElementsByTagName($tagName)
	{
		$list=new TList;
		if($this->_elements)
		{
			foreach($this->_elements as $element)
				if($element->_tagName===$tagName)
					$list->add($element);
		}
		return $list;
	}
	public function toString($indent=0)
	{
		$attr='';
		if($this->_attributes!==null)
		{
			foreach($this->_attributes as $name=>$value)
			{
				$value=$this->xmlEncode($value);
				$attr.=" $name=\"$value\"";
			}
		}
		$prefix=str_repeat(' ',$indent*4);
		if($this->getHasElement())
		{
			$str=$prefix."<{$this->_tagName}$attr>\n";
			foreach($this->getElements() as $element)
				$str.=$element->toString($indent+1)."\n";
			$str.=$prefix."</{$this->_tagName}>";
			return $str;
		}
		else if(($value=$this->getValue())!=='')
		{
			$value=$this->xmlEncode($value);
			return $prefix."<{$this->_tagName}$attr>$value</{$this->_tagName}>";
		}
		else
			return $prefix."<{$this->_tagName}$attr />";
	}
	public function __toString()
	{
		return $this->toString();
	}
	private function xmlEncode($str)
	{
		return strtr($str,array(
			'>'=>'&gt;',
			'<'=>'&lt;',
			'&'=>'&amp;',
			'"'=>'&quot;',
			"\r"=>'&#xD;',
			"\t"=>'&#x9;',
			"\n"=>'&#xA;'));
	}
}
class TXmlDocument extends TXmlElement
{
	private $_version;
	private $_encoding;
	public function __construct($version='1.0',$encoding='')
	{
		parent::__construct('');
		$this->setversion($version);
		$this->setEncoding($encoding);
	}
	public function getVersion()
	{
		return $this->_version;
	}
	public function setVersion($version)
	{
		$this->_version=$version;
	}
	public function getEncoding()
	{
		return $this->_encoding;
	}
	public function setEncoding($encoding)
	{
		$this->_encoding=$encoding;
	}
	public function loadFromFile($file)
	{
		if(($str=@file_get_contents($file))!==false)
			return $this->loadFromString($str);
		else
			throw new TIOException('xmldocument_file_read_failed',$file);
	}
	public function loadFromString($string)
	{
				$doc=new DOMDocument();
		if($doc->loadXML($string)===false)
			return false;
		$this->setEncoding($doc->encoding);
		$this->setVersion($doc->version);
		$element=$doc->documentElement;
		$this->setTagName($element->tagName);
		$this->setValue($element->nodeValue);
		$elements=$this->getElements();
		$attributes=$this->getAttributes();
		$elements->clear();
		$attributes->clear();
		foreach($element->attributes as $name=>$attr)
			$attributes->add($name,$attr->value);
		foreach($element->childNodes as $child)
		{
			if($child instanceof DOMElement)
				$elements->add($this->buildElement($child));
		}
		return true;
	}
	public function saveToFile($file)
	{
		if(($fw=fopen($file,'w'))!==false)
		{
			fwrite($fw,$this->saveToString());
			fclose($fw);
		}
		else
			throw new TIOException('xmldocument_file_write_failed',$file);
	}
	public function saveToString()
	{
		$version=empty($this->_version)?' version="1.0"':' version="'.$this->_version.'"';
		$encoding=empty($this->_encoding)?'':' encoding="'.$this->_encoding.'"';
		return "<?xml{$version}{$encoding}?>\n".$this->toString(0);
	}
	public function __toString()
	{
		return $this->saveToString();
	}
	private function buildElement($node)
	{
		$element=new TXmlElement($node->tagName);
		$element->setValue($node->nodeValue);
		foreach($node->attributes as $name=>$attr)
			$element->getAttributes()->add($name,$attr->value);
		foreach($node->childNodes as $child)
		{
			if($child instanceof DOMElement)
				$element->getElements()->add($this->buildElement($child));
		}
		return $element;
	}
}
class TXmlElementList extends TList
{
	private $_o;
	public function __construct(TXmlElement $owner)
	{
		$this->_o=$owner;
	}
	protected function getOwner()
	{
		return $this->_o;
	}
	public function insertAt($index,$item)
	{
		if($item instanceof TXmlElement)
		{
			parent::insertAt($index,$item);
			if($item->getParent()!==null)
				$item->getParent()->getElements()->remove($item);
			$item->setParent($this->_o);
		}
		else
			throw new TInvalidDataTypeException('xmlelementlist_xmlelement_required');
	}
	public function removeAt($index)
	{
		$item=parent::removeAt($index);
		if($item instanceof TXmlElement)
			$item->setParent(null);
		return $item;
	}
}
class TAuthorizationRule extends TComponent
{
	private $_action;
	private $_users;
	private $_roles;
	private $_verb;
	private $_ipRules;
	private $_everyone;
	private $_guest;
	private $_authenticated;
	public function __construct($action,$users,$roles,$verb='',$ipRules='')
	{
		$action=strtolower(trim($action));
		if($action==='allow' || $action==='deny')
			$this->_action=$action;
		else
			throw new TInvalidDataValueException('authorizationrule_action_invalid',$action);
		$this->_users=array();
		$this->_roles=array();
		$this->_ipRules=array();
		$this->_everyone=false;
		$this->_guest=false;
		$this->_authenticated=false;
		if(trim($users)==='')
			$users='*';
		foreach(explode(',',$users) as $user)
		{
			if(($user=trim(strtolower($user)))!=='')
			{
				if($user==='*')
				{
					$this->_everyone=true;
					break;
				}
				else if($user==='?')
					$this->_guest=true;
				else if($user==='@')
					$this->_authenticated=true;
				else
					$this->_users[]=$user;
			}
		}
		if(trim($roles)==='')
			$roles='*';
		foreach(explode(',',$roles) as $role)
		{
			if(($role=trim(strtolower($role)))!=='')
				$this->_roles[]=$role;
		}
		if(($verb=trim(strtolower($verb)))==='')
			$verb='*';
		if($verb==='*' || $verb==='get' || $verb==='post')
			$this->_verb=$verb;
		else
			throw new TInvalidDataValueException('authorizationrule_verb_invalid',$verb);
		if(trim($ipRules)==='')
			$ipRules='*';
		foreach(explode(',',$ipRules) as $ipRule)
		{
			if(($ipRule=trim($ipRule))!=='')
				$this->_ipRules[]=$ipRule;
		}
	}
	public function getAction()
	{
		return $this->_action;
	}
	public function getUsers()
	{
		return $this->_users;
	}
	public function getRoles()
	{
		return $this->_roles;
	}
	public function getVerb()
	{
		return $this->_verb;
	}
	public function getIPRules()
	{
		return $this->_ipRules;
	}
	public function getGuestApplied()
	{
		return $this->_guest || $this->_everyone;
	}
	public function getEveryoneApplied()
	{
		return $this->_everyone;
	}
	public function getAuthenticatedApplied()
	{
		return $this->_authenticated || $this->_everyone;
	}
	public function isUserAllowed(IUser $user,$verb,$ip)
	{
		if($this->isVerbMatched($verb) && $this->isIpMatched($ip) && $this->isUserMatched($user) && $this->isRoleMatched($user))
			return ($this->_action==='allow')?1:-1;
		else
			return 0;
	}
	private function isIpMatched($ip)
	{
		if(empty($this->_ipRules))
			return 1;
		foreach($this->_ipRules as $rule)
		{
			if($rule==='*' || $rule===$ip || (($pos=strpos($rule,'*'))!==false && strncmp($ip,$rule,$pos)===0))
				return 1;
		}
		return 0;
	}
	private function isUserMatched($user)
	{
		return ($this->_everyone || ($this->_guest && $user->getIsGuest()) || ($this->_authenticated && !$user->getIsGuest()) || in_array(strtolower($user->getName()),$this->_users));
	}
	private function isRoleMatched($user)
	{
		foreach($this->_roles as $role)
		{
			if($role==='*' || $user->isInRole($role))
				return true;
		}
		return false;
	}
	private function isVerbMatched($verb)
	{
		return ($this->_verb==='*' || strcasecmp($verb,$this->_verb)===0);
	}
}
class TAuthorizationRuleCollection extends TList
{
	public function isUserAllowed($user,$verb,$ip)
	{
		if($user instanceof IUser)
		{
			$verb=strtolower(trim($verb));
			foreach($this as $rule)
			{
				if(($decision=$rule->isUserAllowed($user,$verb,$ip))!==0)
					return ($decision>0);
			}
			return true;
		}
		else
			return false;
	}
	public function insertAt($index,$item)
	{
		if($item instanceof TAuthorizationRule)
			parent::insertAt($index,$item);
		else
			throw new TInvalidDataTypeException('authorizationrulecollection_authorizationrule_required');
	}
}
class TSecurityManager extends TModule
{
	const STATE_VALIDATION_KEY='prado:securitymanager:validationkey';
	const STATE_ENCRYPTION_KEY='prado:securitymanager:encryptionkey';
	private $_validationKey=null;
	private $_encryptionKey=null;
	private $_validation=TSecurityManagerValidationMode::SHA1;
	private $_encryption='3DES';
	public function init($config)
	{
		$this->getApplication()->setSecurityManager($this);
	}
	protected function generateRandomKey()
	{
		return rand().rand().rand().rand();
	}
	public function getValidationKey()
	{
		if($this->_validationKey===null)
		{
			if(($this->_validationKey=$this->getApplication()->getGlobalState(self::STATE_VALIDATION_KEY))===null)
			{
				$this->_validationKey=$this->generateRandomKey();
				$this->getApplication()->setGlobalState(self::STATE_VALIDATION_KEY,$this->_validationKey,null);
			}
		}
		return $this->_validationKey;
	}
	public function setValidationKey($value)
	{
		if($value!=='')
			$this->_validationKey=$value;
		else
			throw new TInvalidDataValueException('securitymanager_validationkey_invalid');
	}
	public function getEncryptionKey()
	{
		if($this->_encryptionKey===null)
		{
			if(($this->_encryptionKey=$this->getApplication()->getGlobalState(self::STATE_ENCRYPTION_KEY))===null)
			{
				$this->_encryptionKey=$this->generateRandomKey();
				$this->getApplication()->setGlobalState(self::STATE_ENCRYPTION_KEY,$this->_encryptionKey,null);
			}
		}
		return $this->_encryptionKey;
	}
	public function setEncryptionKey($value)
	{
		if($value!=='')
			$this->_encryptionKey=$value;
		else
			throw new TInvalidDataValueException('securitymanager_encryptionkey_invalid');
	}
	public function getValidation()
	{
		return $this->_validation;
	}
	public function setValidation($value)
	{
		$this->_validation=TPropertyValue::ensureEnum($value,'TSecurityManagerValidationMode');
	}
	public function getEncryption()
	{
		return $this->_encryption;
	}
	public function setEncryption($value)
	{
		throw new TNotSupportedException('Currently only 3DES encryption is supported');
	}
	public function encrypt($data)
	{
		if(function_exists('mcrypt_encrypt'))
		{
			$module=mcrypt_module_open(MCRYPT_3DES, '', MCRYPT_MODE_CBC, '');
			$key=substr(md5($this->getEncryptionKey()),0,mcrypt_enc_get_key_size($module));
			srand();
			$iv=mcrypt_create_iv(mcrypt_enc_get_iv_size($module), MCRYPT_RAND);
			mcrypt_generic_init($module,$key,$iv);
			$encrypted=$iv.mcrypt_generic($module,$data);
			mcrypt_generic_deinit($module);
			mcrypt_module_close($module);
			return $encrypted;
		}
		else
			throw new TNotSupportedException('securitymanager_mcryptextension_required');
	}
	public function decrypt($data)
	{
		if(function_exists('mcrypt_decrypt'))
		{
			$module=mcrypt_module_open(MCRYPT_3DES, '', MCRYPT_MODE_CBC, '');
			$key=substr(md5($this->getEncryptionKey()),0,mcrypt_enc_get_key_size($module));
			$ivSize=mcrypt_enc_get_iv_size($module);
			$iv=substr($data,0,$ivSize);
			mcrypt_generic_init($module,$key,$iv);
			$decrypted=mdecrypt_generic($module,substr($data,$ivSize));
			mcrypt_generic_deinit($module);
			mcrypt_module_close($module);
			return rtrim($decrypted,"\0");
		}
		else
			throw new TNotSupportedException('securitymanager_mcryptextension_required');
	}
	public function hashData($data)
	{
		$hmac=$this->computeHMAC($data);
		return $hmac.$data;
	}
	public function validateData($data)
	{
		$len=$this->_validation==='SHA1'?40:32;
		if(strlen($data)>=$len)
		{
			$hmac=substr($data,0,$len);
			$data2=substr($data,$len);
			return $hmac===$this->computeHMAC($data2)?$data2:false;
		}
		else
			return false;
	}
	protected function computeHMAC($data)
	{
		if($this->_validation==='SHA1')
		{
			$pack='H40';
			$func='sha1';
		}
		else
		{
			$pack='H32';
			$func='md5';
		}
		$key=$this->getValidationKey();
		$key=str_pad($func($key), 64, chr(0));
		return $func((str_repeat(chr(0x5C), 64) ^ substr($key, 0, 64)) . pack($pack, $func((str_repeat(chr(0x36), 64) ^ substr($key, 0, 64)) . $data)));
	}
}
class TSecurityManagerValidationMode extends TEnumerable
{
	const MD5='MD5';
	const SHA1='SHA1';
}
class THttpUtility
{
	private static $_encodeTable=array('<'=>'&lt;','>'=>'&gt;','"'=>'&quot;');
	private static $_decodeTable=array('&lt;'=>'<','&gt;'=>'>','&quot;'=>'"');
	public static function htmlEncode($s)
	{
		return strtr($s,self::$_encodeTable);
	}
	public static function htmlDecode($s)
	{
		return strtr($s,self::$_decodeTable);
	}
}
class TJavaScript
{
	private static $_json;
	public static function renderScriptFiles($files)
	{
		$str='';
		foreach($files as $file)
			$str.= self::renderScriptFile($file);
		return $str;
	}
	public static function renderScriptFile($file)
	{
		return '<script type="text/javascript" src="'.THttpUtility::htmlEncode($file)."\"></script>\n";
	}
	public static function renderScriptBlocks($scripts)
	{
		if(count($scripts))
			return "<script type=\"text/javascript\">\n/*<![CDATA[*/\n".implode("\n",$scripts)."\n/*]]>*/\n</script>\n";
		else
			return '';
	}
	public static function renderScriptBlock($script)
	{
		return "<script type=\"text/javascript\">\n/*<![CDATA[*/\n{$script}\n/*]]>*/\n</script>\n";
	}
	public static function quoteString($js,$forUrl=false)
	{
		if($forUrl)
			return strtr($js,array('%'=>'%25',"\t"=>'\t',"\n"=>'\n',"\r"=>'\r','"'=>'\"','\''=>'\\\'','\\'=>'\\\\'));
		else
			return strtr($js,array("\t"=>'\t',"\n"=>'\n',"\r"=>'\r','"'=>'\"','\''=>'\\\'','\\'=>'\\\\'));
	}
	public static function quoteFunction($js)
	{
		if(self::isFunction($js))
			return $js;
		else
			return 'javascript:'.$js;
	}
	public static function isFunction($js)
	{
		return preg_match('/^\s*javascript:/i', $js);
	}
	public static function encode($value,$toMap=true)
	{
		if(is_string($value))
		{
			if(($n=strlen($value))>2)
			{
				$first=$value[0];
				$last=$value[$n-1];
				if(($first==='[' && $last===']') || ($first==='{' && $last==='}'))
					return $value;
			}
			if(self::isFunction($value))
				return preg_replace('/^\s*javascript:/', '', $value);
			else
				return "'".self::quoteString($value)."'";
		}
		else if(is_bool($value))
			return $value?'true':'false';
		else if(is_array($value))
		{
			$results='';
			if(($n=count($value))>0 && array_keys($value)!==range(0,$n-1))
			{
				foreach($value as $k=>$v)
				{
					if($v!=='')
					{
						if($results!=='')
							$results.=',';
						$results.="'$k':".self::encode($v,$toMap);
					}
				}
				return '{'.$results.'}';
			}
			else
			{
				foreach($value as $v)
				{
					if($v!=='')
					{
						if($results!=='')
							$results.=',';
						$results.=self::encode($v,$toMap);
					}
				}
				return '['.$results.']';
			}
		}
		else if(is_integer($value))
			return "$value";
		else if(is_float($value))
		{
			if($value===-INF)
				return 'Number.NEGATIVE_INFINITY';
			else if($value===INF)
				return 'Number.POSITIVE_INFINITY';
			else
				return "$value";
		}
		else if(is_object($value))
			return self::encode(get_object_vars($value),$toMap);
		else if($value===null)
			return 'null';
		else
			return '';
	}
	public static function jsonEncode($value)
	{
		if(is_null(self::$_json))
			self::$_json = Prado::createComponent('System.Web.Javascripts.TJSON');
		return self::$_json->encode($value);
	}
	public static function jsonDecode($value)
	{
		if(is_null(self::$_json))
			self::$_json = Prado::createComponent('System.Web.Javascripts.TJSON');
		return self::$_json->decode($value);
	}
}
class TUrlManager extends TModule
{
	public function constructUrl($serviceID,$serviceParam,$getItems,$encodeAmpersand,$encodeGetItems)
	{
		$url=$serviceID.'='.urlencode($serviceParam);
		$amp=$encodeAmpersand?'&amp;':'&';
		$request=$this->getRequest();
		if(is_array($getItems) || $getItems instanceof Traversable)
		{
			if($encodeGetItems)
			{
				foreach($getItems as $name=>$value)
				{
					if(is_array($value))
					{
						$name=urlencode($name.'[]');
						foreach($value as $v)
							$url.=$amp.$name.'='.urlencode($v);
					}
					else
						$url.=$amp.urlencode($name).'='.urlencode($value);
				}
			}
			else
			{
				foreach($getItems as $name=>$value)
				{
					if(is_array($value))
					{
						foreach($value as $v)
							$url.=$amp.$name.'[]='.$v;
					}
					else
						$url.=$amp.$name.'='.$value;
				}
			}
		}
		if($request->getUrlFormat()===THttpRequestUrlFormat::Path)
			return $request->getApplicationUrl().'/'.strtr($url,array($amp=>'/','?'=>'/','='=>$request->getUrlParamSeparator()));
		else
			return $request->getApplicationUrl().'?'.$url;
	}
	public function parseUrl()
	{
		$request=$this->getRequest();
		$pathInfo=trim($request->getPathInfo(),'/');
		if($request->getUrlFormat()===THttpRequestUrlFormat::Path && $pathInfo!=='')
		{
			$separator=$request->getUrlParamSeparator();
			$paths=explode('/',$pathInfo);
			$getVariables=array();
			foreach($paths as $path)
			{
				if(($path=trim($path))!=='')
				{
					if(($pos=strpos($path,$separator))!==false)
					{
						$name=substr($path,0,$pos);
						$value=substr($path,$pos+1);
						if(($pos=strpos($name,'[]'))!==false)
							$getVariables[substr($name,0,$pos)][]=$value;
						else
							$getVariables[$name]=$value;
					}
					else
						$getVariables[$path]='';
				}
			}
			return $getVariables;
		}
		else
			return array();
	}
}
class THttpRequest extends TApplicationComponent implements IteratorAggregate,ArrayAccess,Countable,IModule
{
	private $_urlManager=null;
	private $_urlManagerID='';
	private $_separator=',';
	private $_serviceID=null;
	private $_serviceParam=null;
	private $_cookies=null;
	private $_requestUri;
	private $_pathInfo;
	private $_cookieOnly=false;
	private $_urlFormat=THttpRequestUrlFormat::Get;
	private $_services;
	private $_requestResolved=false;
	private $_enableCookieValidation=false;
	private $_url=null;
	private $_id;
	private $_items=array();
	public function getID()
	{
		return $this->_id;
	}
	public function setID($value)
	{
		$this->_id=$value;
	}
	public function init($config)
	{
		if(empty($this->_urlManagerID))
		{
			$this->_urlManager=new TUrlManager;
			$this->_urlManager->init(null);
		}
		else
		{
			$this->_urlManager=$this->getApplication()->getModule($this->_urlManagerID);
			if($this->_urlManager===null)
				throw new TConfigurationException('httprequest_urlmanager_inexist',$this->_urlManagerID);
			if(!($this->_urlManager instanceof TUrlManager))
				throw new TConfigurationException('httprequest_urlmanager_invalid',$this->_urlManagerID);
		}
				if(php_sapi_name()==='cli')
		{
			$_SERVER['REMOTE_ADDR']='127.0.0.1';
			$_SERVER['REQUEST_METHOD']='GET';
			$_SERVER['SERVER_NAME']='localhost';
			$_SERVER['SERVER_PORT']=80;
			$_SERVER['HTTP_USER_AGENT']='';
		}
		$this->_cookieOnly=(int)ini_get('session.use_cookies') && (int)ini_get('session.use_only_cookies');
														if(isset($_SERVER['REQUEST_URI']))
			$this->_requestUri=$_SERVER['REQUEST_URI'];
		else  			$this->_requestUri=$_SERVER['SCRIPT_NAME'].(empty($_SERVER['QUERY_STRING'])?'':'?'.$_SERVER['QUERY_STRING']);
		if(isset($_SERVER['PATH_INFO']))
			$this->_pathInfo=$_SERVER['PATH_INFO'];
		else if(strpos($_SERVER['PHP_SELF'],$_SERVER['SCRIPT_NAME'])===0 && $_SERVER['PHP_SELF']!==$_SERVER['SCRIPT_NAME'])
			$this->_pathInfo=substr($_SERVER['PHP_SELF'],strlen($_SERVER['SCRIPT_NAME']));
		else
			$this->_pathInfo='';
		if(get_magic_quotes_gpc())
		{
			if(isset($_GET))
				$_GET=$this->stripSlashes($_GET);
			if(isset($_POST))
				$_POST=$this->stripSlashes($_POST);
			if(isset($_REQUEST))
				$_REQUEST=$this->stripSlashes($_REQUEST);
			if(isset($_COOKIE))
				$_COOKIE=$this->stripSlashes($_COOKIE);
		}
		$this->getApplication()->setRequest($this);
	}
	public function stripSlashes(&$data)
	{
		return is_array($data)?array_map(array($this,'stripSlashes'),$data):stripslashes($data);
	}
	public function getUrl()
	{
		if($this->_url===null)
		{
			$secure=$this->getIsSecureConnection();
			$url=$secure?'https://':'http://';
			if(empty($_SERVER['HTTP_HOST']))
			{
				$url.=$_SERVER['SERVER_NAME'];
				$port=$_SERVER['SERVER_PORT'];
				if(($port!=80 && !$secure) || ($port!=443 && $secure))
					$url.=':'.$port;
			}
			else
				$url.=$_SERVER['HTTP_HOST'];
			$url.=$this->getRequestUri();
			$this->_url=new TUri($url);
		}
		return $this->_url;
	}
	public function getUrlManager()
	{
		return $this->_urlManagerID;
	}
	public function setUrlManager($value)
	{
		$this->_urlManagerID=$value;
	}
	public function getUrlManagerModule()
	{
		return $this->_urlManager;
	}
	public function getUrlFormat()
	{
		return $this->_urlFormat;
	}
	public function setUrlFormat($value)
	{
		$this->_urlFormat=TPropertyValue::ensureEnum($value,'THttpRequestUrlFormat');
	}
	public function getUrlParamSeparator()
	{
		return $this->_separator;
	}
	public function setUrlParamSeparator($value)
	{
		if(strlen($value)===1)
			$this->_separator=$value;
		else
			throw new TInvalidDataValueException('httprequest_separator_invalid');
	}
	public function getRequestType()
	{
		return $_SERVER['REQUEST_METHOD'];
	}
	public function getIsSecureConnection()
	{
	    return isset($_SERVER['HTTPS']) && strcasecmp($_SERVER['HTTPS'],'off');
	}
	public function getPathInfo()
	{
		return $this->_pathInfo;
	}
	public function getQueryString()
	{
		return isset($_SERVER['QUERY_STRING'])?$_SERVER['QUERY_STRING']:'';
	}
	public function getRequestUri()
	{
		return $this->_requestUri;
	}
	public function getBaseUrl($forceSecureConnection=false)
	{
		$secure=$this->getIsSecureConnection() || $forceSecureConnection;
		$url=($secure ? "https://" : "http://") . $_SERVER ['HTTP_HOST'];
		$port=$_SERVER['SERVER_PORT'];
		if(($port!=80 && !$secure) || ($port!=443 && $secure))
			$url.=':'.$port;
		return $url;
	}
	public function getApplicationUrl()
	{
		return $_SERVER['SCRIPT_NAME'];
	}
	public function getAbsoluteApplicationUrl($forceSecureConnection=false)
	{
		return $this->getBaseUrl($forceSecureConnection) . $this->getApplicationUrl();
	}
	public function getApplicationFilePath()
	{
		return realpath($_SERVER['SCRIPT_FILENAME']);
	}
	public function getServerName()
	{
		return $_SERVER['SERVER_NAME'];
	}
	public function getServerPort()
	{
		return $_SERVER['SERVER_PORT'];
	}
	public function getUrlReferrer()
	{
		return isset($_SERVER['HTTP_REFERER'])?$_SERVER['HTTP_REFERER']:null;
	}
	public function getBrowser()
	{
	    try
	    {
		    return get_browser();
	    }
	    catch(TPhpErrorException $e)
	    {
	        throw new TConfigurationException('httprequest_browscap_required');
	    }
	}
	public function getUserAgent()
	{
		return $_SERVER['HTTP_USER_AGENT'];
	}
	public function getUserHostAddress()
	{
		return $_SERVER['REMOTE_ADDR'];
	}
	public function getUserHost()
	{
		return isset($_SERVER['REMOTE_HOST'])?$_SERVER['REMOTE_HOST']:null;
	}
	public function getAcceptTypes()
	{
				return $_SERVER['HTTP_ACCEPT'];
	}
	public function getUserLanguages()
	{
		return Prado::getUserLanguages();
	}
	public function getEnableCookieValidation()
	{
		return $this->_enableCookieValidation;
	}
	public function setEnableCookieValidation($value)
	{
		$this->_enableCookieValidation=TPropertyValue::ensureBoolean($value);
	}
	public function getCookies()
	{
		if($this->_cookies===null)
		{
			$this->_cookies=new THttpCookieCollection;
			if($this->getEnableCookieValidation())
			{
				$sm=$this->getApplication()->getSecurityManager();
				foreach($_COOKIE as $key=>$value)
				{
					if(($value=$sm->validateData($value))!==false)
						$this->_cookies->add(new THttpCookie($key,$value));
				}
			}
			else
			{
				foreach($_COOKIE as $key=>$value)
					$this->_cookies->add(new THttpCookie($key,$value));
			}
		}
		return $this->_cookies;
	}
	public function getUploadedFiles()
	{
		return $_FILES;
	}
	public function getServerVariables()
	{
		return $_SERVER;
	}
	public function getEnvironmentVariables()
	{
		return $_ENV;
	}
	public function constructUrl($serviceID,$serviceParam,$getItems=null,$encodeAmpersand=true,$encodeGetItems=true)
	{
		$url=$this->_urlManager->constructUrl($serviceID,$serviceParam,$getItems,$encodeAmpersand,$encodeGetItems);
		if(defined('SID') && SID != '' && !$this->_cookieOnly)
			return $url . (strpos($url,'?')===false? '?' : ($encodeAmpersand?'&amp;':'&')) . SID;
		else
			return $url;
	}
	protected function parseUrl()
	{
		return $this->_urlManager->parseUrl();
	}
	public function resolveRequest($serviceIDs)
	{
		$getParams=$this->parseUrl();
		foreach($getParams as $name=>$value)
			$_GET[$name]=$value;
		$this->_items=array_merge($_GET,$_POST);
		$this->_requestResolved=true;
		foreach($serviceIDs as $serviceID)
		{
			if($this->contains($serviceID))
			{
				$this->setServiceID($serviceID);
				$this->setServiceParameter($this->itemAt($serviceID));
				return $serviceID;
			}
		}
		return null;
	}
	public function getRequestResolved()
	{
		return $this->_requestResolved;
	}
	public function getServiceID()
	{
		return $this->_serviceID;
	}
	public function setServiceID($value)
	{
		$this->_serviceID=$value;
	}
	public function getServiceParameter()
	{
		return $this->_serviceParam;
	}
	public function setServiceParameter($value)
	{
		$this->_serviceParam=$value;
	}
	public function getIterator()
	{
		return new TMapIterator($this->_items);
	}
	public function getCount()
	{
		return count($this->_items);
	}
	public function count()
	{
		return $this->getCount();
	}
	public function getKeys()
	{
		return array_keys($this->_items);
	}
	public function itemAt($key)
	{
		return isset($this->_items[$key]) ? $this->_items[$key] : null;
	}
	public function add($key,$value)
	{
		$this->_items[$key]=$value;
	}
	public function remove($key)
	{
		if(isset($this->_items[$key]) || array_key_exists($key,$this->_items))
		{
			$value=$this->_items[$key];
			unset($this->_items[$key]);
			return $value;
		}
		else
			return null;
	}
	public function clear()
	{
		foreach(array_keys($this->_items) as $key)
			$this->remove($key);
	}
	public function contains($key)
	{
		return isset($this->_items[$key]) || array_key_exists($key,$this->_items);
	}
	public function toArray()
	{
		return $this->_items;
	}
	public function offsetExists($offset)
	{
		return $this->contains($offset);
	}
	public function offsetGet($offset)
	{
		return $this->itemAt($offset);
	}
	public function offsetSet($offset,$item)
	{
		$this->add($offset,$item);
	}
	public function offsetUnset($offset)
	{
		$this->remove($offset);
	}
}
class THttpCookieCollection extends TList
{
	private $_o;
	public function __construct($owner=null)
	{
		$this->_o=$owner;
	}
	public function insertAt($index,$item)
	{
		if($item instanceof THttpCookie)
		{
			parent::insertAt($index,$item);
			if($this->_o instanceof THttpResponse)
				$this->_o->addCookie($item);
		}
		else
			throw new TInvalidDataTypeException('httpcookiecollection_httpcookie_required');
	}
	public function removeAt($index)
	{
		$item=parent::removeAt($index);
		if($this->_o instanceof THttpResponse)
			$this->_o->removeCookie($item);
		return $item;
	}
	public function itemAt($index)
	{
		if(is_integer($index))
			return parent::itemAt($index);
		else
			return $this->findCookieByName($index);
	}
	public function findCookieByName($name)
	{
		foreach($this as $cookie)
			if($cookie->getName()===$name)
				return $cookie;
		return null;
	}
}
class THttpCookie extends TComponent
{
	private $_domain='';
	private $_name;
	private $_value='';
	private $_expire=0;
	private $_path='/';
	private $_secure=false;
	public function __construct($name,$value)
	{
		$this->_name=$name;
		$this->_value=$value;
	}
	public function getDomain()
	{
		return $this->_domain;
	}
	public function setDomain($value)
	{
		$this->_domain=$value;
	}
	public function getExpire()
	{
		return $this->_expire;
	}
	public function setExpire($value)
	{
		$this->_expire=TPropertyValue::ensureInteger($value);
	}
	public function getName()
	{
		return $this->_name;
	}
	public function setName($value)
	{
		$this->_name=$value;
	}
	public function getValue()
	{
		return $this->_value;
	}
	public function setValue($value)
	{
		$this->_value=$value;
	}
	public function getPath()
	{
		return $this->_path;
	}
	public function setPath($value)
	{
		$this->_path=$value;
	}
	public function getSecure()
	{
		return $this->_secure;
	}
	public function setSecure($value)
	{
		$this->_secure=TPropertyValue::ensureBoolean($value);
	}
}
class TUri extends TComponent
{
	private static $_defaultPort=array(
		'ftp'=>21,
		'gopher'=>70,
		'http'=>80,
		'https'=>443,
		'news'=>119,
		'nntp'=>119,
		'wais'=>210,
		'telnet'=>23
	);
	private $_scheme;
	private $_host;
	private $_port;
	private $_user;
	private $_pass;
	private $_path;
	private $_query;
	private $_fragment;
	private $_uri;
	public function __construct($uri)
	{
		if(($ret=@parse_url($uri))!==false)
		{
						$this->_scheme=isset($ret['scheme'])?$ret['scheme']:'';
			$this->_host=isset($ret['host'])?$ret['host']:'';
			$this->_port=isset($ret['port'])?$ret['port']:'';
			$this->_user=isset($ret['user'])?$ret['user']:'';
			$this->_pass=isset($ret['pass'])?$ret['pass']:'';
			$this->_path=isset($ret['path'])?$ret['path']:'';
			$this->_query=isset($ret['query'])?$ret['query']:'';
			$this->_fragment=isset($ret['fragment'])?$ret['fragment']:'';
			$this->_uri=$uri;
		}
		else
		{
			throw new TInvalidDataValueException('uri_format_invalid',$uri);
		}
	}
	public function getUri()
	{
		return $this->_uri;
	}
	public function getScheme()
	{
		return $this->_scheme;
	}
	public function getHost()
	{
		return $this->_host;
	}
	public function getPort()
	{
		return $this->_port;
	}
	public function getUser()
	{
		return $this->_user;
	}
	public function getPassword()
	{
		return $this->_pass;
	}
	public function getPath()
	{
		return $this->_path;
	}
	public function getQuery()
	{
		return $this->_query;
	}
	public function getFragment()
	{
		return $this->_fragment;
	}
}
class THttpRequestUrlFormat extends TEnumerable
{
	const Get='Get';
	const Path='Path';
}
class THttpResponseAdapter extends TApplicationComponent
{
	private $_response;
	public function __construct($response)
	{
		$this->_response=$response;
	}
	public function getResponse()
	{
		return $this->_response;
	}
	public function flushContent()
	{
		$this->_response->flushContent();
	}
	public function httpRedirect($url)
	{
		$this->_response->httpRedirect($url);
	}
	public function createNewHtmlWriter($type, $writer)
	{
		return $this->_response->createNewHtmlWriter($type,$writer);
	}
}
class THttpResponse extends TModule implements ITextWriter
{
	private static $HTTP_STATUS_CODES = array(
		100 => 'Continue', 101 => 'Switching Protocols', 
		200 => 'OK', 201 => 'Created', 202 => 'Accepted', 203 => 'Non-Authoritative Information', 204 => 'No Content', 205 => 'Reset Content', 206 => 'Partial Content', 
		300 => 'Multiple Choices', 301 => 'Moved Permanently', 302 => 'Found', 303 => 'See Other', 304 => 'Not Modified', 305 => 'Use Proxy', 307 => 'Temporary Redirect', 
		400 => 'Bad Request', 401 => 'Unauthorized', 402 => 'Payment Required', 403 => 'Forbidden', 404 => 'Not Found', 405 => 'Method Not Allowed', 406 => 'Not Acceptable', 407 => 'Proxy Authentication Required', 408 => 'Request Time-out', 409 => 'Conflict', 410 => 'Gone', 411 => 'Length Required', 412 => 'Precondition Failed', 413 => 'Request Entity Too Large', 414 => 'Request-URI Too Large', 415 => 'Unsupported Media Type', 416 => 'Requested range not satisfiable', 417 => 'Expectation Failed', 
		500 => 'Internal Server Error', 501 => 'Not Implemented', 502 => 'Bad Gateway', 503 => 'Service Unavailable', 504 => 'Gateway Time-out', 505 => 'HTTP Version not supported'
	);
	private $_bufferOutput=true;
	private $_initialized=false;
	private $_cookies=null;
	private $_status=200;
	private $_reason='OK';
	private $_htmlWriterType='System.Web.UI.THtmlWriter';
	private $_contentType=null;
	private $_charset='';
	private $_adapter;
	public function __destruct()
	{
					}
	public function setAdapter(THttpResponseAdapter $adapter)
	{
		$this->_adapter=$adapter;
	}
	public function getAdapter()
	{
		return $this->_adapter;
	}
	public function getHasAdapter()
	{
		return !is_null($this->_adapter);
	}
	public function init($config)
	{
		if($this->_bufferOutput)
			ob_start();
		$this->_initialized=true;
		$this->getApplication()->setResponse($this);
	}
	public function getCacheExpire()
	{
		return session_cache_expire();
	}
	public function setCacheExpire($value)
	{
		session_cache_expire(TPropertyValue::ensureInteger($value));
	}
	public function getCacheControl()
	{
		return session_cache_limiter();
	}
	public function setCacheControl($value)
	{
		session_cache_limiter(TPropertyValue::ensureEnum($value,array('none','nocache','private','private_no_expire','public')));
	}
	public function setContentType($type)
	{
		$this->_contentType = $type;
	}
	public function getContentType()
	{
		return $this->_contentType;
	}
	public function getCharset()
	{
		return $this->_charset;
	}
	public function setCharset($charset)
	{
		$this->_charset = $charset;
	}
	public function getBufferOutput()
	{
		return $this->_bufferOutput;
	}
	public function setBufferOutput($value)
	{
		if($this->_initialized)
			throw new TInvalidOperationException('httpresponse_bufferoutput_unchangeable');
		else
			$this->_bufferOutput=TPropertyValue::ensureBoolean($value);
	}
	public function getStatusCode()
	{
		return $this->_status;
	}
	public function setStatusCode($status, $reason=null)
	{
		$status=TPropertyValue::ensureInteger($status);
		if(isset(self::$HTTP_STATUS_CODES[$status])) {
			$this->_reason=self::$HTTP_STATUS_CODES[$status];
		}else{
			if($reason===null || $reason==='') {
				throw new TInvalidDataValueException("response_status_reason_missing");
			}
			$reason=TPropertyValue::ensureString($reason);
			if(strpos($reason, "\r")!=false || strpos($reason, "\n")!=false) {
				throw new TInvalidDataValueException("response_status_reason_barchars");
			}
			$this->_reason=$reason;
		}
		$this->_status=$status;
	}
	public function getStatusReason() {
		return $this->_reason;
	}
	public function getCookies()
	{
		if($this->_cookies===null)
			$this->_cookies=new THttpCookieCollection($this);
		return $this->_cookies;
	}
	public function write($str)
	{
		echo $str;
	}
	public function writeFile($fileName,$content=null,$mimeType=null,$headers=null)
	{
		static $defaultMimeTypes=array(
			'css'=>'text/css',
			'gif'=>'image/gif',
			'jpg'=>'image/jpeg',
			'jpeg'=>'image/jpeg',
			'htm'=>'text/html',
			'html'=>'text/html',
			'js'=>'javascript/js',
			'pdf'=>'application/pdf',
			'xls'=>'application/vnd.ms-excel',
		);
		if($mimeType===null)
		{
			$mimeType='text/plain';
			if(function_exists('mime_content_type'))
				$mimeType=mime_content_type($fileName);
			else if(($ext=strrchr($fileName,'.'))!==false)
			{
				$ext=substr($ext,1);
				if(isset($defaultMimeTypes[$ext]))
					$mimeType=$defaultMimeTypes[$ext];
			}
		}
		$fn=basename($fileName);
		$this->sendHttpHeader();
		if(is_array($headers))
		{
			foreach($headers as $h)
				header($h);
		}
		else
		{
			header('Pragma: public');
			header('Expires: 0');
			header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
		}
		header("Content-type: $mimeType");
		header('Content-Length: '.($content===null?filesize($fileName):strlen($content)));
		header("Content-Disposition: attachment; filename=\"$fn\"");
		header('Content-Transfer-Encoding: binary');
		if($content===null)
			readfile($fileName);
		else
			echo $content;
	}
	public function redirect($url)
	{
		if($this->getHasAdapter())
			$this->_adapter->httpRedirect($url);
		else
			$this->httpRedirect($url);
	}
	public function httpRedirect($url)
	{
		if(!$this->getApplication()->getRequestCompleted())
			$this->getApplication()->onEndRequest();
		if($url[0]==='/')
			$url=$this->getRequest()->getBaseUrl().$url;
		header('Location: '.str_replace('&amp;','&',$url));
		exit();
	}
	public function reload()
	{
		$this->redirect($this->getRequest()->getRequestUri());
	}
	public function flush()
	{
		if($this->getHasAdapter())
			$this->_adapter->flushContent();
		else
			$this->flushContent();
	}
	public function flushContent()
	{
		$this->sendHttpHeader();
		$this->sendContentTypeHeader();
		if($this->_bufferOutput)
			ob_flush();
	}
	protected function sendHttpHeader ()
	{
		header("HTTP/1.1 {$this->_status} {$this->_reason}", true, $this->_status);
	}
	protected function sendContentTypeHeader()
	{
		$charset=$this->getCharset();
		if($charset==='' && ($globalization=$this->getApplication()->getGlobalization(false))!==null)
			$charset=$globalization->getCharset();
		if($charset!=='')
		{
			$contentType=$this->_contentType===null?'text/html':$this->_contentType;
			$this->appendHeader('Content-Type: '.$contentType.';charset='.$charset);
		}
		else if($this->_contentType!==null)
			$this->appendHeader('Content-Type: '.$this->_contentType.';charset=UTF-8');
	}
	public function getContents()
	{
		return $this->_bufferOutput?ob_get_contents():'';
	}
	public function clear()
	{
		if($this->_bufferOutput)
			ob_clean();
	}
	public function appendHeader($value)
	{
		header($value);
	}
	public function appendLog($message,$messageType=0,$destination='',$extraHeaders='')
	{
		error_log($message,$messageType,$destination,$extraHeaders);
	}
	public function addCookie($cookie)
	{
		$request=$this->getRequest();
		if($request->getEnableCookieValidation())
		{
			$value=$this->getApplication()->getSecurityManager()->hashData($cookie->getValue());
			setcookie($cookie->getName(),$value,$cookie->getExpire(),$cookie->getPath(),$cookie->getDomain(),$cookie->getSecure());
		}
		else
			setcookie($cookie->getName(),$cookie->getValue(),$cookie->getExpire(),$cookie->getPath(),$cookie->getDomain(),$cookie->getSecure());
	}
	public function removeCookie($cookie)
	{
		setcookie($cookie->getName(),null,0,$cookie->getPath(),$cookie->getDomain(),$cookie->getSecure());
	}
	public function getHtmlWriterType()
	{
		return $this->_htmlWriterType;
	}
	public function setHtmlWriterType($value)
	{
		$this->_htmlWriterType=$value;
	}
	public function createHtmlWriter($type=null)
	{
		if($type===null)
			$type=$this->getHtmlWriterType();
		if($this->getHasAdapter())
			return $this->_adapter->createNewHtmlWriter($type, $this);
		else
		 	return $this->createNewHtmlWriter($type, $this);
	}
	public function createNewHtmlWriter($type, $writer)
	{
		return Prado::createComponent($type, $writer);
	}
}
class THttpSession extends TApplicationComponent implements IteratorAggregate,ArrayAccess,Countable,IModule
{
	private $_initialized=false;
	private $_started=false;
	private $_autoStart=false;
	private $_cookie=null;
	private $_id;
	private $_customStorage=false;
	public function getID()
	{
		return $this->_id;
	}
	public function setID($value)
	{
		$this->_id=$value;
	}
	public function init($config)
	{
		if($this->_autoStart)
			$this->open();
		$this->_initialized=true;
		$this->getApplication()->setSession($this);
		register_shutdown_function(array($this, "close"));
	}
	public function open()
	{
		if(!$this->_started)
		{
			if($this->_customStorage)
				session_set_save_handler(array($this,'_open'),array($this,'_close'),array($this,'_read'),array($this,'_write'),array($this,'_destroy'),array($this,'_gc'));
			if($this->_cookie!==null)
				session_set_cookie_params($this->_cookie->getExpire(),$this->_cookie->getPath(),$this->_cookie->getDomain(),$this->_cookie->getSecure());
			if(ini_get('session.auto_start')!=='1')
				session_start();
			$this->_started=true;
		}
	}
	public function close()
	{
		if($this->_started)
		{
			session_write_close();
			$this->_started=false;
		}
	}
	public function destroy()
	{
		if($this->_started)
		{
			session_destroy();
			$this->_started=false;
		}
	}
	public function getIsStarted()
	{
		return $this->_started;
	}
	public function getSessionID()
	{
		return session_id();
	}
	public function setSessionID($value)
	{
		if($this->_started)
			throw new TInvalidOperationException('httpsession_sessionid_unchangeable');
		else
			session_id($value);
	}
	public function getSessionName()
	{
		return session_name();
	}
	public function setSessionName($value)
	{
		if($this->_started)
			throw new TInvalidOperationException('httpsession_sessionname_unchangeable');
		else if(ctype_alnum($value))
			session_name($value);
		else
			throw new TInvalidDataValueException('httpsession_sessionname_invalid',$value);
	}
	public function getSavePath()
	{
		return session_save_path();
	}
	public function setSavePath($value)
	{
		if($this->_started)
			throw new TInvalidOperationException('httpsession_savepath_unchangeable');
		else if(is_dir($value))
			session_save_path($value);
		else
			throw new TInvalidDataValueException('httpsession_savepath_invalid',$value);
	}
	public function getUseCustomStorage()
	{
		return $this->_customStorage;
	}
	public function setUseCustomStorage($value)
	{
		$this->_customStorage=TPropertyValue::ensureBoolean($value);
	}
	public function getCookie()
	{
		if($this->_cookie===null)
			$this->_cookie=new THttpCookie($this->getSessionName(),$this->getSessionID());
		return $this->_cookie;
	}
	public function getCookieMode()
	{
		if(ini_get('session.use_cookies')==='0')
			return THttpSessionCookieMode::None;
		else if(ini_get('session.use_only_cookies')==='0')
			return THttpSessionCookieMode::Allow;
		else
			return THttpSessionCookieMode::Only;
	}
	public function setCookieMode($value)
	{
		if($this->_started)
			throw new TInvalidOperationException('httpsession_cookiemode_unchangeable');
		else
		{
			$value=TPropertyValue::ensureEnum($value,'THttpSessionCookieMode');
			if($value===THttpSessionCookieMode::None)
				ini_set('session.use_cookies','0');
			else if($value===THttpSessionCookieMode::Allow)
			{
				ini_set('session.use_cookies','1');
				ini_set('session.use_only_cookies','0');
			}
			else
			{
				ini_set('session.use_cookies','1');
				ini_set('session.use_only_cookies','1');
			}
		}
	}
	public function getAutoStart()
	{
		return $this->_autoStart;
	}
	public function setAutoStart($value)
	{
		if($this->_initialized)
			throw new TInvalidOperationException('httpsession_autostart_unchangeable');
		else
			$this->_autoStart=TPropertyValue::ensureBoolean($value);
	}
	public function getGCProbability()
	{
		return TPropertyValue::ensureInteger(ini_get('session.gc_probability'));
	}
	public function setGCProbability($value)
	{
		if($this->_started)
			throw new TInvalidOperationException('httpsession_gcprobability_unchangeable');
		else
		{
			$value=TPropertyValue::ensureInteger($value);
			if($value>=0 && $value<=100)
			{
				ini_set('session.gc_probability',$value);
				ini_set('session.gc_divisor','100');
			}
			else
				throw new TInvalidDataValueException('httpsession_gcprobability_invalid',$value);
		}
	}
	public function getUseTransparentSessionID()
	{
		return ini_get('session.use_trans_sid')==='1';
	}
	public function setUseTransparentSessionID($value)
	{
		if($this->_started)
			throw new TInvalidOperationException('httpsession_transid_unchangeable');
		else
			ini_set('session.use_trans_sid',TPropertyValue::ensureBoolean($value)?'1':'0');
	}
	public function getTimeout()
	{
		return TPropertyValue::ensureInteger(ini_get('session.gc_maxlifetime'));
	}
	public function setTimeout($value)
	{
		if($this->_started)
			throw new TInvalidOperationException('httpsession_maxlifetime_unchangeable');
		else
			ini_set('session.gc_maxlifetime',$value);
	}
	public function _open($savePath,$sessionName)
	{
		return true;
	}
	public function _close()
	{
		return true;
	}
	public function _read($id)
	{
		return '';
	}
	public function _write($id,$data)
	{
		return true;
	}
	public function _destroy($id)
	{
		return true;
	}
	public function _gc($maxLifetime)
	{
		return true;
	}
	public function getIterator()
	{
		return new TSessionIterator;
	}
	public function getCount()
	{
		return count($_SESSION);
	}
	public function count()
	{
		return $this->getCount();
	}
	public function getKeys()
	{
		return array_keys($_SESSION);
	}
	public function itemAt($key)
	{
		return isset($_SESSION[$key]) ? $_SESSION[$key] : null;
	}
	public function add($key,$value)
	{
		$_SESSION[$key]=$value;
	}
	public function remove($key)
	{
		if(isset($_SESSION[$key]))
		{
			$value=$_SESSION[$key];
			unset($_SESSION[$key]);
			return $value;
		}
		else
			return null;
	}
	public function clear()
	{
		foreach(array_keys($_SESSION) as $key)
			unset($_SESSION[$key]);
	}
	public function contains($key)
	{
		return isset($_SESSION[$key]);
	}
	public function toArray()
	{
		return $_SESSION;
	}
	public function offsetExists($offset)
	{
		return isset($_SESSION[$offset]);
	}
	public function offsetGet($offset)
	{
		return isset($_SESSION[$offset]) ? $_SESSION[$offset] : null;
	}
	public function offsetSet($offset,$item)
	{
		$_SESSION[$offset]=$item;
	}
	public function offsetUnset($offset)
	{
		unset($_SESSION[$offset]);
	}
}
class TSessionIterator implements Iterator
{
	private $_keys;
	private $_key;
	public function __construct()
	{
		$this->_keys=array_keys($_SESSION);
	}
	public function rewind()
	{
		$this->_key=reset($this->_keys);
	}
	public function key()
	{
		return $this->_key;
	}
	public function current()
	{
		return isset($_SESSION[$this->_key])?$_SESSION[$this->_key]:null;
	}
	public function next()
	{
		do
		{
			$this->_key=next($this->_keys);
		}
		while(!isset($_SESSION[$this->_key]) && $this->_key!==false);
	}
	public function valid()
	{
		return $this->_key!==false;
	}
}
class THttpSessionCookieMode extends TEnumerable
{
	const None='None';
	const Allow='Allow';
	const Only='Only';
}
Prado::using('System.Web.UI.WebControls.*');
class TAttributeCollection extends TMap
{
	private $_caseSensitive=false;
	public function __get($name)
	{
		return $this->contains($name)?$this->itemAt($name):parent::__get($name);
	}
	public function __set($name,$value)
	{
		$this->add($name,$value);
	}
	public function getCaseSensitive()
	{
		return $this->_caseSensitive;
	}
	public function setCaseSensitive($value)
	{
		$this->_caseSensitive=TPropertyValue::ensureBoolean($value);
	}
	public function itemAt($key)
	{
		return parent::itemAt($this->_caseSensitive?$key:strtolower($key));
	}
	public function add($key,$value)
	{
		parent::add($this->_caseSensitive?$key:strtolower($key),$value);
	}
	public function remove($key)
	{
		return parent::remove($this->_caseSensitive?$key:strtolower($key));
	}
	public function contains($key)
	{
		return parent::contains($this->_caseSensitive?$key:strtolower($key));
	}
	public function hasProperty($name)
	{
		return $this->contains($name) || parent::hasProperty($name);
	}
	public function canGetProperty($name)
	{
		return $this->contains($name) || parent::canGetProperty($name);
	}
	public function canSetProperty($name)
	{
		return true;
	}
}
class TControlAdapter extends TApplicationComponent
{
	private $_control;
	public function __construct($control)
	{
		$this->_control=$control;
	}
	public function getControl()
	{
		return $this->_control;
	}
	public function getPage()
	{
		return $this->_control?$this->_control->getPage():null;
	}
	public function createChildControls()
	{
		$this->_control->createChildControls();
	}
	public function loadState()
	{
		$this->_control->loadState();
	}
	public function saveState()
	{
		$this->_control->saveState();
	}
	public function onInit($param)
	{
		$this->_control->onInit($param);
	}
	public function onLoad($param)
	{
		$this->_control->onLoad($param);
	}
	public function onPreRender($param)
	{
		$this->_control->onPreRender($param);
	}
	public function onUnload($param)
	{
		$this->_control->onUnload($param);
	}
	public function render($writer)
	{
		$this->_control->render($writer);
	}
	public function renderChildren($writer)
	{
		$this->_control->renderChildren($writer);
	}
}
class TControl extends TApplicationComponent implements IRenderable, IBindable
{
	const ID_FORMAT='/^[a-zA-Z_]\\w*$/';
	const ID_SEPARATOR='$';
	const CLIENT_ID_SEPARATOR='_';
	const AUTOMATIC_ID_PREFIX='ctl';
	const CS_CONSTRUCTED=0;
	const CS_CHILD_INITIALIZED=1;
	const CS_INITIALIZED=2;
	const CS_STATE_LOADED=3;
	const CS_LOADED=4;
	const CS_PRERENDERED=5;
	const IS_ID_SET=0x01;
	const IS_DISABLE_VIEWSTATE=0x02;
	const IS_SKIN_APPLIED=0x04;
	const IS_STYLESHEET_APPLIED=0x08;
	const IS_DISABLE_THEMING=0x10;
	const IS_CHILD_CREATED=0x20;
	const IS_CREATING_CHILD=0x40;
	const RF_CONTROLS=0;			
	const RF_CHILD_STATE=1;			
	const RF_NAMED_CONTROLS=2;		
	const RF_NAMED_CONTROLS_ID=3;	
	const RF_SKIN_ID=4;				
	const RF_DATA_BINDINGS=5;		
	const RF_EVENTS=6;				
	const RF_CONTROLSTATE=7;		
	const RF_NAMED_OBJECTS=8;		
	const RF_ADAPTER=9;				
	const RF_AUTO_BINDINGS=10;		
	private $_id='';
	private $_uid;
	private $_parent;
	private $_page;
	private $_namingContainer;
	private $_tplControl;
	private $_viewState=array();
	private $_tempState=array();
	private $_trackViewState=true;
	private $_stage=0;
	private $_flags=0;
	private $_rf=array();
	public function __construct()
	{
	}
	public function __get($name)
	{
		if(isset($this->_rf[self::RF_NAMED_OBJECTS][$name]))
			return $this->_rf[self::RF_NAMED_OBJECTS][$name];
		else
			return parent::__get($name);
	}
	public function getHasAdapter()
	{
		return isset($this->_rf[self::RF_ADAPTER]);
	}
	public function getAdapter()
	{
		return isset($this->_rf[self::RF_ADAPTER])?$this->_rf[self::RF_ADAPTER]:null;
	}
	public function setAdapter(TControlAdapter $adapter)
	{
		$this->_rf[self::RF_ADAPTER]=$adapter;
	}
	public function getParent()
	{
		return $this->_parent;
	}
	public function getNamingContainer()
	{
		if(!$this->_namingContainer && $this->_parent)
		{
			if($this->_parent instanceof INamingContainer)
				$this->_namingContainer=$this->_parent;
			else
				$this->_namingContainer=$this->_parent->getNamingContainer();
		}
		return $this->_namingContainer;
	}
	public function getPage()
	{
		if(!$this->_page)
		{
			if($this->_parent)
				$this->_page=$this->_parent->getPage();
			else if($this->_tplControl)
				$this->_page=$this->_tplControl->getPage();
		}
		return $this->_page;
	}
	public function setPage($page)
	{
		$this->_page=$page;
	}
	public function setTemplateControl($control)
	{
		$this->_tplControl=$control;
	}
	public function getTemplateControl()
	{
		if(!$this->_tplControl && $this->_parent)
			$this->_tplControl=$this->_parent->getTemplateControl();
		return $this->_tplControl;
	}
	public function getSourceTemplateControl()
	{
		$control=$this;
		while(($control instanceof TControl) && ($control=$control->getTemplateControl())!==null)
		{
			if(($control instanceof TTemplateControl) && $control->getIsSourceTemplateControl())
				return $control;
		}
		return $this->getPage();
	}
	protected function getControlStage()
	{
		return $this->_stage;
	}
	protected function setControlStage($value)
	{
		$this->_stage=$value;
	}
	public function getID($hideAutoID=true)
	{
		if($hideAutoID)
			return ($this->_flags & self::IS_ID_SET) ? $this->_id : '';
		else
			return $this->_id;
	}
	public function setID($id)
	{
		if(!preg_match(self::ID_FORMAT,$id))
			throw new TInvalidDataValueException('control_id_invalid',get_class($this),$id);
		$this->_id=$id;
		$this->_flags |= self::IS_ID_SET;
		$this->clearCachedUniqueID($this instanceof INamingContainer);
		if($this->_namingContainer)
			$this->_namingContainer->clearNameTable();
	}
	public function getUniqueID()
	{
		if($this->_uid==='' || $this->_uid===null)	
		{
			$this->_uid='';  
			if($namingContainer=$this->getNamingContainer())
			{
				if($this->getPage()===$namingContainer)
					return ($this->_uid=$this->_id);
				else if(($prefix=$namingContainer->getUniqueID())==='')
					return $this->_id;
				else
					return ($this->_uid=$prefix.self::ID_SEPARATOR.$this->_id);
			}
			else	
				return $this->_id;
		}
		else
			return $this->_uid;
	}
	public function focus()
	{
		$this->getPage()->setFocus($this);
	}
	public function getClientID()
	{
		return strtr($this->getUniqueID(),self::ID_SEPARATOR,self::CLIENT_ID_SEPARATOR);
	}
	public static function convertUniqueIdToClientId($uniqueID)
	{
		return strtr($uniqueID,self::ID_SEPARATOR,self::CLIENT_ID_SEPARATOR);
	}
	public function getSkinID()
	{
		return isset($this->_rf[self::RF_SKIN_ID])?$this->_rf[self::RF_SKIN_ID]:'';
	}
	public function setSkinID($value)
	{
		if(($this->_flags & self::IS_SKIN_APPLIED) || $this->_stage>=self::CS_CHILD_INITIALIZED)
			throw new TInvalidOperationException('control_skinid_unchangeable',get_class($this));
		else
			$this->_rf[self::RF_SKIN_ID]=$value;
	}
	public function getEnableTheming()
	{
		if($this->_flags & self::IS_DISABLE_THEMING)
			return false;
		else
			return $this->_parent?$this->_parent->getEnableTheming():true;
	}
	public function setEnableTheming($value)
	{
		if($this->_stage>=self::CS_CHILD_INITIALIZED)
			throw new TInvalidOperationException('control_enabletheming_unchangeable',get_class($this),$this->getUniqueID());
		else if(TPropertyValue::ensureBoolean($value))
			$this->_flags &= ~self::IS_DISABLE_THEMING;
		else
			$this->_flags |= self::IS_DISABLE_THEMING;
	}
	public function getCustomData()
	{
		return $this->getViewState('CustomData',null);
	}
	public function setCustomData($value)
	{
		$this->setViewState('CustomData',$value,null);
	}
	public function getHasControls()
	{
		return isset($this->_rf[self::RF_CONTROLS]) && $this->_rf[self::RF_CONTROLS]->getCount()>0;
	}
	public function getControls()
	{
		if(!isset($this->_rf[self::RF_CONTROLS]))
			$this->_rf[self::RF_CONTROLS]=$this->createControlCollection();
		return $this->_rf[self::RF_CONTROLS];
	}
	protected function createControlCollection()
	{
		return $this->getAllowChildControls()?new TControlCollection($this):new TEmptyControlCollection($this);
	}
	public function getVisible($checkParents=true)
	{
		if($checkParents)
		{
			for($control=$this;$control;$control=$control->_parent)
				if(!$control->getVisible(false))
					return false;
			return true;
		}
		else
			return $this->getViewState('Visible',true);
	}
	public function setVisible($value)
	{
		$this->setViewState('Visible',TPropertyValue::ensureBoolean($value),true);
	}
	public function getEnabled($checkParents=false)
	{
		if($checkParents)
		{
			for($control=$this;$control;$control=$control->_parent)
				if(!$control->getViewState('Enabled',true))
					return false;
			return true;
		}
		else
			return $this->getViewState('Enabled',true);
	}
	public function setEnabled($value)
	{
		$this->setViewState('Enabled',TPropertyValue::ensureBoolean($value),true);
	}
	public function getHasAttributes()
	{
		if($attributes=$this->getViewState('Attributes',null))
			return $attributes->getCount()>0;
		else
			return false;
	}
	public function getAttributes()
	{
		if($attributes=$this->getViewState('Attributes',null))
			return $attributes;
		else
		{
			$attributes=new TAttributeCollection;
			$this->setViewState('Attributes',$attributes,null);
			return $attributes;
		}
	}
	public function hasAttribute($name)
	{
		if($attributes=$this->getViewState('Attributes',null))
			return $attributes->contains($name);
		else
			return false;
	}
	public function getAttribute($name)
	{
		if($attributes=$this->getViewState('Attributes',null))
			return $attributes->itemAt($name);
		else
			return null;
	}
	public function setAttribute($name,$value)
	{
		$this->getAttributes()->add($name,$value);
	}
	public function removeAttribute($name)
	{
		if($attributes=$this->getViewState('Attributes',null))
			return $attributes->remove($name);
		else
			return null;
	}
	public function getEnableViewState($checkParents=false)
	{
		if($checkParents)
		{
			for($control=$this;$control!==null;$control=$control->getParent())
				if($control->_flags & self::IS_DISABLE_VIEWSTATE)
					return false;
			return true;
		}
		else
			return !($this->_flags & self::IS_DISABLE_VIEWSTATE);
	}
	public function setEnableViewState($value)
	{
		if(TPropertyValue::ensureBoolean($value))
			$this->_flags &= ~self::IS_DISABLE_VIEWSTATE;
		else
			$this->_flags |= self::IS_DISABLE_VIEWSTATE;
	}
	protected function getControlState($key,$defaultValue=null)
	{
		return isset($this->_rf[self::RF_CONTROLSTATE][$key])?$this->_rf[self::RF_CONTROLSTATE][$key]:$defaultValue;
	}
	protected function setControlState($key,$value,$defaultValue=null)
	{
		if($value===$defaultValue)
			unset($this->_rf[self::RF_CONTROLSTATE][$key]);
		else
			$this->_rf[self::RF_CONTROLSTATE][$key]=$value;
	}
	protected function clearControlState($key)
	{
		unset($this->_rf[self::RF_CONTROLSTATE][$key]);
	}
	public function trackViewState($enabled)
	{
		$this->_trackViewState=TPropertyValue::ensureBoolean($enabled);
	}
	public function getViewState($key,$defaultValue=null)
	{
		if(isset($this->_viewState[$key]))
			return $this->_viewState[$key]!==null?$this->_viewState[$key]:$defaultValue;
		else if(isset($this->_tempState[$key]))
		{
			if(is_object($this->_tempState[$key]) && $this->_trackViewState)
				$this->_viewState[$key]=$this->_tempState[$key];
			return $this->_tempState[$key];
		}
		else
			return $defaultValue;
	}
	public function setViewState($key,$value,$defaultValue=null)
	{
		if($this->_trackViewState)
		{
			$this->_viewState[$key]=$value;
			unset($this->_tempState[$key]);
		}
		else
		{
			unset($this->_viewState[$key]);
			$this->_tempState[$key]=$value;
		}
	}
	public function clearViewState($key)
	{
		unset($this->_viewState[$key]);
		unset($this->_tempState[$key]);
	}
	public function bindProperty($name,$expression)
	{
		$this->_rf[self::RF_DATA_BINDINGS][$name]=$expression;
	}
	public function unbindProperty($name)
	{
		unset($this->_rf[self::RF_DATA_BINDINGS][$name]);
	}
	public function autoBindProperty($name,$expression)
	{
		$this->_rf[self::RF_AUTO_BINDINGS][$name]=$expression;
	}
	public function dataBind()
	{
		$this->dataBindProperties();
		$this->onDataBinding(null);
		$this->dataBindChildren();
	}
	protected function dataBindProperties()
	{
		if(isset($this->_rf[self::RF_DATA_BINDINGS]))
		{
			if(($context=$this->getTemplateControl())===null)
				$context=$this;
			foreach($this->_rf[self::RF_DATA_BINDINGS] as $property=>$expression)
				$this->setSubProperty($property,$context->evaluateExpression($expression));
		}
	}
	protected function autoDataBindProperties()
	{
		if(isset($this->_rf[self::RF_AUTO_BINDINGS]))
		{
			if(($context=$this->getTemplateControl())===null)
				$context=$this;
			foreach($this->_rf[self::RF_AUTO_BINDINGS] as $property=>$expression)
				$this->setSubProperty($property,$context->evaluateExpression($expression));
		}
	}
	protected function dataBindChildren()
	{
		if(isset($this->_rf[self::RF_CONTROLS]))
		{
			foreach($this->_rf[self::RF_CONTROLS] as $control)
				if($control instanceof IBindable)
					$control->dataBind();
		}
	}
	final protected function getChildControlsCreated()
	{
		return ($this->_flags & self::IS_CHILD_CREATED)!==0;
	}
	final protected function setChildControlsCreated($value)
	{
		if($value)
			$this->_flags |= self::IS_CHILD_CREATED;
		else
		{
			if($this->getHasControls() && ($this->_flags & self::IS_CHILD_CREATED))
				$this->getControls()->clear();
			$this->_flags &= ~self::IS_CHILD_CREATED;
		}
	}
	public function ensureChildControls()
	{
		if(!($this->_flags & self::IS_CHILD_CREATED) && !($this->_flags & self::IS_CREATING_CHILD))
		{
			try
			{
				$this->_flags |= self::IS_CREATING_CHILD;
				if(isset($this->_rf[self::RF_ADAPTER]))
					$this->_rf[self::RF_ADAPTER]->createChildControls();
				else
					$this->createChildControls();
				$this->_flags &= ~self::IS_CREATING_CHILD;
				$this->_flags |= self::IS_CHILD_CREATED;
			}
			catch(Exception $e)
			{
				$this->_flags &= ~self::IS_CREATING_CHILD;
				$this->_flags |= self::IS_CHILD_CREATED;
				throw $e;
			}
		}
	}
	public function createChildControls()
	{
	}
	public function findControl($id)
	{
		$id=strtr($id,'.',self::ID_SEPARATOR);
		$container=($this instanceof INamingContainer)?$this:$this->getNamingContainer();
		if(!$container || !$container->getHasControls())
			return null;
		if(!isset($container->_rf[self::RF_NAMED_CONTROLS]))
		{
			$container->_rf[self::RF_NAMED_CONTROLS]=array();
			$container->fillNameTable($container,$container->_rf[self::RF_CONTROLS]);
		}
		if(($pos=strpos($id,self::ID_SEPARATOR))===false)
			return isset($container->_rf[self::RF_NAMED_CONTROLS][$id])?$container->_rf[self::RF_NAMED_CONTROLS][$id]:null;
		else
		{
			$cid=substr($id,0,$pos);
			$sid=substr($id,$pos+1);
			if(isset($container->_rf[self::RF_NAMED_CONTROLS][$cid]))
				return $container->_rf[self::RF_NAMED_CONTROLS][$cid]->findControl($sid);
			else
				return null;
		}
	}
	public function findControlsByType($type,$strict=true)
	{
		$controls=array();
		if($this->getHasControls())
		{
			foreach($this->_rf[self::RF_CONTROLS] as $control)
			{
				if(is_object($control) && (get_class($control)===$type || (!$strict && ($control instanceof $type))))
					$controls[]=$control;
				if(($control instanceof TControl) && $control->getHasControls())
					$controls=array_merge($controls,$control->findControlsByType($type,$strict));
			}
		}
		return $controls;
	}
	public function findControlsByID($id)
	{
		$controls=array();
		if($this->getHasControls())
		{
			foreach($this->_rf[self::RF_CONTROLS] as $control)
			{
				if($control instanceof TControl)
				{
					if($control->_id===$id)
						$controls[]=$control;
					$controls=array_merge($controls,$control->findControlsByID($id));
				}
			}
		}
		return $controls;
	}
	public function clearNamingContainer()
	{
		unset($this->_rf[self::RF_NAMED_CONTROLS_ID]);
		$this->clearNameTable();
	}
	public function registerObject($name,$object)
	{
		if(isset($this->_rf[self::RF_NAMED_OBJECTS][$name]))
			throw new TInvalidOperationException('control_object_reregistered',$name);
		$this->_rf[self::RF_NAMED_OBJECTS][$name]=$object;
	}
	public function unregisterObject($name)
	{
		unset($this->_rf[self::RF_NAMED_OBJECTS][$name]);
	}
	public function isObjectRegistered($name)
	{
		return isset($this->_rf[self::RF_NAMED_OBJECTS][$name]);
	}
	public function getHasChildInitialized()
	{
		return $this->getControlStage() >= self::CS_CHILD_INITIALIZED;
	}
	public function getHasInitialized()
	{
		return $this->getControlStage() >= self::CS_INITIALIZED;
	}
	public function getHasLoadedPostData()
	{
		return $this->getControlStage() >= self::CS_STATE_LOADED;
	}
	public function getHasLoaded()
	{
		return $this->getControlStage() >= self::CS_LOADED;
	}
	public function getHasPreRendered()
	{
		return $this->getControlStage() >= self::CS_PRERENDERED;
	}
	public function getRegisteredObject($name)
	{
		return isset($this->_rf[self::RF_NAMED_OBJECTS][$name])?$this->_rf[self::RF_NAMED_OBJECTS][$name]:null;
	}
	public function getAllowChildControls()
	{
		return true;
	}
	public function addParsedObject($object)
	{
		$this->getControls()->add($object);
	}
	final protected function clearChildState()
	{
		unset($this->_rf[self::RF_CHILD_STATE]);
	}
	final protected function isDescendentOf($ancestor)
	{
		$control=$this;
		while($control!==$ancestor && $control->_parent)
			$control=$control->_parent;
		return $control===$ancestor;
	}
	public function addedControl($control)
	{
		if($control->_parent)
			$control->_parent->getControls()->remove($control);
		$control->_parent=$this;
		$control->_page=$this->getPage();
		$namingContainer=($this instanceof INamingContainer)?$this:$this->_namingContainer;
		if($namingContainer)
		{
			$control->_namingContainer=$namingContainer;
			if($control->_id==='')
				$control->generateAutomaticID();
			else
				$namingContainer->clearNameTable();
			$control->clearCachedUniqueID($control instanceof INamingContainer);
		}
		if($this->_stage>=self::CS_CHILD_INITIALIZED)
		{
			$control->initRecursive($namingContainer);
			if($this->_stage>=self::CS_STATE_LOADED)
			{
				if(isset($this->_rf[self::RF_CHILD_STATE][$control->_id]))
				{
					$state=$this->_rf[self::RF_CHILD_STATE][$control->_id];
					unset($this->_rf[self::RF_CHILD_STATE][$control->_id]);
				}
				else
					$state=null;
				$control->loadStateRecursive($state,!($this->_flags & self::IS_DISABLE_VIEWSTATE));
				if($this->_stage>=self::CS_LOADED)
				{
					$control->loadRecursive();
					if($this->_stage>=self::CS_PRERENDERED)
						$control->preRenderRecursive();
				}
			}
		}
	}
	public function removedControl($control)
	{
		if($this->_namingContainer)
			$this->_namingContainer->clearNameTable();
		$control->unloadRecursive();
		$control->_parent=null;
		$control->_page=null;
		$control->_namingContainer=null;
		$control->_tplControl=null;
		if(!($control->_flags & self::IS_ID_SET))
			$control->_id='';
		else
			unset($this->_rf[self::RF_NAMED_OBJECTS][$control->_id]);
		$control->clearCachedUniqueID(true);
	}
	protected function initRecursive($namingContainer=null)
	{
		$this->ensureChildControls();
		if($this->getHasControls())
		{
			if($this instanceof INamingContainer)
				$namingContainer=$this;
			$page=$this->getPage();
			foreach($this->_rf[self::RF_CONTROLS] as $control)
			{
				if($control instanceof TControl)
				{
					$control->_namingContainer=$namingContainer;
					$control->_page=$page;
					if($control->_id==='' && $namingContainer)
						$control->generateAutomaticID();
					$control->initRecursive($namingContainer);
				}
			}
		}
		if($this->_stage<self::CS_INITIALIZED)
		{
			$this->_stage=self::CS_CHILD_INITIALIZED;
			if(($page=$this->getPage()) && $this->getEnableTheming() && !($this->_flags & self::IS_SKIN_APPLIED))
			{
				$page->applyControlSkin($this);
				$this->_flags |= self::IS_SKIN_APPLIED;
			}
			if(isset($this->_rf[self::RF_ADAPTER]))
				$this->_rf[self::RF_ADAPTER]->onInit(null);
			else
				$this->onInit(null);
			$this->_stage=self::CS_INITIALIZED;
		}
	}
	protected function loadRecursive()
	{
		if($this->_stage<self::CS_LOADED)
		{
			if(isset($this->_rf[self::RF_ADAPTER]))
				$this->_rf[self::RF_ADAPTER]->onLoad(null);
			else
				$this->onLoad(null);
		}
		if($this->getHasControls())
		{
			foreach($this->_rf[self::RF_CONTROLS] as $control)
			{
				if($control instanceof TControl)
					$control->loadRecursive();
			}
		}
		if($this->_stage<self::CS_LOADED)
			$this->_stage=self::CS_LOADED;
	}
	protected function preRenderRecursive()
	{
		$this->autoDataBindProperties();
		if($this->getVisible(false))
		{
			if(isset($this->_rf[self::RF_ADAPTER]))
				$this->_rf[self::RF_ADAPTER]->onPreRender(null);
			else
				$this->onPreRender(null);
			if($this->getHasControls())
			{
				foreach($this->_rf[self::RF_CONTROLS] as $control)
				{
					if($control instanceof TControl)
						$control->preRenderRecursive();
					else if($control instanceof TCompositeLiteral)
						$control->evaluateDynamicContent();
				}
			}
			$this->addToPostDataLoader();
		}
		$this->_stage=self::CS_PRERENDERED;
	}
	protected function addToPostDataLoader()
	{
		if($this instanceof IPostBackDataHandler)
			$this->getPage()->registerPostDataLoader($this);
	}
	protected function unloadRecursive()
	{
		if(!($this->_flags & self::IS_ID_SET))
			$this->_id='';
		if($this->getHasControls())
		{
			foreach($this->_rf[self::RF_CONTROLS] as $control)
				if($control instanceof TControl)
					$control->unloadRecursive();
		}
		if(isset($this->_rf[self::RF_ADAPTER]))
			$this->_rf[self::RF_ADAPTER]->onUnload(null);
		else
			$this->onUnload(null);
	}
	public function onInit($param)
	{
		$this->raiseEvent('OnInit',$this,$param);
	}
	public function onLoad($param)
	{
		$this->raiseEvent('OnLoad',$this,$param);
	}
	public function onDataBinding($param)
	{
		$this->raiseEvent('OnDataBinding',$this,$param);
	}
	public function onUnload($param)
	{
		$this->raiseEvent('OnUnload',$this,$param);
	}
	public function onPreRender($param)
	{
		$this->raiseEvent('OnPreRender',$this,$param);
	}
	protected function raiseBubbleEvent($sender,$param)
	{
		$control=$this;
		while($control=$control->_parent)
		{
			if($control->bubbleEvent($sender,$param))
				break;
		}
	}
	public function bubbleEvent($sender,$param)
	{
		return false;
	}
	public function broadcastEvent($name,$sender,$param)
	{
		$rootControl=(($page=$this->getPage())===null)?$this:$page;
		$rootControl->broadcastEventInternal($name,$sender,new TBroadcastEventParameter($name,$param));
	}
	private function broadcastEventInternal($name,$sender,$param)
	{
		if($this->hasEvent($name))
			$this->raiseEvent($name,$sender,$param->getParameter());
		if($this instanceof IBroadcastEventReceiver)
			$this->broadcastEventReceived($sender,$param);
		if($this->getHasControls())
		{
			foreach($this->_rf[self::RF_CONTROLS] as $control)
			{
				if($control instanceof TControl)
					$control->broadcastEventInternal($name,$sender,$param);
			}
		}
	}
	protected function traverseChildControls($param,$preCallback=null,$postCallback=null)
	{
		if($preCallback!==null)
			call_user_func($preCallback,$this,$param);
		if($this->getHasControls())
		{
			foreach($this->_rf[self::RF_CONTROLS] as $control)
			{
				if($control instanceof TControl)
				{
					$control->traverseChildControls($param,$preCallback,$postCallback);
				}
			}
		}
		if($postCallback!==null)
			call_user_func($postCallback,$this,$param);
	}
	public function renderControl($writer)
	{
		if($this->getVisible(false))
		{
			if(isset($this->_rf[self::RF_ADAPTER]))
				$this->_rf[self::RF_ADAPTER]->render($writer);
			else
				$this->render($writer);
		}
	}
	public function render($writer)
	{
		$this->renderChildren($writer);
	}
	public function renderChildren($writer)
	{
		if($this->getHasControls())
		{
			foreach($this->_rf[self::RF_CONTROLS] as $control)
			{
				if(is_string($control))
					$writer->write($control);
				else if($control instanceof TControl)
					$control->renderControl($writer);
				else if($control instanceof IRenderable)
					$control->render($writer);
			}
		}
	}
	public function saveState()
	{
	}
	public function loadState()
	{
	}
	protected function loadStateRecursive(&$state,$needViewState=true)
	{
		if(is_array($state))
		{
			$needViewState=($needViewState && !($this->_flags & self::IS_DISABLE_VIEWSTATE));
			if(isset($state[1]))
			{
				$this->_rf[self::RF_CONTROLSTATE]=&$state[1];
				unset($state[1]);
			}
			else
				unset($this->_rf[self::RF_CONTROLSTATE]);
			if($needViewState)
			{
				if(isset($state[0]))
					$this->_viewState=&$state[0];
				else
					$this->_viewState=array();
			}
			unset($state[0]);
			if($this->getHasControls())
			{
				foreach($this->_rf[self::RF_CONTROLS] as $control)
				{
					if($control instanceof TControl)
					{
						if(isset($state[$control->_id]))
						{
							$control->loadStateRecursive($state[$control->_id],$needViewState);
							unset($state[$control->_id]);
						}
					}
				}
			}
			if(!empty($state))
				$this->_rf[self::RF_CHILD_STATE]=&$state;
		}
		$this->_stage=self::CS_STATE_LOADED;
		if(isset($this->_rf[self::RF_ADAPTER]))
			$this->_rf[self::RF_ADAPTER]->loadState();
		else
			$this->loadState();
	}
	protected function &saveStateRecursive($needViewState=true)
	{
		if(isset($this->_rf[self::RF_ADAPTER]))
			$this->_rf[self::RF_ADAPTER]->saveState();
		else
			$this->saveState();
		$needViewState=($needViewState && !($this->_flags & self::IS_DISABLE_VIEWSTATE));
		$state=array();
		if($this->getHasControls())
		{
			foreach($this->_rf[self::RF_CONTROLS] as $control)
			{
				if($control instanceof TControl)
					$state[$control->_id]=&$control->saveStateRecursive($needViewState);
			}
		}
		if($needViewState && !empty($this->_viewState))
			$state[0]=&$this->_viewState;
		if(isset($this->_rf[self::RF_CONTROLSTATE]))
			$state[1]=&$this->_rf[self::RF_CONTROLSTATE];
		return $state;
	}
	public function applyStyleSheetSkin($page)
	{
		if($page && !($this->_flags & self::IS_STYLESHEET_APPLIED))
		{
			$page->applyControlStyleSheet($this);
			$this->_flags |= self::IS_STYLESHEET_APPLIED;
		}
		else if($this->_flags & self::IS_STYLESHEET_APPLIED)
			throw new TInvalidOperationException('control_stylesheet_applied',get_class($this));
	}
	private function clearCachedUniqueID($recursive)
	{
		if($recursive && $this->_uid!==null && isset($this->_rf[self::RF_CONTROLS]))
		{
			foreach($this->_rf[self::RF_CONTROLS] as $control)
				if($control instanceof TControl)
					$control->clearCachedUniqueID($recursive);
		}
		$this->_uid=null;
	}
	private function generateAutomaticID()
	{
		$this->_flags &= ~self::IS_ID_SET;
		if(!isset($this->_namingContainer->_rf[self::RF_NAMED_CONTROLS_ID]))
			$this->_namingContainer->_rf[self::RF_NAMED_CONTROLS_ID]=0;
		$id=$this->_namingContainer->_rf[self::RF_NAMED_CONTROLS_ID]++;
		$this->_id=self::AUTOMATIC_ID_PREFIX . $id;
		$this->_namingContainer->clearNameTable();
	}
	private function clearNameTable()
	{
		unset($this->_rf[self::RF_NAMED_CONTROLS]);
	}
	private function fillNameTable($container,$controls)
	{
		foreach($controls as $control)
		{
			if($control instanceof TControl)
			{
				if($control->_id!=='')
				{
					if(isset($container->_rf[self::RF_NAMED_CONTROLS][$control->_id]))
						throw new TInvalidDataValueException('control_id_nonunique',get_class($control),$control->_id);
					else
						$container->_rf[self::RF_NAMED_CONTROLS][$control->_id]=$control;
				}
				if(!($control instanceof INamingContainer) && $control->getHasControls())
					$this->fillNameTable($container,$control->_rf[self::RF_CONTROLS]);
			}
		}
	}
}
class TControlCollection extends TList
{
	private $_o;
	public function __construct(TControl $owner,$readOnly=false)
	{
		$this->_o=$owner;
		parent::__construct(null,$readOnly);
	}
	protected function getOwner()
	{
		return $this->_o;
	}
	public function insertAt($index,$item)
	{
		if($item instanceof TControl)
		{
			parent::insertAt($index,$item);
			$this->_o->addedControl($item);
		}
		else if(is_string($item) || ($item instanceof IRenderable))
			parent::insertAt($index,$item);
		else
			throw new TInvalidDataTypeException('controlcollection_control_required');
	}
	public function removeAt($index)
	{
		$item=parent::removeAt($index);
		if($item instanceof TControl)
			$this->_o->removedControl($item);
		return $item;
	}
	public function clear()
	{
		parent::clear();
		if($this->_o instanceof INamingContainer)
			$this->_o->clearNamingContainer();
	}
}
class TEmptyControlCollection extends TControlCollection
{
	public function __construct(TControl $owner)
	{
		parent::__construct($owner,true);
	}
	public function insertAt($index,$item)
	{
		if(!is_string($item))  
			parent::insertAt($index,$item);  
	}
}
interface INamingContainer
{
}
interface IPostBackEventHandler
{
	public function raisePostBackEvent($param);
}
interface IPostBackDataHandler
{
	public function loadPostData($key,$values);
	public function raisePostDataChangedEvent();
	public function getDataChanged();
}
interface IValidator
{
	public function validate();
	public function getIsValid();
	public function setIsValid($value);
	public function getErrorMessage();
	public function setErrorMessage($value);
}
interface IValidatable
{
	public function getValidationPropertyValue();
}
interface IBroadcastEventReceiver
{
	public function broadcastEventReceived($sender,$param);
}
interface ITheme
{
	public function applySkin($control);
}
interface ITemplate
{
	public function instantiateIn($parent);
}
interface IButtonControl
{
	public function getText();
	public function setText($value);
	public function getCausesValidation();
	public function setCausesValidation($value);
	public function getCommandName();
	public function setCommandName($value);
	public function getCommandParameter();
	public function setCommandParameter($value);
	public function getValidationGroup();
	public function setValidationGroup($value);
	public function onClick($param);
	public function onCommand($param);
	public function setIsDefaultButton($value);
	public function getIsDefaultButton();
}
interface ISurroundable
{
	public function getSurroundingTagID();
}
class TBroadcastEventParameter extends TEventParameter
{
	private $_name;
	private $_param;
	public function __construct($name='',$parameter=null)
	{
		$this->_name=$name;
		$this->_param=$parameter;
	}
	public function getName()
	{
		return $this->_name;
	}
	public function setName($value)
	{
		$this->_name=$value;
	}
	public function getParameter()
	{
		return $this->_param;
	}
	public function setParameter($value)
	{
		$this->_param=$value;
	}
}
class TCommandEventParameter extends TEventParameter
{
	private $_name;
	private $_param;
	public function __construct($name='',$parameter='')
	{
		$this->_name=$name;
		$this->_param=$parameter;
	}
	public function getCommandName()
	{
		return $this->_name;
	}
	public function getCommandParameter()
	{
		return $this->_param;
	}
}
class TCompositeLiteral extends TComponent implements IRenderable, IBindable
{
	const TYPE_EXPRESSION=0;
	const TYPE_STATEMENTS=1;
	const TYPE_DATABINDING=2;
	private $_container=null;
	private $_items=array();
	private $_expressions=array();
	private $_statements=array();
	private $_bindings=array();
	public function __construct($items)
	{
		$this->_items=array();
		$this->_expressions=array();
		$this->_statements=array();
		foreach($items as $id=>$item)
		{
			if(is_array($item))
			{
				if($item[0]===self::TYPE_EXPRESSION)
					$this->_expressions[$id]=$item[1];
				else if($item[0]===self::TYPE_STATEMENTS)
					$this->_statements[$id]=$item[1];
				else if($item[0]===self::TYPE_DATABINDING)
					$this->_bindings[$id]=$item[1];
				$this->_items[$id]='';
			}
			else
				$this->_items[$id]=$item;
		}
	}
	public function getContainer()
	{
		return $this->_container;
	}
	public function setContainer(TComponent $value)
	{
		$this->_container=$value;
	}
	public function evaluateDynamicContent()
	{
		$context=$this->_container===null?$this:$this->_container;
		foreach($this->_expressions as $id=>$expression)
			$this->_items[$id]=$context->evaluateExpression($expression);
		foreach($this->_statements as $id=>$statement)
			$this->_items[$id]=$context->evaluateStatements($statement);
	}
	public function dataBind()
	{
		$context=$this->_container===null?$this:$this->_container;
		foreach($this->_bindings as $id=>$binding)
			$this->_items[$id]=$context->evaluateExpression($binding);
	}
	public function render($writer)
	{
		$writer->write(implode('',$this->_items));
	}
}
class TFont extends TComponent
{
	const IS_BOLD=0x01;
	const IS_ITALIC=0x02;
	const IS_OVERLINE=0x04;
	const IS_STRIKEOUT=0x08;
	const IS_UNDERLINE=0x10;
	const IS_SET_BOLD=0x01000;
	const IS_SET_ITALIC=0x02000;
	const IS_SET_OVERLINE=0x04000;
	const IS_SET_STRIKEOUT=0x08000;
	const IS_SET_UNDERLINE=0x10000;
	const IS_SET_SIZE=0x20000;
	const IS_SET_NAME=0x40000;
	private $_flags=0;
	private $_name='';
	private $_size='';
	public function getBold()
	{
		return ($this->_flags & self::IS_BOLD)!==0;
	}
	public function setBold($value)
	{
		$this->_flags |= self::IS_SET_BOLD;
		if(TPropertyValue::ensureBoolean($value))
			$this->_flags |= self::IS_BOLD;
		else
			$this->_flags &= ~self::IS_BOLD;
	}
	public function getItalic()
	{
		return ($this->_flags & self::IS_ITALIC)!==0;
	}
	public function setItalic($value)
	{
		$this->_flags |= self::IS_SET_ITALIC;
		if(TPropertyValue::ensureBoolean($value))
			$this->_flags |= self::IS_ITALIC;
		else
			$this->_flags &= ~self::IS_ITALIC;
	}
	public function getOverline()
	{
		return ($this->_flags & self::IS_OVERLINE)!==0;
	}
	public function setOverline($value)
	{
		$this->_flags |= self::IS_SET_OVERLINE;
		if(TPropertyValue::ensureBoolean($value))
			$this->_flags |= self::IS_OVERLINE;
		else
			$this->_flags &= ~self::IS_OVERLINE;
	}
	public function getSize()
	{
		return $this->_size;
	}
	public function setSize($value)
	{
		$this->_flags |= self::IS_SET_SIZE;
		$this->_size=$value;
	}
	public function getStrikeout()
	{
		return ($this->_flags & self::IS_STRIKEOUT)!==0;
	}
	public function setStrikeout($value)
	{
		$this->_flags |= self::IS_SET_STRIKEOUT;
		if(TPropertyValue::ensureBoolean($value))
			$this->_flags |= self::IS_STRIKEOUT;
		else
			$this->_flags &= ~self::IS_STRIKEOUT;
	}
	public function getUnderline()
	{
		return ($this->_flags & self::IS_UNDERLINE)!==0;
	}
	public function setUnderline($value)
	{
		$this->_flags |= self::IS_SET_UNDERLINE;
		if(TPropertyValue::ensureBoolean($value))
			$this->_flags |= self::IS_UNDERLINE;
		else
			$this->_flags &= ~self::IS_UNDERLINE;
	}
	public function getName()
	{
		return $this->_name;
	}
	public function setName($value)
	{
		$this->_flags |= self::IS_SET_NAME;
		$this->_name=$value;
	}
	public function getIsEmpty()
	{
		return !$this->_flags;
	}
	public function reset()
	{
		$this->_flags=0;
		$this->_name='';
		$this->_size='';
	}
	public function mergeWith($font)
	{
		if($font===null || $font->_flags===0)
			return;
		if(!($this->_flags & self::IS_SET_BOLD) && ($font->_flags & self::IS_SET_BOLD))
			$this->setBold($font->getBold());
		if(!($this->_flags & self::IS_SET_ITALIC) && ($font->_flags & self::IS_SET_ITALIC))
			$this->setItalic($font->getItalic());
		if(!($this->_flags & self::IS_SET_OVERLINE) && ($font->_flags & self::IS_SET_OVERLINE))
			$this->setOverline($font->getOverline());
		if(!($this->_flags & self::IS_SET_STRIKEOUT) && ($font->_flags & self::IS_SET_STRIKEOUT))
			$this->setStrikeout($font->getStrikeout());
		if(!($this->_flags & self::IS_SET_UNDERLINE) && ($font->_flags & self::IS_SET_UNDERLINE))
			$this->setUnderline($font->getUnderline());
		if(!($this->_flags & self::IS_SET_SIZE) && ($font->_flags & self::IS_SET_SIZE))
			$this->setSize($font->getSize());
		if(!($this->_flags & self::IS_SET_NAME) && ($font->_flags & self::IS_SET_NAME))
			$this->setName($font->getName());
	}
	public function copyFrom($font)
	{
		if($font===null || $font->_flags===0)
			return;
		if($font->_flags & self::IS_SET_BOLD)
			$this->setBold($font->getBold());
		if($font->_flags & self::IS_SET_ITALIC)
			$this->setItalic($font->getItalic());
		if($font->_flags & self::IS_SET_OVERLINE)
			$this->setOverline($font->getOverline());
		if($font->_flags & self::IS_SET_STRIKEOUT)
			$this->setStrikeout($font->getStrikeout());
		if($font->_flags & self::IS_SET_UNDERLINE)
			$this->setUnderline($font->getUnderline());
		if($font->_flags & self::IS_SET_SIZE)
			$this->setSize($font->getSize());
		if($font->_flags & self::IS_SET_NAME)
			$this->setName($font->getName());
	}
	public function toString()
	{
		if($this->_flags===0)
			return '';
		$str='';
		if($this->_flags & self::IS_SET_BOLD)
			$str.='font-weight:'.(($this->_flags & self::IS_BOLD)?'bold;':'normal;');
		if($this->_flags & self::IS_SET_ITALIC)
			$str.='font-style:'.(($this->_flags & self::IS_ITALIC)?'italic;':'normal;');
		$textDec='';
		if($this->_flags & self::IS_UNDERLINE)
			$textDec.='underline';
		if($this->_flags & self::IS_OVERLINE)
			$textDec.=' overline';
		if($this->_flags & self::IS_STRIKEOUT)
			$textDec.=' line-through';
		$textDec=ltrim($textDec);
		if($textDec!=='')
			$str.='text-decoration:'.$textDec.';';
		if($this->_size!=='')
			$str.='font-size:'.$this->_size.';';
		if($this->_name!=='')
			$str.='font-family:'.$this->_name.';';
		return $str;
	}
	public function addAttributesToRender($writer)
	{
		if($this->_flags===0)
			return;
		if($this->_flags & self::IS_SET_BOLD)
			$writer->addStyleAttribute('font-weight',(($this->_flags & self::IS_BOLD)?'bold':'normal'));
		if($this->_flags & self::IS_SET_ITALIC)
			$writer->addStyleAttribute('font-style',(($this->_flags & self::IS_ITALIC)?'italic':'normal'));
		$textDec='';
		if($this->_flags & self::IS_UNDERLINE)
			$textDec.='underline';
		if($this->_flags & self::IS_OVERLINE)
			$textDec.=' overline';
		if($this->_flags & self::IS_STRIKEOUT)
			$textDec.=' line-through';
		$textDec=ltrim($textDec);
		if($textDec!=='')
			$writer->addStyleAttribute('text-decoration',$textDec);
		if($this->_size!=='')
			$writer->addStyleAttribute('font-size',$this->_size);
		if($this->_name!=='')
			$writer->addStyleAttribute('font-family',$this->_name);
	}
}
class TStyle extends TComponent
{
	private $_fields=array();
	private $_font=null;
	private $_class=null;
	private $_customStyle=null;
	private $_displayStyle='Fixed';
	public function __construct($style=null)
	{
		if($style!==null)
			$this->copyFrom($style);
	}
	public function __clone()
	{
		if(!is_null($this->_font))
			$this->_font = clone($this->_font);
	}
	public function getBackColor()
	{
		return isset($this->_fields['background-color'])?$this->_fields['background-color']:'';
	}
	public function setBackColor($value)
	{
		if(trim($value)==='')
			unset($this->_fields['background-color']);
		else
			$this->_fields['background-color']=$value;
	}
	public function getBorderColor()
	{
		return isset($this->_fields['border-color'])?$this->_fields['border-color']:'';
	}
	public function setBorderColor($value)
	{
		if(trim($value)==='')
			unset($this->_fields['border-color']);
		else
			$this->_fields['border-color']=$value;
	}
	public function getBorderStyle()
	{
		return isset($this->_fields['border-style'])?$this->_fields['border-style']:'';
	}
	public function setBorderStyle($value)
	{
		if(trim($value)==='')
			unset($this->_fields['border-style']);
		else
			$this->_fields['border-style']=$value;
	}
	public function getBorderWidth()
	{
		return isset($this->_fields['border-width'])?$this->_fields['border-width']:'';
	}
	public function setBorderWidth($value)
	{
		if(trim($value)==='')
			unset($this->_fields['border-width']);
		else
			$this->_fields['border-width']=$value;
	}
	public function getCssClass()
	{
		return $this->_class===null?'':$this->_class;
	}
	public function hasCssClass()
	{
		return !is_null($this->_class);
	}
	public function setCssClass($value)
	{
		$this->_class=$value;
	}
	public function getFont()
	{
		if($this->_font===null)
			$this->_font=new TFont;
		return $this->_font;
	}
	public function hasFont()
	{
		return $this->_font !== null;
	}
	public function setDisplayStyle($value)
	{
		$this->_displayStyle = TPropertyValue::ensureEnum($value, 'TDisplayStyle');
		switch($this->_displayStyle)
		{
			case TDisplayStyle::None:
				$this->_fields['display'] = 'none';
				break;
			case TDisplayStyle::Dynamic:
				$this->_fields['display'] = ''; 
				break;
			case TDisplayStyle::Fixed:
				$this->_fields['visibility'] = 'visible';
				break;
			case TDisplayStyle::Hidden:
				$this->_fields['visibility'] = 'hidden';
				break;
		}
	}
	public function getDisplayStyle()
	{
		return $this->_displayStyle;
	}
	public function getForeColor()
	{
		return isset($this->_fields['color'])?$this->_fields['color']:'';
	}
	public function setForeColor($value)
	{
		if(trim($value)==='')
			unset($this->_fields['color']);
		else
			$this->_fields['color']=$value;
	}
	public function getHeight()
	{
		return isset($this->_fields['height'])?$this->_fields['height']:'';
	}
	public function setHeight($value)
	{
		if(trim($value)==='')
			unset($this->_fields['height']);
		else
			$this->_fields['height']=$value;
	}
	public function getCustomStyle()
	{
		return $this->_customStyle===null?'':$this->_customStyle;
	}
	public function setCustomStyle($value)
	{
		$this->_customStyle=$value;
	}
	public function getStyleField($name)
	{
		return isset($this->_fields[$name])?$this->_fields[$name]:'';
	}
	public function setStyleField($name,$value)
	{
		$this->_fields[$name]=$value;
	}
	public function clearStyleField($name)
	{
		unset($this->_fields[$name]);
	}
	public function hasStyleField($name)
	{
		return isset($this->_fields[$name]);
	}
	public function getWidth()
	{
		return isset($this->_fields['width'])?$this->_fields['width']:'';
	}
	public function setWidth($value)
	{
		$this->_fields['width']=$value;
	}
	public function reset()
	{
		$this->_fields=array();
		$this->_font=null;
		$this->_class=null;
		$this->_customStyle=null;
	}
	public function copyFrom($style)
	{
		if($style instanceof TStyle)
		{
			$this->_fields=array_merge($this->_fields,$style->_fields);
			if($style->_class!==null)
				$this->_class=$style->_class;
			if($style->_customStyle!==null)
				$this->_customStyle=$style->_customStyle;
			if($style->_font!==null)
				$this->getFont()->copyFrom($style->_font);
		}
	}
	public function mergeWith($style)
	{
		if($style instanceof TStyle)
		{
			$this->_fields=array_merge($style->_fields,$this->_fields);
			if($this->_class===null)
				$this->_class=$style->_class;
			if($this->_customStyle===null)
				$this->_customStyle=$style->_customStyle;
			if($style->_font!==null)
				$this->getFont()->mergeWith($style->_font);
		}
	}
	public function addAttributesToRender($writer)
	{
		if($this->_customStyle!==null)
		{
			foreach(explode(';',$this->_customStyle) as $style)
			{
				$arr=explode(':',$style);
				if(isset($arr[1]) && trim($arr[0])!=='')
					$writer->addStyleAttribute(trim($arr[0]),trim($arr[1]));
			}
		}
		$writer->addStyleAttributes($this->_fields);
		if($this->_font!==null)
			$this->_font->addAttributesToRender($writer);
		if($this->_class!==null)
			$writer->addAttribute('class',$this->_class);
	}
	public function getStyleFields()
	{
		return $this->_fields;
	}
}
class TDisplayStyle extends TEnumerable
{
	const None='None';
	const Dynamic='Dynamic';
	const Fixed='Fixed';
	const Hidden='Hidden';
}
class TTableStyle extends TStyle
{
	private $_backImageUrl=null;
	private $_horizontalAlign=null;
	private $_cellPadding=null;
	private $_cellSpacing=null;
	private $_gridLines=null;
	private $_borderCollapse=null;
	public function reset()
	{
		$this->_backImageUrl=null;
		$this->_horizontalAlign=null;
		$this->_cellPadding=null;
		$this->_cellSpacing=null;
		$this->_gridLines=null;
		$this->_borderCollapse=null;
	}
	public function copyFrom($style)
	{
		parent::copyFrom($style);
		if($style instanceof TTableStyle)
		{
			if($style->_backImageUrl!==null)
				$this->_backImageUrl=$style->_backImageUrl;
			if($style->_horizontalAlign!==null)
				$this->_horizontalAlign=$style->_horizontalAlign;
			if($style->_cellPadding!==null)
				$this->_cellPadding=$style->_cellPadding;
			if($style->_cellSpacing!==null)
				$this->_cellSpacing=$style->_cellSpacing;
			if($style->_gridLines!==null)
				$this->_gridLines=$style->_gridLines;
			if($style->_borderCollapse!==null)
				$this->_borderCollapse=$style->_borderCollapse;
		}
	}
	public function mergeWith($style)
	{
		parent::mergeWith($style);
		if($style instanceof TTableStyle)
		{
			if($this->_backImageUrl===null && $style->_backImageUrl!==null)
				$this->_backImageUrl=$style->_backImageUrl;
			if($this->_horizontalAlign===null && $style->_horizontalAlign!==null)
				$this->_horizontalAlign=$style->_horizontalAlign;
			if($this->_cellPadding===null && $style->_cellPadding!==null)
				$this->_cellPadding=$style->_cellPadding;
			if($this->_cellSpacing===null && $style->_cellSpacing!==null)
				$this->_cellSpacing=$style->_cellSpacing;
			if($this->_gridLines===null && $style->_gridLines!==null)
				$this->_gridLines=$style->_gridLines;
			if($this->_borderCollapse===null && $style->_borderCollapse!==null)
				$this->_borderCollapse=$style->_borderCollapse;
		}
	}
	public function addAttributesToRender($writer)
	{
		if(($url=trim($this->getBackImageUrl()))!=='')
			$writer->addStyleAttribute('background-image','url('.$url.')');
		if(($horizontalAlign=$this->getHorizontalAlign())!==THorizontalAlign::NotSet)
			$writer->addStyleAttribute('text-align',strtolower($horizontalAlign));
		if(($cellPadding=$this->getCellPadding())>=0)
			$writer->addAttribute('cellpadding',"$cellPadding");
		if(($cellSpacing=$this->getCellSpacing())>=0)
			$writer->addAttribute('cellspacing',"$cellSpacing");
		if($this->getBorderCollapse())
			$writer->addStyleAttribute('border-collapse','collapse');
		switch($this->getGridLines())
		{
			case TTableGridLines::Horizontal : $writer->addAttribute('rules','rows'); break;
			case TTableGridLines::Vertical : $writer->addAttribute('rules','cols'); break;
			case TTableGridLines::Both : $writer->addAttribute('rules','all'); break;
		}
		parent::addAttributesToRender($writer);
	}
	public function getBackImageUrl()
	{
		return $this->_backImageUrl===null?'':$this->_backImageUrl;
	}
	public function setBackImageUrl($value)
	{
		$this->_backImageUrl=$value;
	}
	public function getHorizontalAlign()
	{
		return $this->_horizontalAlign===null?THorizontalAlign::NotSet:$this->_horizontalAlign;
	}
	public function setHorizontalAlign($value)
	{
		$this->_horizontalAlign=TPropertyValue::ensureEnum($value,'THorizontalAlign');
	}
	public function getCellPadding()
	{
		return $this->_cellPadding===null?-1:$this->_cellPadding;
	}
	public function setCellPadding($value)
	{
		if(($this->_cellPadding=TPropertyValue::ensureInteger($value))<-1)
			throw new TInvalidDataValueException('tablestyle_cellpadding_invalid');
	}
	public function getCellSpacing()
	{
		return $this->_cellSpacing===null?-1:$this->_cellSpacing;
	}
	public function setCellSpacing($value)
	{
		if(($this->_cellSpacing=TPropertyValue::ensureInteger($value))<-1)
			throw new TInvalidDataValueException('tablestyle_cellspacing_invalid');
	}
	public function getGridLines()
	{
		return $this->_gridLines===null?TTableGridLines::None:$this->_gridLines;
	}
	public function setGridLines($value)
	{
		$this->_gridLines=TPropertyValue::ensureEnum($value,'TTableGridLines');
	}
	public function getBorderCollapse()
	{
		return $this->_borderCollapse===null?false:$this->_borderCollapse;
	}
	public function setBorderCollapse($value)
	{
		$this->_borderCollapse=TPropertyValue::ensureBoolean($value);
	}
}
class TTableItemStyle extends TStyle
{
	private $_horizontalAlign=null;
	private $_verticalAlign=null;
	private $_wrap=null;
	public function reset()
	{
		parent::reset();
		$this->_verticalAlign=null;
		$this->_horizontalAlign=null;
		$this->_wrap=null;
	}
	public function copyFrom($style)
	{
		parent::copyFrom($style);
		if($style instanceof TTableItemStyle)
		{
			if($this->_verticalAlign===null && $style->_verticalAlign!==null)
				$this->_verticalAlign=$style->_verticalAlign;
			if($this->_horizontalAlign===null && $style->_horizontalAlign!==null)
				$this->_horizontalAlign=$style->_horizontalAlign;
			if($this->_wrap===null && $style->_wrap!==null)
				$this->_wrap=$style->_wrap;
		}
	}
	public function mergeWith($style)
	{
		parent::mergeWith($style);
		if($style instanceof TTableItemStyle)
		{
			if($style->_verticalAlign!==null)
				$this->_verticalAlign=$style->_verticalAlign;
			if($style->_horizontalAlign!==null)
				$this->_horizontalAlign=$style->_horizontalAlign;
			if($style->_wrap!==null)
				$this->_wrap=$style->_wrap;
		}
	}
	public function addAttributesToRender($writer)
	{
		if(!$this->getWrap())
			$writer->addStyleAttribute('white-space','nowrap');
		if(($horizontalAlign=$this->getHorizontalAlign())!==THorizontalAlign::NotSet)
			$writer->addAttribute('align',strtolower($horizontalAlign));
		if(($verticalAlign=$this->getVerticalAlign())!==TVerticalAlign::NotSet)
			$writer->addAttribute('valign',strtolower($verticalAlign));
		parent::addAttributesToRender($writer);
	}
	public function getHorizontalAlign()
	{
		return $this->_horizontalAlign===null?THorizontalAlign::NotSet:$this->_horizontalAlign;
	}
	public function setHorizontalAlign($value)
	{
		$this->_horizontalAlign=TPropertyValue::ensureEnum($value,'THorizontalAlign');
	}
	public function getVerticalAlign()
	{
		return $this->_verticalAlign===null?TVerticalAlign::NotSet:$this->_verticalAlign;
	}
	public function setVerticalAlign($value)
	{
		$this->_verticalAlign=TPropertyValue::ensureEnum($value,'TVerticalAlign');
	}
	public function getWrap()
	{
		return $this->_wrap===null?true:$this->_wrap;
	}
	public function setWrap($value)
	{
		$this->_wrap=TPropertyValue::ensureBoolean($value);
	}
}
class THorizontalAlign extends TEnumerable
{
	const NotSet='NotSet';
	const Left='Left';
	const Right='Right';
	const Center='Center';
	const Justify='Justify';
}
class TVerticalAlign extends TEnumerable
{
	const NotSet='NotSet';
	const Top='Top';
	const Bottom='Bottom';
	const Middle='Middle';
}
class TTableGridLines extends TEnumerable
{
	const None='None';
	const Horizontal='Horizontal';
	const Vertical='Vertical';
	const Both='Both';
}
class TWebControlAdapter extends TControlAdapter
{
	public function render($writer)
	{
		$this->renderBeginTag($writer);
		$this->renderContents($writer);
		$this->renderEndTag($writer);
	}
	public function renderBeginTag($writer)
	{
		$this->getControl()->renderBeginTag($writer);
	}
	public function renderContents($writer)
	{
		$this->getControl()->renderContents($writer);
	}
	public function renderEndTag($writer)
	{
		$this->getControl()->renderEndTag($writer);
	}
}
class TWebControl extends TControl implements IStyleable
{
	public function copyBaseAttributes(TWebControl $control)
	{
		$this->setAccessKey($control->getAccessKey());
		$this->setToolTip($control->getToolTip());
		$this->setTabIndex($control->getTabIndex());
		if(!$control->getEnabled())
			$this->setEnabled(false);
		if($control->getHasAttributes())
			$this->getAttributes()->copyFrom($control->getAttributes());
	}
	public function getAccessKey()
	{
		return $this->getViewState('AccessKey','');
	}
	public function setAccessKey($value)
	{
		if(strlen($value)>1)
			throw new TInvalidDataValueException('webcontrol_accesskey_invalid',get_class($this),$value);
		$this->setViewState('AccessKey',$value,'');
	}
	public function getBackColor()
	{
		if($style=$this->getViewState('Style',null))
			return $style->getBackColor();
		else
			return '';
	}
	public function setBackColor($value)
	{
		$this->getStyle()->setBackColor($value);
	}
	public function getBorderColor()
	{
		if($style=$this->getViewState('Style',null))
			return $style->getBorderColor();
		else
			return '';
	}
	public function setBorderColor($value)
	{
		$this->getStyle()->setBorderColor($value);
	}
	public function getBorderStyle()
	{
		if($style=$this->getViewState('Style',null))
			return $style->getBorderStyle();
		else
			return '';
	}
	public function setBorderStyle($value)
	{
		$this->getStyle()->setBorderStyle($value);
	}
	public function getBorderWidth()
	{
		if($style=$this->getViewState('Style',null))
			return $style->getBorderWidth();
		else
			return '';
	}
	public function setBorderWidth($value)
	{
		$this->getStyle()->setBorderWidth($value);
	}
	public function getFont()
	{
		return $this->getStyle()->getFont();
	}
	public function getForeColor()
	{
		if($style=$this->getViewState('Style',null))
			return $style->getForeColor();
		else
			return '';
	}
	public function setForeColor($value)
	{
		$this->getStyle()->setForeColor($value);
	}
	public function getHeight()
	{
		if($style=$this->getViewState('Style',null))
			return $style->getHeight();
		else
			return '';
	}
	public function setDisplay($value)
	{
		$this->getStyle()->setDisplayStyle($value);
	}
	public function getDisplay()
	{
		return $this->getStyle()->getDisplayStyle();
	}
	public function setCssClass($value)
	{
		$this->getStyle()->setCssClass($value);
	}
	public function getCssClass()
	{
		if($style=$this->getViewState('Style',null))
			return $style->getCssClass();
		else
			return '';
	}
	public function setHeight($value)
	{
		$this->getStyle()->setHeight($value);
	}
	public function getHasStyle()
	{
		return $this->getViewState('Style',null)!==null;
	}
	protected function createStyle()
	{
		return new TStyle;
	}
	public function getStyle()
	{
		if($style=$this->getViewState('Style',null))
			return $style;
		else
		{
			$style=$this->createStyle();
			$this->setViewState('Style',$style,null);
			return $style;
		}
	}
	public function setStyle($value)
	{
		if(is_string($value))
			$this->getStyle()->setCustomStyle($value);
		else
			throw new TInvalidDataValueException('webcontrol_style_invalid',get_class($this));
	}
	public function clearStyle()
	{
		$this->clearViewState('Style');
	}
	public function getTabIndex()
	{
		return $this->getViewState('TabIndex',0);
	}
	public function setTabIndex($value)
	{
		$this->setViewState('TabIndex',TPropertyValue::ensureInteger($value),0);
	}
	protected function getTagName()
	{
		return 'span';
	}
	public function getToolTip()
	{
		return $this->getViewState('ToolTip','');
	}
	public function setToolTip($value)
	{
		$this->setViewState('ToolTip',$value,'');
	}
	public function getWidth()
	{
		if($style=$this->getViewState('Style',null))
			return $style->getWidth();
		else
			return '';
	}
	public function setWidth($value)
	{
		$this->getStyle()->setWidth($value);
	}
	protected function addAttributesToRender($writer)
	{
		if($this->getID()!=='')
			$writer->addAttribute('id',$this->getClientID());
		if(($accessKey=$this->getAccessKey())!=='')
			$writer->addAttribute('accesskey',$accessKey);
		if(!$this->getEnabled())
			$writer->addAttribute('disabled','disabled');
		if(($tabIndex=$this->getTabIndex())>0)
			$writer->addAttribute('tabindex',"$tabIndex");
		if(($toolTip=$this->getToolTip())!=='')
			$writer->addAttribute('title',$toolTip);
		if($style=$this->getViewState('Style',null))
			$style->addAttributesToRender($writer);
		if($this->getHasAttributes())
		{
			foreach($this->getAttributes() as $name=>$value)
				$writer->addAttribute($name,$value);
		}
	}
	public function render($writer)
	{
		$this->renderBeginTag($writer);
		$this->renderContents($writer);
		$this->renderEndTag($writer);
	}
	public function renderBeginTag($writer)
	{
		$this->addAttributesToRender($writer);
		$writer->renderBeginTag($this->getTagName());
	}
	public function renderContents($writer)
	{
		parent::renderChildren($writer);
	}
	public function renderEndTag($writer)
	{
		$writer->renderEndTag();
	}
}
class TCompositeControl extends TControl implements INamingContainer
{
	protected function initRecursive($namingContainer=null)
	{
		$this->ensureChildControls();
		parent::initRecursive($namingContainer);
	}
}
class TTemplateControl extends TCompositeControl
{
	const EXT_TEMPLATE='.tpl';
	private static $_template=array();
	private $_localTemplate=null;
	private $_master=null;
	private $_masterClass='';
	private $_contents=array();
	private $_placeholders=array();
	public function getTemplate()
	{
		if($this->_localTemplate===null)
		{
			$class=get_class($this);
			if(!isset(self::$_template[$class]))
				self::$_template[$class]=$this->loadTemplate();
			return self::$_template[$class];
		}
		else
			return $this->_localTemplate;
	}
	public function setTemplate($value)
	{
		$this->_localTemplate=$value;
	}
	public function getIsSourceTemplateControl()
	{
		if(($template=$this->getTemplate())!==null)
			return $template->getIsSourceTemplate();
		else
			return false;
	}
	public function getTemplateDirectory()
	{
		if(($template=$this->getTemplate())!==null)
			return $template->getContextPath();
		else
			return '';
	}
	protected function loadTemplate()
	{
		$template=$this->getService()->getTemplateManager()->getTemplateByClassName(get_class($this));
		return $template;
	}
	public function createChildControls()
	{
		if($tpl=$this->getTemplate())
		{
			foreach($tpl->getDirective() as $name=>$value)
			{
				if(is_string($value))
					$this->setSubProperty($name,$value);
				else
					throw new TConfigurationException('templatecontrol_directive_invalid',get_class($this),$name);
			}
			$tpl->instantiateIn($this);
		}
	}
	public function registerContent($id,TContent $object)
	{
		if(isset($this->_contents[$id]))
			throw new TConfigurationException('templatecontrol_contentid_duplicated',$id);
		else
			$this->_contents[$id]=$object;
	}
	public function registerContentPlaceHolder($id,TContentPlaceHolder $object)
	{
		if(isset($this->_placeholders[$id]))
			throw new TConfigurationException('templatecontrol_placeholderid_duplicated',$id);
		else
			$this->_placeholders[$id]=$object;
	}
	public function getMasterClass()
	{
		return $this->_masterClass;
	}
	public function setMasterClass($value)
	{
		$this->_masterClass=$value;
	}
	public function getMaster()
	{
		return $this->_master;
	}
	public function injectContent($id,$content)
	{
		if(isset($this->_placeholders[$id]))
		{
			$placeholder=$this->_placeholders[$id];
			$controls=$placeholder->getParent()->getControls();
			$loc=$controls->remove($placeholder);
			$controls->insertAt($loc,$content);
		}
		else
			throw new TConfigurationException('templatecontrol_placeholder_inexistent',$id);
	}
	protected function initRecursive($namingContainer=null)
	{
		$this->ensureChildControls();
		if($this->_masterClass!=='')
		{
			$master=Prado::createComponent($this->_masterClass);
			if(!($master instanceof TTemplateControl))
				throw new TInvalidDataValueException('templatecontrol_mastercontrol_invalid');
			$this->_master=$master;
			$this->getControls()->clear();
			$this->getControls()->add($master);
			$master->ensureChildControls();
			foreach($this->_contents as $id=>$content)
				$master->injectContent($id,$content);
		}
		else if(!empty($this->_contents))
			throw new TConfigurationException('templatecontrol_mastercontrol_required',get_class($this));
		parent::initRecursive($namingContainer);
	}
}
class TForm extends TControl
{
	public function onInit($param)
	{
		parent::onInit($param);
		$this->getPage()->setForm($this);
	}
	protected function addAttributesToRender($writer)
	{
		$writer->addAttribute('id',$this->getClientID());
		$writer->addAttribute('method',$this->getMethod());
		$uri=$this->getRequest()->getRequestURI();
		$writer->addAttribute('action',str_replace('&','&amp;',str_replace('&amp;','&',$uri)));
		if(($enctype=$this->getEnctype())!=='')
			$writer->addAttribute('enctype',$enctype);
		$attributes=$this->getAttributes();
		$attributes->remove('action');
		$writer->addAttributes($attributes);
		if(($butt=$this->getDefaultButton())!=='')
		{
			if(($button=$this->findControl($butt))!==null)
				$this->getPage()->getClientScript()->registerDefaultButton($this, $button);
			else
				throw new TInvalidDataValueException('form_defaultbutton_invalid',$butt);
		}
	}
	public function render($writer)
	{
		$page=$this->getPage();
		$page->beginFormRender($writer);
		$textWriter=new TTextWriter;
		$this->renderChildren(new THtmlWriter($textWriter));
		$content=$textWriter->flush();
		$page->endFormRender($writer);
		$this->addAttributesToRender($writer);
		$writer->renderBeginTag('form');
		$cs=$page->getClientScript();
		if($page->getClientSupportsJavaScript())
		{
			$cs->renderHiddenFields($writer);
			$cs->renderScriptFiles($writer);
			$cs->renderBeginScripts($writer);
			$writer->write($content);
			$cs->renderEndScripts($writer);
		}
		else
		{
			$cs->renderHiddenFields($writer);
			$writer->write($content);
		}
		$writer->renderEndTag();
	}
	public function getDefaultButton()
	{
		return $this->getViewState('DefaultButton','');
	}
	public function setDefaultButton($value)
	{
		$this->setViewState('DefaultButton',$value,'');
	}
	public function getMethod()
	{
		return $this->getViewState('Method','post');
	}
	public function setMethod($value)
	{
		$this->setViewState('Method',TPropertyValue::ensureEnum($value,'post','get'),'post');
	}
	public function getEnctype()
	{
		return $this->getViewState('Enctype','');
	}
	public function setEnctype($value)
	{
		$this->setViewState('Enctype',$value,'');
	}
	public function getName()
	{
		return $this->getUniqueID();
	}
}
class TClientScriptManager extends TApplicationComponent
{
	const SCRIPT_PATH='Web/Javascripts/source';
	const SCRIPT_LOADER='Web/Javascripts/clientscripts.php';
	private $_page;
	private $_hiddenFields=array();
	private $_beginScripts=array();
	private $_endScripts=array();
	private $_scriptFiles=array();
	private $_headScriptFiles=array();
	private $_headScripts=array();
	private $_styleSheetFiles=array();
	private $_styleSheets=array();
	private $_registeredPradoScripts=array();
	private static $_pradoScripts;
	public function __construct(TPage $owner)
	{
		$this->_page=$owner;
	}
	public function getRequiresHead()
	{
		return count($this->_styleSheetFiles) || count($this->_styleSheets)
			|| count($this->_headScriptFiles) || count($this->_headScripts);
	}
	public function registerPradoScript($name)
	{
		$this->registerPradoScriptInternal($name);
		$params=func_get_args();
		$this->_page->registerCachingAction('Page.ClientScript','registerPradoScript',$params);
	}
	private function registerPradoScriptInternal($name)
	{
		if(!isset($this->_registeredPradoScripts[$name]))
		{
			if(is_null(self::$_pradoScripts))
			{
				$packageFile = Prado::getFrameworkPath().DIRECTORY_SEPARATOR.self::SCRIPT_PATH.'/packages.php';
				list($packages,$deps)= include($packageFile);
				self::$_pradoScripts = $deps;
			}
			if(isset(self::$_pradoScripts[$name]))
				$this->_registeredPradoScripts[$name]=true;
			else
				throw new TInvalidOperationException('csmanager_pradoscript_invalid',$name);
		}
	}
	public function getPradoScriptAssetUrl()
	{
		$base = Prado::getFrameworkPath().DIRECTORY_SEPARATOR.self::SCRIPT_PATH;
		$assets = Prado::getApplication()->getAssetManager();
		return $assets->getPublishedUrl($base);
	}
	protected function renderPradoScripts($writer)
	{
		if(($packages=array_keys($this->_registeredPradoScripts))!==array())
		{
			$base = Prado::getFrameworkPath().DIRECTORY_SEPARATOR.self::SCRIPT_PATH;
			$url = $this->registerJavascriptPackages($base, $packages);
			$writer->write(TJavaScript::renderScriptFile($url));
		}
	}
	public function registerJavascriptPackages($base, $packages, $debug=null, $gzip=true)
	{
		list($path,$url) = $this->getPackagePathUrl($base);
		$scriptLoaderPath = $path.'/'.basename(self::SCRIPT_LOADER);
		$scriptLoaderSrc = Prado::getFrameworkPath().DIRECTORY_SEPARATOR.self::SCRIPT_LOADER;
		if(!is_file($scriptLoaderPath))
			copy($scriptLoaderSrc, $scriptLoaderPath);
		$url .= '/'.basename(self::SCRIPT_LOADER).'?js='.implode(',', $packages);
		if($debug!==false && $this->getApplication()->getMode()===TApplicationMode::Debug)
		{
			$this->verifyJavascriptPackages($base,$path,$packages);
			$url.='&amp;mode=debug';
		}
		if($gzip===false)
			$url.='&amp;gzip=false';
		return $url;
	}
	protected function verifyJavascriptPackages($base,$path,$scripts)
	{
		$file = $path.'/packages.php';
		if(is_file($file))
		{
			list($packs,$deps) = include($file);
			if(count($missing = array_diff($scripts, array_keys($deps))) > 0)
			{
				throw new TConfigurationException('csmanager_invalid_packages',
					$base.'/packages.php',implode(', ', $missing), implode(', ', array_keys($deps)));
			}
		}
	}
	protected function getPackagePathUrl($base)
	{
		$assets = Prado::getApplication()->getAssetManager();
		if(strpos($base, $assets->getBaseUrl())===false)
		{
			if(!is_null($dir = Prado::getPathOfNameSpace($base)))
				$base = $dir;
			return array($assets->getPublishedPath($base), $assets->publishFilePath($base));
		}
		else
		{
			return array($assets->getBasePath().str_replace($assets->getBaseUrl(),'',$base), $base);
		}
	}
	public function getCallbackReference(ICallbackEventHandler $callbackHandler, $options=null)
	{
		$options = !is_array($options) ? array() : $options;
		$class = new TReflectionClass($callbackHandler);
		$clientSide = $callbackHandler->getActiveControl()->getClientSide();
		$options = array_merge($options, $clientSide->getOptions()->toArray());
		$optionString = TJavascript::encode($options);
		$this->registerPradoScriptInternal('ajax');
		$id = $callbackHandler->getUniqueID();
		return "new Prado.CallbackRequest('{$id}',{$optionString})";
	}
	public function registerCallbackControl($class, $options)
	{
		$optionString=TJavaScript::encode($options);
		$code="new {$class}({$optionString});";
		$this->_endScripts[sprintf('%08X', crc32($code))]=$code;
		$this->registerPradoScriptInternal('ajax');
		$params=func_get_args();
		$this->_page->registerCachingAction('Page.ClientScript','registerCallbackControl',$params);
	}
	public function registerPostBackControl($class,$options)
	{
		if(is_null($class)) return;
		if(!isset($options['FormID']) && ($form=$this->_page->getForm())!==null)
			$options['FormID']=$form->getClientID();
		$optionString=TJavaScript::encode($options);
		$code="new {$class}({$optionString});";
		$this->_endScripts[sprintf('%08X', crc32($code))]=$code;
		$this->_hiddenFields[TPage::FIELD_POSTBACK_TARGET]='';
		$this->_hiddenFields[TPage::FIELD_POSTBACK_PARAMETER]='';
		$this->registerPradoScriptInternal('prado');
		$params=func_get_args();
		$this->_page->registerCachingAction('Page.ClientScript','registerPostBackControl',$params);
	}
	public function registerDefaultButton($panel, $button)
	{
		$panelID=is_string($panel)?$panel:$panel->getUniqueID();
		if(is_string($button))
			$buttonID=$button;
		else
		{
			$button->setIsDefaultButton(true);
			$buttonID=$button->getUniqueID();
		}
		$options = TJavaScript::encode($this->getDefaultButtonOptions($panelID, $buttonID));
		$code = "new Prado.WebUI.DefaultButton($options);";
		$this->_endScripts['prado:'.$panelID]=$code;
		$this->_hiddenFields[TPage::FIELD_POSTBACK_TARGET]='';
		$this->registerPradoScriptInternal('prado');
		$params=array($panelID,$buttonID);
		$this->_page->registerCachingAction('Page.ClientScript','registerDefaultButton',$params);
	}
	protected function getDefaultButtonOptions($panelID, $buttonID)
	{
		$options['Panel'] = TControl::convertUniqueIdToClientId($panelID);
		$options['Target'] = TControl::convertUniqueIdToClientId($buttonID);
		$options['EventTarget'] = $buttonID;
		$options['Event'] = 'click';
		return $options;
	}
	public function registerFocusControl($target)
	{
		$this->registerPradoScriptInternal('effects');
		if($target instanceof TControl)
			$target=$target->getClientID();
		$id = TJavaScript::quoteString($target);
		$this->_endScripts['prado:focus'] = 'new Effect.ScrollTo("'.$id.'"); Prado.Element.focus("'.$id.'");';
		$params=func_get_args();
		$this->_page->registerCachingAction('Page.ClientScript','registerFocusControl',$params);
	}
	public function registerStyleSheetFile($key,$url,$media='')
	{
		if($media==='')
			$this->_styleSheetFiles[$key]=$url;
		else
			$this->_styleSheetFiles[$key]=array($url,$media);
		$params=func_get_args();
		$this->_page->registerCachingAction('Page.ClientScript','registerStyleSheetFile',$params);
	}
	public function registerStyleSheet($key,$css,$media='')
	{
		$this->_styleSheets[$key]=$css;
		$params=func_get_args();
		$this->_page->registerCachingAction('Page.ClientScript','registerStyleSheet',$params);
	}
	public function registerHeadScriptFile($key,$url)
	{
		$this->_headScriptFiles[$key]=$url;
		$params=func_get_args();
		$this->_page->registerCachingAction('Page.ClientScript','registerHeadScriptFile',$params);
	}
	public function registerHeadScript($key,$script)
	{
		$this->_headScripts[$key]=$script;
		$params=func_get_args();
		$this->_page->registerCachingAction('Page.ClientScript','registerHeadScript',$params);
	}
	public function registerScriptFile($key,$url)
	{
		$this->_scriptFiles[$key]=$url;
		$params=func_get_args();
		$this->_page->registerCachingAction('Page.ClientScript','registerScriptFile',$params);
	}
	public function registerBeginScript($key,$script)
	{
		$this->_beginScripts[$key]=$script;
		$params=func_get_args();
		$this->_page->registerCachingAction('Page.ClientScript','registerBeginScript',$params);
	}
	public function registerEndScript($key,$script)
	{
		$this->_endScripts[$key]=$script;
		$params=func_get_args();
		$this->_page->registerCachingAction('Page.ClientScript','registerEndScript',$params);
	}
	public function registerHiddenField($name,$value)
	{
		$this->_hiddenFields[$name]=$value;
		$params=func_get_args();
		$this->_page->registerCachingAction('Page.ClientScript','registerHiddenField',$params);
	}
	public function isStyleSheetFileRegistered($key)
	{
		return isset($this->_styleSheetFiles[$key]);
	}
	public function isStyleSheetRegistered($key)
	{
		return isset($this->_styleSheets[$key]);
	}
	public function isHeadScriptFileRegistered($key)
	{
		return isset($this->_headScriptFiles[$key]);
	}
	public function isHeadScriptRegistered($key)
	{
		return isset($this->_headScripts[$key]);
	}
	public function isScriptFileRegistered($key)
	{
		return isset($this->_scriptFiles[$key]);
	}
	public function isBeginScriptRegistered($key)
	{
		return isset($this->_beginScripts[$key]);
	}
	public function isEndScriptRegistered($key)
	{
		return isset($this->_endScripts[$key]);
	}
	public function hasEndScripts()
	{
		return count($this->_endScripts) > 0;
	}
	public function hasBeginScripts()
	{
		return count($this->_beginScripts) > 0;
	}
	public function isHiddenFieldRegistered($key)
	{
		return isset($this->_hiddenFields[$key]);
	}
	public function renderStyleSheetFiles($writer)
	{
		$str='';
		foreach($this->_styleSheetFiles as $url)
		{
			if(is_array($url))
				$str.="<link rel=\"stylesheet\" type=\"text/css\" media=\"{$url[1]}\" href=\"".THttpUtility::htmlEncode($url[0])."\" />\n";
			else
				$str.="<link rel=\"stylesheet\" type=\"text/css\" href=\"".THttpUtility::htmlEncode($url)."\" />\n";
		}
		$writer->write($str);
	}
	public function renderStyleSheets($writer)
	{
		if(count($this->_styleSheets))
			$writer->write("<style type=\"text/css\">\n/*<![CDATA[*/\n".implode("\n",$this->_styleSheets)."\n/*]]>*/\n</style>\n");
	}
	public function renderHeadScriptFiles($writer)
	{
		$writer->write(TJavaScript::renderScriptFiles($this->_headScriptFiles));
	}
	public function renderHeadScripts($writer)
	{
		$writer->write(TJavaScript::renderScriptBlocks($this->_headScripts));
	}
	public function renderScriptFiles($writer)
	{
		$this->renderPradoScripts($writer);
		if(!empty($this->_scriptFiles))
			$writer->write(TJavaScript::renderScriptFiles($this->_scriptFiles));
	}
	public function renderBeginScripts($writer)
	{
		$writer->write(TJavaScript::renderScriptBlocks($this->_beginScripts));
	}
	public function renderEndScripts($writer)
	{
		$writer->write(TJavaScript::renderScriptBlocks($this->_endScripts));
	}
	public function renderHiddenFields($writer)
	{
		$str='';
		foreach($this->_hiddenFields as $name=>$value)
		{
			$id=strtr($name,':','_');
			if(is_array($value))
			{
				foreach($value as $v)
					$str.='<input type="hidden" name="'.$name.'[]" id="'.$id.'" value="'.THttpUtility::htmlEncode($value)."\" />\n";
			}
			else
			{
				$str.='<input type="hidden" name="'.$name.'" id="'.$id.'" value="'.THttpUtility::htmlEncode($value)."\" />\n";
			}
		}
		if($str!=='')
			$writer->write("<div style=\"visibility:hidden;\">\n".$str."</div>\n");
	}
}
abstract class TClientSideOptions extends TComponent
{
	private $_options;
	public function __construct()
	{
		$this->_options = Prado::createComponent('System.Collections.TMap');
	}
	protected function setFunction($name, $code)
	{
		if(!TJavascript::isFunction($code))
			$code = TJavascript::quoteFunction($this->ensureFunction($code));
		$this->setOption($name, $code);
	}
	protected function getOption($name)
	{
		return $this->_options->itemAt($name);
	}
	protected function setOption($name, $value)
	{
		$this->_options->add($name, $value);
	}
	public function getOptions()
	{
		return $this->_options;
	}
	protected function ensureFunction($javascript)
	{
		return "function(sender, parameter){ {$javascript} }";
	}
}
class TPage extends TTemplateControl
{
	const FIELD_POSTBACK_TARGET='PRADO_POSTBACK_TARGET';
	const FIELD_POSTBACK_PARAMETER='PRADO_POSTBACK_PARAMETER';
	const FIELD_LASTFOCUS='PRADO_LASTFOCUS';
	const FIELD_PAGESTATE='PRADO_PAGESTATE';
	const FIELD_CALLBACK_TARGET='PRADO_CALLBACK_TARGET';
	const FIELD_CALLBACK_PARAMETER='PRADO_CALLBACK_PARAMETER';
	private static $_systemPostFields=array(
		'PRADO_POSTBACK_TARGET'=>true,
		'PRADO_POSTBACK_PARAMETER'=>true,
		'PRADO_LASTFOCUS'=>true,
		'PRADO_PAGESTATE'=>true,
		'PRADO_CALLBACK_TARGET'=>true,
		'PRADO_CALLBACK_PARAMETER'=>true
	);
	private $_form;
	private $_head;
	private $_validators=array();
	private $_validated=false;
	private $_theme;
	private $_title;
	private $_styleSheet;
	private $_clientScript;
	private $_postData;
	private $_restPostData;
	private $_controlsPostDataChanged=array();
	private $_controlsRequiringPostData=array();
	private $_controlsRegisteredForPostData=array();
	private $_postBackEventTarget;
	private $_postBackEventParameter;
	private $_formRendered=false;
	private $_inFormRender=false;
	private $_focus;
	private $_pagePath='';
	private $_enableStateValidation=true;
	private $_enableStateEncryption=false;
	private $_statePersisterClass='System.Web.UI.TPageStatePersister';
	private $_statePersister;
	private $_cachingStack;
	private $_clientState='';
	private $_postDataLoaders=array();
	private $_isLoadingPostData=false;
	private $_enableJavaScript=true;
	public function __construct()
	{
		parent::__construct();
		$this->setPage($this);
	}
	public function run($writer)
	{
		$this->determinePostBackMode();
		if($this->getIsPostBack())
		{
			if($this->getIsCallback())
				$this->processCallbackRequest($writer);
			else
				$this->processPostBackRequest($writer);
		}
		else
			$this->processNormalRequest($writer);
	}
	protected function processNormalRequest($writer)
	{
		$this->onPreInit(null);
		$this->initRecursive();
		$this->onInitComplete(null);
		$this->onPreLoad(null);
		$this->loadRecursive();
		$this->onLoadComplete(null);
		$this->preRenderRecursive();
		$this->onPreRenderComplete(null);
		$this->savePageState();
		$this->onSaveStateComplete(null);
		$this->renderControl($writer);
		$this->unloadRecursive();
	}
	protected function processPostBackRequest($writer)
	{
		$this->onPreInit(null);
		$this->initRecursive();
		$this->onInitComplete(null);
		$this->_restPostData=new TMap;
		$this->loadPageState();
		$this->processPostData($this->_postData,true);
		$this->onPreLoad(null);
		$this->loadRecursive();
		$this->processPostData($this->_restPostData,false);
		$this->raiseChangedEvents();
		$this->raisePostBackEvent();
		$this->onLoadComplete(null);
		$this->preRenderRecursive();
		$this->onPreRenderComplete(null);
		$this->savePageState();
		$this->onSaveStateComplete(null);
		$this->renderControl($writer);
		$this->unloadRecursive();
	}
	protected function processCallbackRequest($writer)
	{
		Prado::using('System.Web.UI.ActiveControls.TActivePageAdapter');
		$this->setAdapter(new TActivePageAdapter($this));
        if (($g=$this->getApplication()->getGlobalization(false))!==null && 
            strtoupper($enc=$g->getCharset())!='UTF-8')
                foreach ($this->_postData as $k=>$v)
                    $this->_postData[$k]=iconv('UTF-8',$enc.'//IGNORE',$v);
		$this->onPreInit(null);
		$this->initRecursive();
		$this->onInitComplete(null);
		$this->_restPostData=new TMap;
		$this->loadPageState();
		$this->processPostData($this->_postData,true);
		$this->onPreLoad(null);
		$this->loadRecursive();
		$this->processPostData($this->_restPostData,false);
		$this->raiseChangedEvents();
		$this->getAdapter()->processCallbackEvent($writer);
		$this->onLoadComplete(null);
		$this->preRenderRecursive();
		$this->onPreRenderComplete(null);
		$this->savePageState();
		$this->onSaveStateComplete(null);
		$this->getAdapter()->renderCallbackResponse($writer);
		$this->unloadRecursive();
	}
	public function getCallbackClient()
	{
		if($this->getAdapter() !== null)
			return $this->getAdapter()->getCallbackClientHandler();
		else
			return new TCallbackClientScript();
	}
	public function setCallbackClient($client)
	{
		$this->getAdapter()->setCallbackClientHandler($client);
	}
	public function getCallbackEventTarget()
	{
		return $this->getAdapter()->getCallbackEventTarget();
	}
	public function setCallbackEventTarget(TControl $control)
	{
		$this->getAdapter()->setCallbackEventTarget($control);
	}
	public function getCallbackEventParameter()
	{
		return $this->getAdapter()->getCallbackEventParameter();
	}
	public function setCallbackEventParameter($value)
	{
		$this->getAdapter()->setCallbackEventParameter($value);
	}
	public function registerPostDataLoader($control)
	{
		$id=is_string($control)?$control:$control->getUniqueID();
		$this->_postDataLoaders[$id] = true;
	}
	public function getPostDataLoaders()
	{
		return array_keys($this->_postDataLoaders);
	}
	public function getForm()
	{
		return $this->_form;
	}
	public function setForm(TForm $form)
	{
		if($this->_form===null)
			$this->_form=$form;
		else
			throw new TInvalidOperationException('page_form_duplicated');
	}
	public function getValidators($validationGroup=null)
	{
		if(!$this->_validators)
			$this->_validators=new TList;
		if($validationGroup===null)
			return $this->_validators;
		else
		{
			$list=new TList;
			foreach($this->_validators as $validator)
				if($validator->getValidationGroup()===$validationGroup)
					$list->add($validator);
			return $list;
		}
	}
	public function validate($validationGroup=null)
	{
		$this->_validated=true;
		if($this->_validators && $this->_validators->getCount())
		{
			if($validationGroup===null)
			{
				foreach($this->_validators as $validator)
					$validator->validate();
			}
			else
			{
				foreach($this->_validators as $validator)
				{
					if($validator->getValidationGroup()===$validationGroup)
						$validator->validate();
				}
			}
		}
	}
	public function getIsValid()
	{
		if($this->_validated)
		{
			if($this->_validators && $this->_validators->getCount())
			{
				foreach($this->_validators as $validator)
					if(!$validator->getIsValid())
						return false;
			}
			return true;
		}
		else
			throw new TInvalidOperationException('page_isvalid_unknown');
	}
	public function getTheme()
	{
		if(is_string($this->_theme))
			$this->_theme=$this->getService()->getThemeManager()->getTheme($this->_theme);
		return $this->_theme;
	}
	public function setTheme($value)
	{
		$this->_theme=empty($value)?null:$value;
	}
	public function getStyleSheetTheme()
	{
		if(is_string($this->_styleSheet))
			$this->_styleSheet=$this->getService()->getThemeManager()->getTheme($this->_styleSheet);
		return $this->_styleSheet;
	}
	public function setStyleSheetTheme($value)
	{
		$this->_styleSheet=empty($value)?null:$value;
	}
	public function applyControlSkin($control)
	{
		if(($theme=$this->getTheme())!==null)
			$theme->applySkin($control);
	}
	public function applyControlStyleSheet($control)
	{
		if(($theme=$this->getStyleSheetTheme())!==null)
			$theme->applySkin($control);
	}
	public function getClientScript()
	{
		if(!$this->_clientScript)
			$this->_clientScript=new TClientScriptManager($this);
		return $this->_clientScript;
	}
	public function onPreInit($param)
	{
		$this->raiseEvent('OnPreInit',$this,$param);
	}
	public function onInitComplete($param)
	{
		$this->raiseEvent('OnInitComplete',$this,$param);
	}
	public function onPreLoad($param)
	{
		$this->raiseEvent('OnPreLoad',$this,$param);
	}
	public function onLoadComplete($param)
	{
		$this->raiseEvent('OnLoadComplete',$this,$param);
	}
	public function onPreRenderComplete($param)
	{
		$this->raiseEvent('OnPreRenderComplete',$this,$param);
		$cs=$this->getClientScript();
		$theme=$this->getTheme();
		if($theme instanceof ITheme)
		{
			foreach($theme->getStyleSheetFiles() as $url)
				$cs->registerStyleSheetFile($url,$url,$this->getCssMediaType($url));
			foreach($theme->getJavaScriptFiles() as $url)
				$cs->registerHeadScriptFile($url,$url);
		}
		$styleSheet=$this->getStyleSheetTheme();
		if($styleSheet instanceof ITheme)
		{
			foreach($styleSheet->getStyleSheetFiles() as $url)
				$cs->registerStyleSheetFile($url,$url,$this->getCssMediaType($url));
			foreach($styleSheet->getJavaScriptFiles() as $url)
				$cs->registerHeadScriptFile($url,$url);
		}
		if($cs->getRequiresHead() && $this->getHead()===null)
			throw new TConfigurationException('page_head_required');
	}
	private function getCssMediaType($url)
	{
		$segs=explode('.',basename($url));
		if(isset($segs[2]))
			return $segs[count($segs)-2];
		else
			return '';
	}
	public function onSaveStateComplete($param)
	{
		$this->raiseEvent('OnSaveStateComplete',$this,$param);
	}
	private function determinePostBackMode()
	{
		$postData=$this->getRequest();
		if($postData->contains(self::FIELD_PAGESTATE) || $postData->contains(self::FIELD_POSTBACK_TARGET))
			$this->_postData=$postData;
	}
	public function getIsPostBack()
	{
		return $this->_postData!==null;
	}
	public function getIsCallback()
	{
		return $this->getIsPostBack() && $this->getRequest()->contains(self::FIELD_CALLBACK_TARGET);
	}
	public function saveState()
	{
		parent::saveState();
		$this->setViewState('ControlsRequiringPostBack',$this->_controlsRegisteredForPostData,array());
	}
	public function loadState()
	{
		parent::loadState();
		$this->_controlsRequiringPostData=$this->getViewState('ControlsRequiringPostBack',array());
	}
	protected function loadPageState()
	{
		$state=$this->getStatePersister()->load();
		$this->loadStateRecursive($state,$this->getEnableViewState());
	}
	protected function savePageState()
	{
		$state=&$this->saveStateRecursive($this->getEnableViewState());
		$this->getStatePersister()->save($state);
	}
	protected function isSystemPostField($field)
	{
		return isset(self::$_systemPostFields[$field]);
	}
	public function registerRequiresPostData($control)
	{
		$id=is_string($control)?$control:$control->getUniqueID();
		$this->_controlsRegisteredForPostData[$id]=true;
		$this->registerPostDataLoader($id);
		$params=func_get_args();
		foreach($this->getCachingStack() as $item)
			$item->registerAction('Page','registerRequiresPostData',$id);
	}
	public function getPostBackEventTarget()
	{
		if($this->_postBackEventTarget===null && $this->_postData!==null)
		{
			$eventTarget=$this->_postData->itemAt(self::FIELD_POSTBACK_TARGET);
			if(!empty($eventTarget))
				$this->_postBackEventTarget=$this->findControl($eventTarget);
		}
		return $this->_postBackEventTarget;
	}
	public function setPostBackEventTarget(TControl $control)
	{
		$this->_postBackEventTarget=$control;
	}
	public function getPostBackEventParameter()
	{
		if($this->_postBackEventParameter===null && $this->_postData!==null)
		{
			if(($this->_postBackEventParameter=$this->_postData->itemAt(self::FIELD_POSTBACK_PARAMETER))===null)
				$this->_postBackEventParameter='';
		}
		return $this->_postBackEventParameter;
	}
	public function setPostBackEventParameter($value)
	{
		$this->_postBackEventParameter=$value;
	}
	protected function processPostData($postData,$beforeLoad)
	{
		$this->_isLoadingPostData=true;
		if($beforeLoad)
			$this->_restPostData=new TMap;
		foreach($postData as $key=>$value)
		{
			if($this->isSystemPostField($key))
				continue;
			else if($control=$this->findControl($key))
			{
				if($control instanceof IPostBackDataHandler)
				{
					if($control->loadPostData($key,$postData))
						$this->_controlsPostDataChanged[]=$control;
				}
				else if($control instanceof IPostBackEventHandler &&
					empty($this->_postData[self::FIELD_POSTBACK_TARGET]))
				{
					$this->_postData->add(self::FIELD_POSTBACK_TARGET,$key);  
				}
				unset($this->_controlsRequiringPostData[$key]);
			}
			else if($beforeLoad)
				$this->_restPostData->add($key,$value);
		}
		foreach($this->_controlsRequiringPostData as $key=>$value)
		{
			if($control=$this->findControl($key))
			{
				if($control instanceof IPostBackDataHandler)
				{
					if($control->loadPostData($key,$this->_postData))
						$this->_controlsPostDataChanged[]=$control;
				}
				else
					throw new TInvalidDataValueException('page_postbackcontrol_invalid',$key);
				unset($this->_controlsRequiringPostData[$key]);
			}
		}
		$this->_isLoadingPostData=false;
	}
	public function getIsLoadingPostData()
	{
		return $this->_isLoadingPostData;
	}
	private function raiseChangedEvents()
	{
		foreach($this->_controlsPostDataChanged as $control)
			$control->raisePostDataChangedEvent();
	}
	private function raisePostBackEvent()
	{
		if(($postBackHandler=$this->getPostBackEventTarget())===null)
			$this->validate();
		else if($postBackHandler instanceof IPostBackEventHandler)
			$postBackHandler->raisePostBackEvent($this->getPostBackEventParameter());
	}
	public function ensureRenderInForm($control)
	{
		if(!$this->getIsCallback() && !$this->_inFormRender)
			throw new TConfigurationException('page_control_outofform',get_class($control),$control->getUniqueID());
	}
	public function beginFormRender($writer)
	{
		if($this->_formRendered)
			throw new TConfigurationException('page_form_duplicated');
		$this->_formRendered=true;
		$this->_inFormRender=true;
		$this->getClientScript()->registerHiddenField(self::FIELD_PAGESTATE,$this->getClientState());
	}
	public function endFormRender($writer)
	{
		if($this->_focus)
		{
			if(($this->_focus instanceof TControl) && $this->_focus->getVisible(true))
				$focus=$this->_focus->getClientID();
			else
				$focus=$this->_focus;
			$this->getClientScript()->registerFocusControl($focus);
		}
		else if($this->_postData && ($lastFocus=$this->_postData->itemAt(self::FIELD_LASTFOCUS))!==null)
			$this->getClientScript()->registerFocusControl($lastFocus);
		$this->_inFormRender=false;
	}
	public function setFocus($value)
	{
		$this->_focus=$value;
	}
	public function getClientSupportsJavaScript()
	{
		return $this->_enableJavaScript;
	}
	public function setClientSupportsJavaScript($value)
	{
		$this->_enableJavaScript=TPropertyValue::ensureBoolean($value);
	}
	public function getHead()
	{
		return $this->_head;
	}
	public function setHead(THead $value)
	{
		if($this->_head)
			throw new TInvalidOperationException('page_head_duplicated');
		$this->_head=$value;
		if($this->_title!==null)
		{
			$this->_head->setTitle($this->_title);
			$this->_title=null;
		}
	}
	public function getTitle()
	{
		if($this->_head)
			return $this->_head->getTitle();
		else
			return $this->_title===null ? '' : $this->_title;
	}
	public function setTitle($value)
	{
		if($this->_head)
			$this->_head->setTitle($value);
		else
			$this->_title=$value;
	}
	public function getClientState()
	{
		return $this->_clientState;
	}
	public function setClientState($state)
	{
		$this->_clientState=$state;
	}
	public function getRequestClientState()
	{
		return $this->getRequest()->itemAt(self::FIELD_PAGESTATE);
	}
	public function getStatePersisterClass()
	{
		return $this->_statePersisterClass;
	}
	public function setStatePersisterClass($value)
	{
		$this->_statePersisterClass=$value;
	}
	public function getStatePersister()
	{
		if($this->_statePersister===null)
		{
			$this->_statePersister=Prado::createComponent($this->_statePersisterClass);
			if(!($this->_statePersister instanceof IPageStatePersister))
				throw new TInvalidDataTypeException('page_statepersister_invalid');
			$this->_statePersister->setPage($this);
		}
		return $this->_statePersister;
	}
	public function getEnableStateValidation()
	{
		return $this->_enableStateValidation;
	}
	public function setEnableStateValidation($value)
	{
		$this->_enableStateValidation=TPropertyValue::ensureBoolean($value);
	}
	public function getEnableStateEncryption()
	{
		return $this->_enableStateEncryption;
	}
	public function setEnableStateEncryption($value)
	{
		$this->_enableStateEncryption=TPropertyValue::ensureBoolean($value);
	}
	public function getPagePath()
	{
		return $this->_pagePath;
	}
	public function setPagePath($value)
	{
		$this->_pagePath=$value;
	}
	public function registerCachingAction($context,$funcName,$funcParams)
	{
		if($this->_cachingStack)
		{
			foreach($this->_cachingStack as $cache)
				$cache->registerAction($context,$funcName,$funcParams);
		}
	}
	public function getCachingStack()
	{
		if(!$this->_cachingStack)
			$this->_cachingStack=new TStack;
		return $this->_cachingStack;
	}
}
interface IPageStatePersister
{
	public function getPage();
	public function setPage(TPage $page);
	public function save($state);
	public function load();
}
class TPageStateFormatter
{
	public static function serialize($page,$data)
	{
		$sm=$page->getApplication()->getSecurityManager();
		if($page->getEnableStateValidation())
			$str=$sm->hashData(Prado::serialize($data));
		else
			$str=Prado::serialize($data);
		if($page->getEnableStateEncryption())
			$str=$sm->encrypt($str);
		if(extension_loaded('zlib'))
			$str=gzcompress($str);
		return base64_encode($str);
	}
	public static function unserialize($page,$data)
	{
		$str=base64_decode($data);
		if($str==='')
			return null;
		if(extension_loaded('zlib'))
			$str=@gzuncompress($str);
		if($str!==false)
		{
			$sm=$page->getApplication()->getSecurityManager();
			if($page->getEnableStateEncryption())
				$str=$sm->decrypt($str);
			if($page->getEnableStateValidation())
			{
				if(($str=$sm->validateData($str))!==false)
					return Prado::unserialize($str);
			}
			else
				return $str;
		}
		return null;
	}
}
class TOutputCache extends TControl implements INamingContainer
{
	const CACHE_ID_PREFIX='prado:outputcache';
	private $_cacheModuleID='';
	private $_dataCached=false;
	private $_cacheAvailable=false;
	private $_cacheChecked=false;
	private $_cacheKey=null;
	private $_duration=60;
	private $_cache=null;
	private $_contents;
	private $_state;
	private $_actions=array();
	private $_varyByParam='';
	private $_keyPrefix='';
	private $_varyBySession=false;
	private $_cachePostBack=false;
	private $_cacheTime=0;
	public function getAllowChildControls()
	{
		$this->determineCacheability();
		return !$this->_dataCached;
	}
	private function determineCacheability()
	{
		if(!$this->_cacheChecked)
		{
			$this->_cacheChecked=true;
			if($this->_duration>0 && ($this->_cachePostBack || !$this->getPage()->getIsPostBack()))
			{
				if($this->_cacheModuleID!=='')
				{
					$this->_cache=$this->getApplication()->getModule($this->_cacheModuleID);
					if(!($this->_cache instanceof ICache))
						throw new TConfigurationException('outputcache_cachemoduleid_invalid',$this->_cacheModuleID);
				}
				else
					$this->_cache=$this->getApplication()->getCache();
				if($this->_cache!==null)
				{
					$this->_cacheAvailable=true;
					$data=$this->_cache->get($this->getCacheKey());
					if(is_array($data))
					{
						$param=new TOutputCacheCheckDependencyEventParameter;
						$param->setCacheTime(isset($data[3])?$data[3]:0);
						$this->onCheckDependency($param);
						$this->_dataCached=$param->getIsValid();
					}
					else
						$this->_dataCached=false;
					if($this->_dataCached)
						list($this->_contents,$this->_state,$this->_actions,$this->_cacheTime)=$data;
				}
			}
		}
	}
	protected function initRecursive($namingContainer=null)
	{
		if($this->_cacheAvailable && !$this->_dataCached)
		{
			$stack=$this->getPage()->getCachingStack();
			$stack->push($this);
			parent::initRecursive($namingContainer);
			$stack->pop();
		}
		else
			parent::initRecursive($namingContainer);
	}
	protected function loadRecursive()
	{
		if($this->_cacheAvailable && !$this->_dataCached)
		{
			$stack=$this->getPage()->getCachingStack();
			$stack->push($this);
			parent::loadRecursive();
			$stack->pop();
		}
		else
		{
			if($this->_dataCached)
				$this->performActions();
			parent::loadRecursive();
		}
	}
	private function performActions()
	{
		$page=$this->getPage();
		$cs=$page->getClientScript();
		foreach($this->_actions as $action)
		{
			if($action[0]==='Page.ClientScript')
				call_user_func_array(array($cs,$action[1]),$action[2]);
			else if($action[0]==='Page')
				call_user_func_array(array($page,$action[1]),$action[2]);
			else
				call_user_func_array(array($this->getSubProperty($action[0]),$action[1]),$action[2]);
		}
	}
	protected function preRenderRecursive()
	{
		if($this->_cacheAvailable && !$this->_dataCached)
		{
			$stack=$this->getPage()->getCachingStack();
			$stack->push($this);
			parent::preRenderRecursive();
			$stack->pop();
		}
		else
			parent::preRenderRecursive();
	}
	protected function loadStateRecursive(&$state,$needViewState=true)
	{
		$st=unserialize($state);
		parent::loadStateRecursive($st,$needViewState);
	}
	protected function &saveStateRecursive($needViewState=true)
	{
		if($this->_dataCached)
			return $this->_state;
		else
		{
			$st=parent::saveStateRecursive($needViewState);
			$this->_state=serialize($st);
			return $this->_state;
		}
	}
	public function registerAction($context,$funcName,$funcParams)
	{
		$this->_actions[]=array($context,$funcName,$funcParams);
	}
	private function getCacheKey()
	{
		if($this->_cacheKey===null)
			$this->_cacheKey=$this->calculateCacheKey();
		return $this->_cacheKey;
	}
	protected function calculateCacheKey()
	{
		$key=$this->getBaseCacheKey();
		if($this->_varyBySession)
			$key.=$this->getSession()->getSessionID();
		if($this->_varyByParam!=='')
		{
			$params=array();
			$request=$this->getRequest();
			foreach(explode(',',$this->_varyByParam) as $name)
			{
				$name=trim($name);
				$params[$name]=$request->itemAt($name);
			}
			$key.=serialize($params);
		}
		$param=new TOutputCacheCalculateKeyEventParameter;
		$this->onCalculateKey($param);
		$key.=$param->getCacheKey();
		return $key;
	}
	protected function getBaseCacheKey()
	{
		return self::CACHE_ID_PREFIX.$this->_keyPrefix.$this->getPage()->getPagePath().$this->getUniqueID();
	}
	public function getCacheModuleID()
	{
		return $this->_cacheModuleID;
	}
	public function setCacheModuleID($value)
	{
		$this->_cacheModuleID=$value;
	}
	public function setCacheKeyPrefix($value)
	{
		$this->_keyPrefix=$value;
	}
	public function getCacheTime()
	{
		return $this->_cacheTime;
	}
	protected function getCacheDependency()
	{
		return null;
	}
	public function getContentCached()
	{
		return $this->_dataCached;
	}
	public function getDuration()
	{
		return $this->_duration;
	}
	public function setDuration($value)
	{
		if(($value=TPropertyValue::ensureInteger($value))<0)
			throw new TInvalidDataValueException('outputcache_duration_invalid',get_class($this));
		$this->_duration=$value;
	}
	public function getVaryByParam()
	{
		return $this->_varyByParam;
	}
	public function setVaryByParam($value)
	{
		$this->_varyByParam=trim($value);
	}
	public function getVaryBySession()
	{
		return $this->_varyBySession;
	}
	public function setVaryBySession($value)
	{
		$this->_varyBySession=TPropertyValue::ensureBoolean($value);
	}
	public function getCachingPostBack()
	{
		return $this->_cachePostBack;
	}
	public function setCachingPostBack($value)
	{
		$this->_cachePostBack=TPropertyValue::ensureBoolean($value);
	}
	public function onCheckDependency($param)
	{
		$this->raiseEvent('OnCheckDependency',$this,$param);
	}
	public function onCalculateKey($param)
	{
		$this->raiseEvent('OnCalculateKey',$this,$param);
	}
	public function render($writer)
	{
		if($this->_dataCached)
			$writer->write($this->_contents);
		else if($this->_cacheAvailable)
		{
			$textWriter=new TTextWriter;
			$stack=$this->getPage()->getCachingStack();
			$stack->push($this);
			parent::render(new THtmlWriter($textWriter));
			$stack->pop();
			$content=$textWriter->flush();
			$data=array($content,$this->_state,$this->_actions,time());
			$this->_cache->set($this->getCacheKey(),$data,$this->getDuration(),$this->getCacheDependency());
			$writer->write($content);
		}
		else
			parent::render($writer);
	}
}
class TOutputCacheCheckDependencyEventParameter extends TEventParameter
{
	private $_isValid=true;
	private $_cacheTime=0;
	public function getIsValid()
	{
		return $this->_isValid;
	}
	public function setIsValid($value)
	{
		$this->_isValid=TPropertyValue::ensureBoolean($value);
	}
	public function getCacheTime()
	{
		return $this->_cacheTime;
	}
	public function setCacheTime($value)
	{
		$this->_cacheTime=TPropertyValue::ensureInteger($value);
	}
}
class TOutputCacheCalculateKeyEventParameter extends TEventParameter
{
	private $_cacheKey='';
	public function getCacheKey()
	{
		return $this->_cacheKey;
	}
	public function setCacheKey($value)
	{
		$this->_cacheKey=TPropertyValue::ensureString($value);
	}
}
class TTemplateManager extends TModule
{
	const TEMPLATE_FILE_EXT='.tpl';
	const TEMPLATE_CACHE_PREFIX='prado:template:';
	public function init($config)
	{
		$this->getService()->setTemplateManager($this);
	}
	public function getTemplateByClassName($className)
	{
		$class=new ReflectionClass($className);
		$tplFile=dirname($class->getFileName()).DIRECTORY_SEPARATOR.$className.self::TEMPLATE_FILE_EXT;
		return $this->getTemplateByFileName($tplFile);
	}
	public function getTemplateByFileName($fileName)
	{
		if(($fileName=$this->getLocalizedTemplate($fileName))!==null)
		{
			if(($cache=$this->getApplication()->getCache())===null)
				return new TTemplate(file_get_contents($fileName),dirname($fileName),$fileName);
			else
			{
				$array=$cache->get(self::TEMPLATE_CACHE_PREFIX.$fileName);
				if(is_array($array))
				{
					list($template,$timestamps)=$array;
					if($this->getApplication()->getMode()===TApplicationMode::Performance)
						return $template;
					$cacheValid=true;
					foreach($timestamps as $tplFile=>$timestamp)
					{
						if(!is_file($tplFile) || filemtime($tplFile)>$timestamp)
						{
							$cacheValid=false;
							break;
						}
					}
					if($cacheValid)
						return $template;
				}
				$template=new TTemplate(file_get_contents($fileName),dirname($fileName),$fileName);
				$includedFiles=$template->getIncludedFiles();
				$timestamps=array();
				$timestamps[$fileName]=filemtime($fileName);
				foreach($includedFiles as $includedFile)
					$timestamps[$includedFile]=filemtime($includedFile);
				$cache->set(self::TEMPLATE_CACHE_PREFIX.$fileName,array($template,$timestamps));
				return $template;
			}
		}
		else
			return null;
	}
	protected function getLocalizedTemplate($filename)
	{
		if(($app=$this->getApplication()->getGlobalization(false))===null)
			return is_file($filename)?$filename:null;
		foreach($app->getLocalizedResource($filename) as $file)
		{
			if(($file=realpath($file))!==false && is_file($file))
				return $file;
		}
		return null;
	}
}
class TTemplate extends TApplicationComponent implements ITemplate
{
	const REGEX_RULES='/<!--.*?--!>|<!---.*?--->|<\/?com:([\w\.]+)((?:\s*[\w\.]+\s*=\s*\'.*?\'|\s*[\w\.]+\s*=\s*".*?"|\s*[\w\.]+\s*=\s*<%.*?%>)*)\s*\/?>|<\/?prop:([\w\.]+)\s*>|<%@\s*((?:\s*[\w\.]+\s*=\s*\'.*?\'|\s*[\w\.]+\s*=\s*".*?")*)\s*%>|<%[%#~\\$=\\[](.*?)%>|<prop:([\w\.]+)((?:\s*[\w\.]+\s*=\s*\'.*?\'|\s*[\w\.]+\s*=\s*".*?"|\s*[\w\.]+\s*=\s*<%.*?%>)*)\s*\/>/msS';
	const CONFIG_DATABIND=0;
	const CONFIG_EXPRESSION=1;
	const CONFIG_ASSET=2;
	const CONFIG_PARAMETER=3;
	const CONFIG_LOCALIZATION=4;
	const CONFIG_TEMPLATE=5;
	private $_tpl=array();
	private $_directive=array();
	private $_contextPath;
	private $_tplFile=null;
	private $_startingLine=0;
	private $_content;
	private $_sourceTemplate=true;
	private $_hashCode='';
	private $_tplControl=null;
	private $_includedFiles=array();
	private $_includeAtLine=array();
	private $_includeLines=array();
	public function __construct($template,$contextPath,$tplFile=null,$startingLine=0,$sourceTemplate=true)
	{
		$this->_sourceTemplate=$sourceTemplate;
		$this->_contextPath=$contextPath;
		$this->_tplFile=$tplFile;
		$this->_startingLine=$startingLine;
		$this->_content=$template;
		$this->_hashCode=md5($template);
		$this->parse($template);
		$this->_content=null; 
	}
	public function getTemplateFile()
	{
		return $this->_tplFile;
	}
	public function getIsSourceTemplate()
	{
		return $this->_sourceTemplate;
	}
	public function getContextPath()
	{
		return $this->_contextPath;
	}
	public function getDirective()
	{
		return $this->_directive;
	}
	public function getHashCode()
	{
		return $this->_hashCode;
	}
	public function &getItems()
	{
		return $this->_tpl;
	}
	public function instantiateIn($tplControl,$parentControl=null)
	{
		$this->_tplControl=$tplControl;
		if($parentControl===null)
			$parentControl=$tplControl;
		if(($page=$tplControl->getPage())===null)
			$page=$this->getService()->getRequestedPage();
		$controls=array();
		$directChildren=array();
		foreach($this->_tpl as $key=>$object)
		{
			if($object[0]===-1)
				$parent=$parentControl;
			else if(isset($controls[$object[0]]))
				$parent=$controls[$object[0]];
			else
				continue;
			if(isset($object[2]))	
			{
				$component=Prado::createComponent($object[1]);
				$properties=&$object[2];
				if($component instanceof TControl)
				{
					if($component instanceof TOutputCache)
						$component->setCacheKeyPrefix($this->_hashCode.$key);
					$component->setTemplateControl($tplControl);
					if(isset($properties['id']))
					{
						if(is_array($properties['id']))
							$properties['id']=$component->evaluateExpression($properties['id'][1]);
						$tplControl->registerObject($properties['id'],$component);
					}
					if(isset($properties['skinid']))
					{
						if(is_array($properties['skinid']))
							$component->setSkinID($component->evaluateExpression($properties['skinid'][1]));
						else
							$component->setSkinID($properties['skinid']);
						unset($properties['skinid']);
					}
					$component->trackViewState(false);
					$component->applyStyleSheetSkin($page);
					foreach($properties as $name=>$value)
						$this->configureControl($component,$name,$value);
					$component->trackViewState(true);
					if($parent===$parentControl)
						$directChildren[]=$component;
					else
						$component->createdOnTemplate($parent);
					if($component->getAllowChildControls())
						$controls[$key]=$component;
				}
				else if($component instanceof TComponent)
				{
					$controls[$key]=$component;
					if(isset($properties['id']))
					{
						if(is_array($properties['id']))
							$properties['id']=$component->evaluateExpression($properties['id'][1]);
						$tplControl->registerObject($properties['id'],$component);
						if(!$component->hasProperty('id'))
							unset($properties['id']);
					}
					foreach($properties as $name=>$value)
						$this->configureComponent($component,$name,$value);
					if($parent===$parentControl)
						$directChildren[]=$component;
					else
						$component->createdOnTemplate($parent);
				}
			}
			else
			{
				if($object[1] instanceof TCompositeLiteral)
				{
					$o=clone $object[1];
					$o->setContainer($tplControl);
					if($parent===$parentControl)
						$directChildren[]=$o;
					else
						$parent->addParsedObject($o);
				}
				else
				{
					if($parent===$parentControl)
						$directChildren[]=$object[1];
					else
						$parent->addParsedObject($object[1]);
				}
			}
		}
		foreach($directChildren as $control)
		{
			if($control instanceof TComponent)
				$control->createdOnTemplate($parentControl);
			else
				$parentControl->addParsedObject($control);
		}
	}
	protected function configureControl($control,$name,$value)
	{
		if(strncasecmp($name,'on',2)===0)		
			$this->configureEvent($control,$name,$value,$control);
		else if(($pos=strrpos($name,'.'))===false)	
			$this->configureProperty($control,$name,$value);
		else	
			$this->configureSubProperty($control,$name,$value);
	}
	protected function configureComponent($component,$name,$value)
	{
		if(strpos($name,'.')===false)	
			$this->configureProperty($component,$name,$value);
		else	
			$this->configureSubProperty($component,$name,$value);
	}
	protected function configureEvent($control,$name,$value,$contextControl)
	{
		if(strpos($value,'.')===false)
			$control->attachEventHandler($name,array($contextControl,'TemplateControl.'.$value));
		else
			$control->attachEventHandler($name,array($contextControl,$value));
	}
	protected function configureProperty($component,$name,$value)
	{
		if(is_array($value))
		{
			switch($value[0])
			{
				case self::CONFIG_DATABIND:
					$component->bindProperty($name,$value[1]);
					break;
				case self::CONFIG_EXPRESSION:
					if($component instanceof TControl)
						$component->autoBindProperty($name,$value[1]);
					else
					{
						$setter='set'.$name;
						$component->$setter($this->_tplControl->evaluateExpression($value[1]));
					}
					break;
				case self::CONFIG_TEMPLATE:
					$setter='set'.$name;
					$component->$setter($value[1]);
					break;
				case self::CONFIG_ASSET:		
					$setter='set'.$name;
					$url=$this->publishFilePath($this->_contextPath.DIRECTORY_SEPARATOR.$value[1]);
					$component->$setter($url);
					break;
				case self::CONFIG_PARAMETER:		
					$setter='set'.$name;
					$component->$setter($this->getApplication()->getParameters()->itemAt($value[1]));
					break;
				case self::CONFIG_LOCALIZATION:
					$setter='set'.$name;
					$component->$setter(Prado::localize($value[1]));
					break;
				default:	
					throw new TConfigurationException('template_tag_unexpected',$name,$value[1]);
					break;
			}
		}
		else
		{
			$setter='set'.$name;
			$component->$setter($value);
		}
	}
	protected function configureSubProperty($component,$name,$value)
	{
		if(is_array($value))
		{
			switch($value[0])
			{
				case self::CONFIG_DATABIND:		
					$component->bindProperty($name,$value[1]);
					break;
				case self::CONFIG_EXPRESSION:		
					if($component instanceof TControl)
						$component->autoBindProperty($name,$value[1]);
					else
						$component->setSubProperty($name,$this->_tplControl->evaluateExpression($value[1]));
					break;
				case self::CONFIG_TEMPLATE:
					$component->setSubProperty($name,$value[1]);
					break;
				case self::CONFIG_ASSET:		
					$url=$this->publishFilePath($this->_contextPath.DIRECTORY_SEPARATOR.$value[1]);
					$component->setSubProperty($name,$url);
					break;
				case self::CONFIG_PARAMETER:		
					$component->setSubProperty($name,$this->getApplication()->getParameters()->itemAt($value[1]));
					break;
				case self::CONFIG_LOCALIZATION:
					$component->setSubProperty($name,Prado::localize($value[1]));
					break;
				default:	
					throw new TConfigurationException('template_tag_unexpected',$name,$value[1]);
					break;
			}
		}
		else
			$component->setSubProperty($name,$value);
	}
	protected function parse($input)
	{
		$input=$this->preprocess($input);
		$tpl=&$this->_tpl;
		$n=preg_match_all(self::REGEX_RULES,$input,$matches,PREG_SET_ORDER|PREG_OFFSET_CAPTURE);
		$expectPropEnd=false;
		$textStart=0;
        $stack=array();
		$container=-1;
		$matchEnd=0;
		$c=0;
		$this->_directive=null;
		try
		{
			for($i=0;$i<$n;++$i)
			{
				$match=&$matches[$i];
				$str=$match[0][0];
				$matchStart=$match[0][1];
				$matchEnd=$matchStart+strlen($str)-1;
				if(strpos($str,'<com:')===0)	
				{
					if($expectPropEnd)
						continue;
					if($matchStart>$textStart)
						$tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
					$textStart=$matchEnd+1;
					$type=$match[1][0];
					$attributes=$this->parseAttributes($match[2][0],$match[2][1]);
					$this->validateAttributes($type,$attributes);
					$tpl[$c++]=array($container,$type,$attributes);
					if($str[strlen($str)-2]!=='/')  
					{
						array_push($stack,$type);
						$container=$c-1;
					}
				}
				else if(strpos($str,'</com:')===0)	
				{
					if($expectPropEnd)
						continue;
					if($matchStart>$textStart)
						$tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
					$textStart=$matchEnd+1;
					$type=$match[1][0];
					if(empty($stack))
						throw new TConfigurationException('template_closingtag_unexpected',"</com:$type>");
					$name=array_pop($stack);
					if($name!==$type)
					{
						$tag=$name[0]==='@' ? '</prop:'.substr($name,1).'>' : "</com:$name>";
						throw new TConfigurationException('template_closingtag_expected',$tag);
					}
					$container=$tpl[$container][0];
				}
				else if(strpos($str,'<%@')===0)	
				{
					if($expectPropEnd)
						continue;
					if($matchStart>$textStart)
						$tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
					$textStart=$matchEnd+1;
					if(isset($tpl[0]) || $this->_directive!==null)
						throw new TConfigurationException('template_directive_nonunique');
					$this->_directive=$this->parseAttributes($match[4][0],$match[4][1]);
				}
				else if(strpos($str,'<%')===0)	
				{
					if($expectPropEnd)
						continue;
					if($matchStart>$textStart)
						$tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
					$textStart=$matchEnd+1;
					$literal=trim($match[5][0]);
					if($str[2]==='=')	
						$tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,$literal));
					else if($str[2]==='%')  
						$tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_STATEMENTS,$literal));
					else if($str[2]==='#')
						$tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_DATABINDING,$literal));
					else if($str[2]==='$')
						$tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"\$this->getApplication()->getParameters()->itemAt('$literal')"));
					else if($str[2]==='~')
						$tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"\$this->publishFilePath('$this->_contextPath/$literal')"));
					else if($str[2]==='[')
					{
						$literal=strtr(trim(substr($literal,0,strlen($literal)-1)),array("'"=>"\'","\\"=>"\\\\"));
						$tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"Prado::localize('$literal')"));
					}
				}
				else if(strpos($str,'<prop:')===0)	
				{
					if(strrpos($str,'/>')===strlen($str)-2)  
					{
						if($expectPropEnd)
							continue;
						if($matchStart>$textStart)
							$tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
						$textStart=$matchEnd+1;
						$prop=strtolower($match[6][0]);
						$attrs=$this->parseAttributes($match[7][0],$match[7][1]);
						$attributes=array();
						foreach($attrs as $name=>$value)
							$attributes[$prop.'.'.$name]=$value;
						$type=$tpl[$container][1];
						$this->validateAttributes($type,$attributes);
						foreach($attributes as $name=>$value)
						{
							if(isset($tpl[$container][2][$name]))
								throw new TConfigurationException('template_property_duplicated',$name);
							$tpl[$container][2][$name]=$value;
						}
					}
					else  
					{
						$prop=strtolower($match[3][0]);
						array_push($stack,'@'.$prop);
						if(!$expectPropEnd)
						{
							if($matchStart>$textStart)
								$tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
							$textStart=$matchEnd+1;
							$expectPropEnd=true;
						}
					}
				}
				else if(strpos($str,'</prop:')===0)	
				{
					$prop=strtolower($match[3][0]);
					if(empty($stack))
						throw new TConfigurationException('template_closingtag_unexpected',"</prop:$prop>");
					$name=array_pop($stack);
					if($name!=='@'.$prop)
					{
						$tag=$name[0]==='@' ? '</prop:'.substr($name,1).'>' : "</com:$name>";
						throw new TConfigurationException('template_closingtag_expected',$tag);
					}
					if(($last=count($stack))<1 || $stack[$last-1][0]!=='@')
					{
						if($matchStart>$textStart)
						{
							$value=substr($input,$textStart,$matchStart-$textStart);
							if(substr($prop,-8,8)==='template')
								$value=$this->parseTemplateProperty($value,$textStart);
							else
								$value=$this->parseAttribute($value);
							if($container>=0)
							{
								$type=$tpl[$container][1];
								$this->validateAttributes($type,array($prop=>$value));
								if(isset($tpl[$container][2][$prop]))
									throw new TConfigurationException('template_property_duplicated',$prop);
								$tpl[$container][2][$prop]=$value;
							}
							else	
								$this->_directive[$prop]=$value;
							$textStart=$matchEnd+1;
						}
						$expectPropEnd=false;
					}
				}
				else if(strpos($str,'<!--')===0)	
				{
					if($expectPropEnd)
						throw new TConfigurationException('template_comments_forbidden');
					if($matchStart>$textStart)
						$tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
					$textStart=$matchEnd+1;
				}
				else
					throw new TConfigurationException('template_matching_unexpected',$match);
			}
			if(!empty($stack))
			{
				$name=array_pop($stack);
				$tag=$name[0]==='@' ? '</prop:'.substr($name,1).'>' : "</com:$name>";
				throw new TConfigurationException('template_closingtag_expected',$tag);
			}
			if($textStart<strlen($input))
				$tpl[$c++]=array($container,substr($input,$textStart));
		}
		catch(Exception $e)
		{
			if(($e instanceof TException) && ($e instanceof TTemplateException))
				throw $e;
			if($matchEnd===0)
				$line=$this->_startingLine+1;
			else
				$line=$this->_startingLine+count(explode("\n",substr($input,0,$matchEnd+1)));
			$this->handleException($e,$line,$input);
		}
		if($this->_directive===null)
			$this->_directive=array();
		$objects=array();
		$parent=null;
		$merged=array();
		foreach($tpl as $id=>$object)
		{
			if(isset($object[2]) || $object[0]!==$parent)
			{
				if($parent!==null)
				{
					if(count($merged[1])===1 && is_string($merged[1][0]))
						$objects[$id-1]=array($merged[0],$merged[1][0]);
					else
						$objects[$id-1]=array($merged[0],new TCompositeLiteral($merged[1]));
				}
				if(isset($object[2]))
				{
					$parent=null;
					$objects[$id]=$object;
				}
				else
				{
					$parent=$object[0];
					$merged=array($parent,array($object[1]));
				}
			}
			else
				$merged[1][]=$object[1];
		}
		if($parent!==null)
		{
			if(count($merged[1])===1 && is_string($merged[1][0]))
				$objects[$id]=array($merged[0],$merged[1][0]);
			else
				$objects[$id]=array($merged[0],new TCompositeLiteral($merged[1]));
		}
		$tpl=$objects;
		return $objects;
	}
	protected function parseAttributes($str,$offset)
	{
		if($str==='')
			return array();
		$pattern='/([\w\.]+)\s*=\s*(\'.*?\'|".*?"|<%.*?%>)/msS';
		$attributes=array();
		$n=preg_match_all($pattern,$str,$matches,PREG_SET_ORDER|PREG_OFFSET_CAPTURE);
		for($i=0;$i<$n;++$i)
		{
			$match=&$matches[$i];
			$name=strtolower($match[1][0]);
			if(isset($attributes[$name]))
				throw new TConfigurationException('template_property_duplicated',$name);
			$value=$match[2][0];
			if(substr($name,-8,8)==='template')
			{
				if($value[0]==='\'' || $value[0]==='"')
					$attributes[$name]=$this->parseTemplateProperty(substr($value,1,strlen($value)-2),$match[2][1]+1);
				else
					$attributes[$name]=$this->parseTemplateProperty($value,$match[2][1]);
			}
			else
			{
				if($value[0]==='\'' || $value[0]==='"')
					$attributes[$name]=$this->parseAttribute(substr($value,1,strlen($value)-2));
				else
					$attributes[$name]=$this->parseAttribute($value);
			}
		}
		return $attributes;
	}
	protected function parseTemplateProperty($content,$offset)
	{
		$line=$this->_startingLine+count(explode("\n",substr($this->_content,0,$offset)))-1;
		return array(self::CONFIG_TEMPLATE,new TTemplate($content,$this->_contextPath,$this->_tplFile,$line,false));
	}
	protected function parseAttribute($value)
	{
		if(($n=preg_match_all('/<%[#=].*?%>/msS',$value,$matches,PREG_OFFSET_CAPTURE))>0)
		{
			$isDataBind=false;
			$textStart=0;
			$expr='';
			for($i=0;$i<$n;++$i)
			{
				$match=$matches[0][$i];
				$token=$match[0];
				$offset=$match[1];
				$length=strlen($token);
				if($token[2]==='#')
					$isDataBind=true;
				if($offset>$textStart)
					$expr.=".'".strtr(substr($value,$textStart,$offset-$textStart),array("'"=>"\\'","\\"=>"\\\\"))."'";
				$expr.='.('.substr($token,3,$length-5).')';
				$textStart=$offset+$length;
			}
			$length=strlen($value);
			if($length>$textStart)
				$expr.=".'".strtr(substr($value,$textStart,$length-$textStart),array("'"=>"\\'","\\"=>"\\\\"))."'";
			if($isDataBind)
				return array(self::CONFIG_DATABIND,ltrim($expr,'.'));
			else
				return array(self::CONFIG_EXPRESSION,ltrim($expr,'.'));
		}
		else if(preg_match('/\\s*(<%~.*?%>|<%\\$.*?%>|<%\\[.*?\\]%>)\\s*/msS',$value,$matches) && $matches[0]===$value)
		{
			$value=$matches[1];
			if($value[2]==='~') 
				return array(self::CONFIG_ASSET,trim(substr($value,3,strlen($value)-5)));
			else if($value[2]==='[')
				return array(self::CONFIG_LOCALIZATION,trim(substr($value,3,strlen($value)-6)));
			else if($value[2]==='$')
				return array(self::CONFIG_PARAMETER,trim(substr($value,3,strlen($value)-5)));
		}
		else
			return $value;
	}
	protected function validateAttributes($type,$attributes)
	{
		Prado::using($type);
		if(($pos=strrpos($type,'.'))!==false)
			$className=substr($type,$pos+1);
		else
			$className=$type;
		$class=new TReflectionClass($className);
		if(is_subclass_of($className,'TControl') || $className==='TControl')
		{
			foreach($attributes as $name=>$att)
			{
				if(($pos=strpos($name,'.'))!==false)
				{
					$subname=substr($name,0,$pos);
					if(!$class->hasMethod('get'.$subname))
						throw new TConfigurationException('template_property_unknown',$type,$subname);
				}
				else if(strncasecmp($name,'on',2)===0)
				{
					if(!$class->hasMethod($name))
						throw new TConfigurationException('template_event_unknown',$type,$name);
					else if(!is_string($att))
						throw new TConfigurationException('template_eventhandler_invalid',$type,$name);
				}
				else
				{
					if(!$class->hasMethod('set'.$name))
					{
						if($class->hasMethod('get'.$name))
							throw new TConfigurationException('template_property_readonly',$type,$name);
						else
							throw new TConfigurationException('template_property_unknown',$type,$name);
					}
					else if(is_array($att) && $att[0]!==self::CONFIG_EXPRESSION)
					{
						if(strcasecmp($name,'id')===0)
							throw new TConfigurationException('template_controlid_invalid',$type);
						else if(strcasecmp($name,'skinid')===0)
							throw new TConfigurationException('template_controlskinid_invalid',$type);
					}
				}
			}
		}
		else if(is_subclass_of($className,'TComponent') || $className==='TComponent')
		{
			foreach($attributes as $name=>$att)
			{
				if(is_array($att) && ($att[0]===self::CONFIG_DATABIND))
					throw new TConfigurationException('template_databind_forbidden',$type,$name);
				if(($pos=strpos($name,'.'))!==false)
				{
					$subname=substr($name,0,$pos);
					if(!$class->hasMethod('get'.$subname))
						throw new TConfigurationException('template_property_unknown',$type,$subname);
				}
				else if(strncasecmp($name,'on',2)===0)
					throw new TConfigurationException('template_event_forbidden',$type,$name);
				else
				{
					if(strcasecmp($name,'id')!==0 && !$class->hasMethod('set'.$name))
					{
						if($class->hasMethod('get'.$name))
							throw new TConfigurationException('template_property_readonly',$type,$name);
						else
							throw new TConfigurationException('template_property_unknown',$type,$name);
					}
				}
			}
		}
		else
			throw new TConfigurationException('template_component_required',$type);
	}
	public function getIncludedFiles()
	{
		return $this->_includedFiles;
	}
	protected function handleException($e,$line,$input=null)
	{
		$srcFile=$this->_tplFile;
		if(($n=count($this->_includedFiles))>0) 
		{
			for($i=$n-1;$i>=0;--$i)
			{
				if($this->_includeAtLine[$i]<=$line)
				{
					if($line<$this->_includeAtLine[$i]+$this->_includeLines[$i])
					{
						$line=$line-$this->_includeAtLine[$i]+1;
						$srcFile=$this->_includedFiles[$i];
						break;
					}
					else
						$line=$line-$this->_includeLines[$i]+1;
				}
			}
		}
		$exception=new TTemplateException('template_format_invalid',$e->getMessage());
		$exception->setLineNumber($line);
		if(!empty($srcFile))
			$exception->setTemplateFile($srcFile);
		else
			$exception->setTemplateSource($input);
		throw $exception;
	}
	protected function preprocess($input)
	{
		if($n=preg_match_all('/<%include(.*?)%>/',$input,$matches,PREG_SET_ORDER|PREG_OFFSET_CAPTURE))
		{
			for($i=0;$i<$n;++$i)
			{
				$filePath=Prado::getPathOfNamespace(trim($matches[$i][1][0]),TTemplateManager::TEMPLATE_FILE_EXT);
				if($filePath!==null && is_file($filePath))
					$this->_includedFiles[]=$filePath;
				else
				{
					$errorLine=count(explode("\n",substr($input,0,$matches[$i][0][1]+1)));
					$this->handleException(new TConfigurationException('template_include_invalid',trim($matches[$i][1][0])),$errorLine,$input);
				}
			}
			$base=0;
			for($i=0;$i<$n;++$i)
			{
				$ext=file_get_contents($this->_includedFiles[$i]);
				$length=strlen($matches[$i][0][0]);
				$offset=$base+$matches[$i][0][1];
				$this->_includeAtLine[$i]=count(explode("\n",substr($input,0,$offset)));
				$this->_includeLines[$i]=count(explode("\n",$ext));
				$input=substr_replace($input,$ext,$offset,$length);
				$base+=strlen($ext)-$length;
			}
		}
		return $input;
	}
}
class TThemeManager extends TModule
{
	const DEFAULT_BASEPATH='themes';
	private $_initialized=false;
	private $_basePath=null;
	private $_baseUrl=null;
	public function init($config)
	{
		$this->_initialized=true;
		$service=$this->getService();
		if($service instanceof TPageService)
			$service->setThemeManager($this);
		else
			throw new TConfigurationException('thememanager_service_unavailable');
	}
	public function getTheme($name)
	{
		$themePath=$this->getBasePath().DIRECTORY_SEPARATOR.$name;
		$themeUrl=rtrim($this->getBaseUrl(),'/').'/'.$name;
		return new TTheme($themePath,$themeUrl);
	}
	public function getAvailableThemes()
	{
		$themes=array();
		$basePath=$this->getBasePath();
		$folder=@opendir($basePath);
		while($file=@readdir($folder))
		{
			if($file!=='.' && $file!=='..' && $file!=='.svn' && is_dir($basePath.DIRECTORY_SEPARATOR.$file))
				$themes[]=$file;
		}
		closedir($folder);
		return $themes;
	}
	public function getBasePath()
	{
		if($this->_basePath===null)
		{
			$this->_basePath=dirname($this->getRequest()->getApplicationFilePath()).DIRECTORY_SEPARATOR.self::DEFAULT_BASEPATH;
			if(($basePath=realpath($this->_basePath))===false || !is_dir($basePath))
				throw new TConfigurationException('thememanager_basepath_invalid2',$this->_basePath);
			$this->_basePath=$basePath;
		}
		return $this->_basePath;
	}
	public function setBasePath($value)
	{
		if($this->_initialized)
			throw new TInvalidOperationException('thememanager_basepath_unchangeable');
		else
		{
			$this->_basePath=Prado::getPathOfNamespace($value);
			if($this->_basePath===null || !is_dir($this->_basePath))
				throw new TInvalidDataValueException('thememanager_basepath_invalid',$value);
		}
	}
	public function getBaseUrl()
	{
		if($this->_baseUrl===null)
		{
			$appPath=dirname($this->getRequest()->getApplicationFilePath());
			$basePath=$this->getBasePath();
			if(strpos($basePath,$appPath)===false)
				throw new TConfigurationException('thememanager_baseurl_required');
			$appUrl=rtrim(dirname($this->getRequest()->getApplicationUrl()),'/\\');
			$this->_baseUrl=$appUrl.strtr(substr($basePath,strlen($appPath)),'\\','/');
		}
		return $this->_baseUrl;
	}
	public function setBaseUrl($value)
	{
		$this->_baseUrl=rtrim($value,'/');
	}
}
class TTheme extends TApplicationComponent implements ITheme
{
	const THEME_CACHE_PREFIX='prado:theme:';
	const SKIN_FILE_EXT='.skin';
	private $_themePath;
	private $_themeUrl;
	private $_skins=null;
	private $_name='';
	private $_cssFiles=array();
	private $_jsFiles=array();
	public function __construct($themePath,$themeUrl)
	{
		$this->_themeUrl=$themeUrl;
		$this->_themePath=realpath($themePath);
		$this->_name=basename($themePath);
		$cacheValid=false;
		if(($cache=$this->getApplication()->getCache())!==null)
		{
			$array=$cache->get(self::THEME_CACHE_PREFIX.$themePath);
			if(is_array($array))
			{
				list($skins,$cssFiles,$jsFiles,$timestamp)=$array;
				if($this->getApplication()->getMode()!==TApplicationMode::Performance)
				{
					if(($dir=opendir($themePath))===false)
						throw new TIOException('theme_path_inexistent',$themePath);
					$cacheValid=true;
					while(($file=readdir($dir))!==false)
					{
						if($file==='.' || $file==='..')
							continue;
						else if(basename($file,'.css')!==$file)
							$this->_cssFiles[]=$themeUrl.'/'.$file;
						else if(basename($file,'.js')!==$file)
							$this->_jsFiles[]=$themeUrl.'/'.$file;
						else if(basename($file,self::SKIN_FILE_EXT)!==$file && filemtime($themePath.DIRECTORY_SEPARATOR.$file)>$timestamp)
						{
							$cacheValid=false;
							break;
						}
					}
					closedir($dir);
					if($cacheValid)
						$this->_skins=$skins;
				}
				else
				{
					$cacheValid=true;
					$this->_cssFiles=$cssFiles;
					$this->_jsFiles=$jsFiles;
					$this->_skins=$skins;
				}
			}
		}
		if(!$cacheValid)
		{
			$this->_cssFiles=array();
			$this->_jsFiles=array();
			$this->_skins=array();
			if(($dir=opendir($themePath))===false)
				throw new TIOException('theme_path_inexistent',$themePath);
			while(($file=readdir($dir))!==false)
			{
				if($file==='.' || $file==='..')
					continue;
				else if(basename($file,'.css')!==$file)
					$this->_cssFiles[]=$themeUrl.'/'.$file;
				else if(basename($file,'.js')!==$file)
					$this->_jsFiles[]=$themeUrl.'/'.$file;
				else if(basename($file,self::SKIN_FILE_EXT)!==$file)
				{
					$template=new TTemplate(file_get_contents($themePath.'/'.$file),$themePath,$themePath.'/'.$file);
					foreach($template->getItems() as $skin)
					{
						if(!isset($skin[2]))  
							continue;
						else if($skin[0]!==-1)
							throw new TConfigurationException('theme_control_nested',$skin[1],dirname($themePath));
						$type=$skin[1];
						$id=isset($skin[2]['skinid'])?$skin[2]['skinid']:0;
						unset($skin[2]['skinid']);
						if(isset($this->_skins[$type][$id]))
							throw new TConfigurationException('theme_skinid_duplicated',$type,$id,dirname($themePath));
						$this->_skins[$type][$id]=$skin[2];
					}
				}
			}
			closedir($dir);
			sort($this->_cssFiles);
			sort($this->_jsFiles);
			if($cache!==null)
				$cache->set(self::THEME_CACHE_PREFIX.$themePath,array($this->_skins,$this->_cssFiles,$this->_jsFiles,time()));
		}
	}
	public function getName()
	{
		return $this->_name;
	}
	protected function setName($value)
	{
		$this->_name = $value;
	}
	public function getBaseUrl()
	{
		return $this->_themeUrl;
	}
	protected function setBaseUrl($value)
	{
		$this->_themeUrl=rtrim($value,'/');
	}
	public function getBasePath()
	{
		return $this->_themePath;
	}
	protected function setBasePath($value)
	{
		$this->_themePath=$value;
	}
	public function applySkin($control)
	{
		$type=get_class($control);
		if(($id=$control->getSkinID())==='')
			$id=0;
		if(isset($this->_skins[$type][$id]))
		{
			foreach($this->_skins[$type][$id] as $name=>$value)
			{
				if(is_array($value))
				{
					switch($value[0])
					{
						case TTemplate::CONFIG_EXPRESSION:
							$value=$this->evaluateExpression($value[1]);
							break;
						case TTemplate::CONFIG_ASSET:
							$value=$this->_themeUrl.'/'.ltrim($value[1],'/');
							break;
						case TTemplate::CONFIG_DATABIND:
							$control->bindProperty($name,$value[1]);
							break;
						case TTemplate::CONFIG_PARAMETER:
							$control->setSubProperty($name,$this->getApplication()->getParameters()->itemAt($value[1]));
							break;
						case TTemplate::CONFIG_TEMPLATE:
							$control->setSubProperty($name,$value[1]);
							break;
						case TTemplate::CONFIG_LOCALIZATION:
							$control->setSubProperty($name,Prado::localize($value[1]));
							break;
						default:
							throw new TConfigurationException('theme_tag_unexpected',$name,$value[0]);
							break;
					}
				}
				if(!is_array($value))
				{
					if(strpos($name,'.')===false)	
					{
						if($control->hasProperty($name))
						{
							if($control->canSetProperty($name))
							{
								$setter='set'.$name;
								$control->$setter($value);
							}
							else
								throw new TConfigurationException('theme_property_readonly',$type,$name);
						}
						else
							throw new TConfigurationException('theme_property_undefined',$type,$name);
					}
					else	
						$control->setSubProperty($name,$value);
				}
			}
			return true;
		}
		else
			return false;
	}
	public function getStyleSheetFiles()
	{
		return $this->_cssFiles;
	}
	protected function setStyleSheetFiles($value)
	{
		$this->_cssFiles=$value;
	}
	public function getJavaScriptFiles()
	{
		return $this->_jsFiles;
	}
	protected function setJavaScriptFiles($value)
	{
		$this->_jsFiles=$value;
	}
}
class TPageService extends TService
{
	const CONFIG_FILE='config.xml';
	const DEFAULT_BASEPATH='pages';
	const CONFIG_CACHE_PREFIX='prado:pageservice:';
	const PAGE_FILE_EXT='.page';
	private $_basePath=null;
	private $_basePageClass='TPage';
	private $_defaultPage='Home';
	private $_pagePath=null;
	private $_page=null;
	private $_properties;
	private $_initialized=false;
	private $_themeManager=null;
	private $_templateManager=null;
	public function init($config)
	{
		$pageConfig=$this->loadPageConfig($config);
		$this->initPageContext($pageConfig);
		$this->_initialized=true;
	}
	protected function initPageContext($pageConfig)
	{
		$application=$this->getApplication();
		foreach($pageConfig->getApplicationConfigurations() as $appConfig)
			$application->applyConfiguration($appConfig);
		$this->applyConfiguration($pageConfig);
	}
	protected function applyConfiguration($config)
	{
		$this->_properties=$config->getProperties();
		$this->getApplication()->getAuthorizationRules()->mergeWith($config->getRules());
		$pagePath=$this->getRequestedPagePath();
		foreach($config->getExternalConfigurations() as $filePath=>$params)
		{
			list($configPagePath,$condition)=$params;
			if($condition!==true)
				$condition=$this->evaluateExpression($condition);
			if($condition)
			{
				if(($path=Prado::getPathOfNamespace($filePath,TApplication::CONFIG_FILE_EXT))===null || !is_file($path))
					throw new TConfigurationException('pageservice_includefile_invalid',$filePath);
				$c=new TPageConfiguration($pagePath);
				$c->loadFromFile($path,$configPagePath);
				$this->applyConfiguration($c);
			}
		}
	}
	protected function determineRequestedPagePath()
	{
		$pagePath=$this->getRequest()->getServiceParameter();
		if(empty($pagePath))
			$pagePath=$this->getDefaultPage();
		return $pagePath;
	}
	protected function loadPageConfig($config)
	{
		$application=$this->getApplication();
		$pagePath=$this->getRequestedPagePath();
		if(($cache=$application->getCache())===null)
		{
			$pageConfig=new TPageConfiguration($pagePath);
			if($config!==null)
				$pageConfig->loadPageConfigurationFromXml($config,$application->getBasePath(),'');
			$pageConfig->loadFromFiles($this->getBasePath());
		}
		else
		{
			$configCached=true;
			$currentTimestamp=array();
			$arr=$cache->get(self::CONFIG_CACHE_PREFIX.$this->getID().$pagePath);
			if(is_array($arr))
			{
				list($pageConfig,$timestamps)=$arr;
				if($application->getMode()!==TApplicationMode::Performance)
				{
					foreach($timestamps as $fileName=>$timestamp)
					{
						if($fileName===0) 
						{
							$appConfigFile=$application->getConfigurationFile();
							$currentTimestamp[0]=$appConfigFile===null?0:@filemtime($appConfigFile);
							if($currentTimestamp[0]>$timestamp || ($timestamp>0 && !$currentTimestamp[0]))
								$configCached=false;
						}
						else
						{
							$currentTimestamp[$fileName]=@filemtime($fileName);
							if($currentTimestamp[$fileName]>$timestamp || ($timestamp>0 && !$currentTimestamp[$fileName]))
								$configCached=false;
						}
					}
				}
			}
			else
			{
				$configCached=false;
				$paths=explode('.',$pagePath);
				$configPath=$this->getBasePath();
				foreach($paths as $path)
				{
					$configFile=$configPath.DIRECTORY_SEPARATOR.self::CONFIG_FILE;
					$currentTimestamp[$configFile]=@filemtime($configFile);
					$configPath.=DIRECTORY_SEPARATOR.$path;
				}
				$appConfigFile=$application->getConfigurationFile();
				$currentTimestamp[0]=$appConfigFile===null?0:@filemtime($appConfigFile);
			}
			if(!$configCached)
			{
				$pageConfig=new TPageConfiguration($pagePath);
				if($config!==null)
					$pageConfig->loadPageConfigurationFromXml($config,$application->getBasePath(),'');
				$pageConfig->loadFromFiles($this->getBasePath());
				$cache->set(self::CONFIG_CACHE_PREFIX.$this->getID().$pagePath,array($pageConfig,$currentTimestamp));
			}
		}
		return $pageConfig;
	}
	public function getTemplateManager()
	{
		if(!$this->_templateManager)
		{
			$this->_templateManager=new TTemplateManager;
			$this->_templateManager->init(null);
		}
		return $this->_templateManager;
	}
	public function setTemplateManager(TTemplateManager $value)
	{
		$this->_templateManager=$value;
	}
	public function getThemeManager()
	{
		if(!$this->_themeManager)
		{
			$this->_themeManager=new TThemeManager;
			$this->_themeManager->init(null);
		}
		return $this->_themeManager;
	}
	public function setThemeManager(TThemeManager $value)
	{
		$this->_themeManager=$value;
	}
	public function getRequestedPagePath()
	{
		if($this->_pagePath===null)
		{
			$this->_pagePath=strtr($this->determineRequestedPagePath(),'/\\','..');
			if(empty($this->_pagePath))
				throw new THttpException(404,'pageservice_page_required');
		}
		return $this->_pagePath;
	}
	public function getRequestedPage()
	{
		return $this->_page;
	}
	public function getDefaultPage()
	{
		return $this->_defaultPage;
	}
	public function setDefaultPage($value)
	{
		if($this->_initialized)
			throw new TInvalidOperationException('pageservice_defaultpage_unchangeable');
		else
			$this->_defaultPage=$value;
	}
	public function getDefaultPageUrl()
	{
		return $this->constructUrl($this->getDefaultPage());
	}
	public function getBasePath()
	{
		if($this->_basePath===null)
		{
			$basePath=$this->getApplication()->getBasePath().DIRECTORY_SEPARATOR.self::DEFAULT_BASEPATH;
			if(($this->_basePath=realpath($basePath))===false || !is_dir($this->_basePath))
				throw new TConfigurationException('pageservice_basepath_invalid',$basePath);
		}
		return $this->_basePath;
	}
	public function setBasePath($value)
	{
		if($this->_initialized)
			throw new TInvalidOperationException('pageservice_basepath_unchangeable');
		else if(($path=Prado::getPathOfNamespace($value))===null || !is_dir($path))
			throw new TConfigurationException('pageservice_basepath_invalid',$value);
		$this->_basePath=realpath($path);
	}
	public function setBasePageClass($value)
	{
		$this->_basePageClass=$value;
	}
	public function getBasePageClass()
	{
		return $this->_basePageClass;
	}
	public function run()
	{
		$this->_page=$this->createPage($this->getRequestedPagePath());
		$this->runPage($this->_page,$this->_properties);
	}
	protected function createPage($pagePath)
	{
		$path=$this->getBasePath().DIRECTORY_SEPARATOR.strtr($pagePath,'.',DIRECTORY_SEPARATOR);
		$hasTemplateFile=is_file($path.self::PAGE_FILE_EXT);
		$hasClassFile=is_file($path.Prado::CLASS_FILE_EXT);
		if(!$hasTemplateFile && !$hasClassFile)
			throw new THttpException(404,'pageservice_page_unknown',$pagePath);
		if($hasClassFile)
		{
			$className=basename($path);
			if(!class_exists($className,false))
				include_once($path.Prado::CLASS_FILE_EXT);
		}
		else
		{
			$className=$this->getBasePageClass();
			Prado::using($className);
			if(($pos=strrpos($className,'.'))!==false)
				$className=substr($className,$pos+1);
		}
 		if(!class_exists($className,false) || ($className!=='TPage' && !is_subclass_of($className,'TPage')))
			throw new THttpException(404,'pageservice_page_unknown',$pagePath);
		$page=new $className;
		$page->setPagePath($pagePath);
		if($hasTemplateFile)
			$page->setTemplate($this->getTemplateManager()->getTemplateByFileName($path.self::PAGE_FILE_EXT));
		return $page;
	}
	protected function runPage($page,$properties)
	{
		foreach($properties as $name=>$value)
			$page->setSubProperty($name,$value);
		$page->run($this->getResponse()->createHtmlWriter());
	}
	public function constructUrl($pagePath,$getParams=null,$encodeAmpersand=true,$encodeGetItems=true)
	{
		return $this->getRequest()->constructUrl($this->getID(),$pagePath,$getParams,$encodeAmpersand,$encodeGetItems);
	}
}
class TPageConfiguration extends TComponent
{
	private $_appConfigs=array();
	private $_properties=array();
	private $_rules=array();
	private $_includes=array();
	private $_pagePath='';
	public function __construct($pagePath)
	{
		$this->_pagePath=$pagePath;
	}
	public function getExternalConfigurations()
	{
		return $this->_includes;
	}
	public function getProperties()
	{
		return $this->_properties;
	}
	public function getRules()
	{
		return $this->_rules;
	}
	public function getApplicationConfigurations()
	{
		return $this->_appConfigs;
	}
	public function loadFromFiles($basePath)
	{
		$paths=explode('.',$this->_pagePath);
		$page=array_pop($paths);
		$path=$basePath;
		$configPagePath='';
		foreach($paths as $p)
		{
			$this->loadFromFile($path.DIRECTORY_SEPARATOR.TPageService::CONFIG_FILE,$configPagePath);
			$path.=DIRECTORY_SEPARATOR.$p;
			if($configPagePath==='')
				$configPagePath=$p;
			else
				$configPagePath.='.'.$p;
		}
		$this->loadFromFile($path.DIRECTORY_SEPARATOR.TPageService::CONFIG_FILE,$configPagePath);
		$this->_rules=new TAuthorizationRuleCollection($this->_rules);
	}
	public function loadFromFile($fname,$configPagePath)
	{
		if(empty($fname) || !is_file($fname))
			return;
		$dom=new TXmlDocument;
		if($dom->loadFromFile($fname))
			$this->loadFromXml($dom,dirname($fname),$configPagePath);
		else
			throw new TConfigurationException('pageserviceconf_file_invalid',$fname);
	}
	public function loadFromXml($dom,$configPath,$configPagePath)
	{
		$this->loadApplicationConfigurationFromXml($dom,$configPath);
		$this->loadPageConfigurationFromXml($dom,$configPath,$configPagePath);
	}
	public function loadApplicationConfigurationFromXml($dom,$configPath)
	{
		$appConfig=new TApplicationConfiguration;
		$appConfig->loadFromXml($dom,$configPath);
		$this->_appConfigs[]=$appConfig;
	}
	public function loadPageConfigurationFromXml($dom,$configPath,$configPagePath)
	{
		if(($authorizationNode=$dom->getElementByTagName('authorization'))!==null)
		{
			$rules=array();
			foreach($authorizationNode->getElements() as $node)
			{
				$patterns=$node->getAttribute('pages');
				$ruleApplies=false;
				if(empty($patterns) || trim($patterns)==='*') 
					$ruleApplies=true;
				else
				{
					foreach(explode(',',$patterns) as $pattern)
					{
						if(($pattern=trim($pattern))!=='')
						{
							if($configPagePath!=='')  
								$pattern=$configPagePath.'.'.$pattern;
							if(strcasecmp($pattern,$this->_pagePath)===0)
							{
								$ruleApplies=true;
								break;
							}
							if($pattern[strlen($pattern)-1]==='*') 
							{
								if(strncasecmp($this->_pagePath,$pattern,strlen($pattern)-1)===0)
								{
									$ruleApplies=true;
									break;
								}
							}
						}
					}
				}
				if($ruleApplies)
					$rules[]=new TAuthorizationRule($node->getTagName(),$node->getAttribute('users'),$node->getAttribute('roles'),$node->getAttribute('verb'),$node->getAttribute('ips'));
			}
			$this->_rules=array_merge($rules,$this->_rules);
		}
		if(($pagesNode=$dom->getElementByTagName('pages'))!==null)
		{
			$this->_properties=array_merge($this->_properties,$pagesNode->getAttributes()->toArray());
			foreach($pagesNode->getElementsByTagName('page') as $node)
			{
				$properties=$node->getAttributes();
				$id=$properties->remove('id');
				if(empty($id))
					throw new TConfigurationException('pageserviceconf_page_invalid',$configPath);
				$matching=false;
				$id=($configPagePath==='')?$id:$configPagePath.'.'.$id;
				if(strcasecmp($id,$this->_pagePath)===0)
					$matching=true;
				else if($id[strlen($id)-1]==='*') 
					$matching=strncasecmp($this->_pagePath,$id,strlen($id)-1)===0;
				if($matching)
					$this->_properties=array_merge($this->_properties,$properties->toArray());
			}
		}
		foreach($dom->getElementsByTagName('include') as $node)
		{
			if(($when=$node->getAttribute('when'))===null)
				$when=true;
			if(($filePath=$node->getAttribute('file'))===null)
				throw new TConfigurationException('pageserviceconf_includefile_required');
			if(isset($this->_includes[$filePath]))
				$this->_includes[$filePath]=array($configPagePath,'('.$this->_includes[$filePath][1].') || ('.$when.')');
			else
				$this->_includes[$filePath]=array($configPagePath,$when);
		}
	}
}
class TAssetManager extends TModule
{
	const DEFAULT_BASEPATH='assets';
	private $_basePath=null;
	private $_baseUrl=null;
	private $_checkTimestamp=false;
	private $_application;
	private $_published=array();
	private $_initialized=false;
	public function init($config)
	{
		$application=$this->getApplication();
		if($this->_basePath===null)
			$this->_basePath=dirname($application->getRequest()->getApplicationFilePath()).DIRECTORY_SEPARATOR.self::DEFAULT_BASEPATH;
		if(!is_writable($this->_basePath) || !is_dir($this->_basePath))
			throw new TConfigurationException('assetmanager_basepath_invalid',$this->_basePath);
		if($this->_baseUrl===null)
			$this->_baseUrl=rtrim(dirname($application->getRequest()->getApplicationUrl()),'/\\').'/'.self::DEFAULT_BASEPATH;
		$application->setAssetManager($this);
		$this->_initialized=true;
	}
	public function getBasePath()
	{
		return $this->_basePath;
	}
	public function setBasePath($value)
	{
		if($this->_initialized)
			throw new TInvalidOperationException('assetmanager_basepath_unchangeable');
		else
		{
			$this->_basePath=Prado::getPathOfNamespace($value);
			if($this->_basePath===null || !is_dir($this->_basePath) || !is_writable($this->_basePath))
				throw new TInvalidDataValueException('assetmanage_basepath_invalid',$value);
		}
	}
	public function getBaseUrl()
	{
		return $this->_baseUrl;
	}
	public function setBaseUrl($value)
	{
		if($this->_initialized)
			throw new TInvalidOperationException('assetmanager_baseurl_unchangeable');
		else
			$this->_baseUrl=rtrim($value,'/');
	}
	public function publishFilePath($path,$checkTimestamp=false)
	{
		if(isset($this->_published[$path]))
			return $this->_published[$path];
		else if(empty($path) || ($fullpath=realpath($path))===false)
			throw new TInvalidDataValueException('assetmanager_filepath_invalid',$path);
		else if(is_file($fullpath))
		{
			$dir=$this->hash(dirname($fullpath));
			$fileName=basename($fullpath);
			$dst=$this->_basePath.DIRECTORY_SEPARATOR.$dir;
			if(!is_file($dst.DIRECTORY_SEPARATOR.$fileName) || $checkTimestamp || $this->getApplication()->getMode()!==TApplicationMode::Performance)
				$this->copyFile($fullpath,$dst);
			return $this->_published[$path]=$this->_baseUrl.'/'.$dir.'/'.$fileName;
		}
		else
		{
			$dir=$this->hash($fullpath);
			if(!is_dir($this->_basePath.DIRECTORY_SEPARATOR.$dir) || $checkTimestamp || $this->getApplication()->getMode()!==TApplicationMode::Performance)
			{
				$this->copyDirectory($fullpath,$this->_basePath.DIRECTORY_SEPARATOR.$dir);
			}
			return $this->_published[$path]=$this->_baseUrl.'/'.$dir;
		}
	}
	public function getPublishedPath($path)
	{
		$path=realpath($path);
		if(is_file($path))
			return $this->_basePath.DIRECTORY_SEPARATOR.$this->hash(dirname($path)).DIRECTORY_SEPARATOR.basename($path);
		else
			return $this->_basePath.DIRECTORY_SEPARATOR.$this->hash($path);
	}
	public function getPublishedUrl($path)
	{
		$path=realpath($path);
		if(is_file($path))
			return $this->_baseUrl.'/'.$this->hash(dirname($path)).'/'.basename($path);
		else
			return $this->_baseUrl.'/'.$this->hash($path);
	}
	protected function hash($dir)
	{
		return sprintf('%x',crc32($dir.Prado::getVersion()));
	}
	protected function copyFile($src,$dst)
	{
		if(!is_dir($dst))
		{
			@mkdir($dst);
			@chmod($dst, PRADO_CHMOD);
		}
		$dstFile=$dst.DIRECTORY_SEPARATOR.basename($src);
		if(@filemtime($dstFile)<@filemtime($src))
		{
			@copy($src,$dstFile);
		}
	}
	public function copyDirectory($src,$dst)
	{
		if(!is_dir($dst))
		{
			@mkdir($dst);
			@chmod($dst, PRADO_CHMOD);
		}
		if($folder=@opendir($src))
		{
			while($file=@readdir($folder))
			{
				if($file==='.' || $file==='..' || $file==='.svn')
					continue;
				else if(is_file($src.DIRECTORY_SEPARATOR.$file))
				{
					if(@filemtime($dst.DIRECTORY_SEPARATOR.$file)<@filemtime($src.DIRECTORY_SEPARATOR.$file))
						@copy($src.DIRECTORY_SEPARATOR.$file,$dst.DIRECTORY_SEPARATOR.$file);
				}
				else
					$this->copyDirectory($src.DIRECTORY_SEPARATOR.$file,$dst.DIRECTORY_SEPARATOR.$file);
			}
			closedir($folder);
		} else {
			throw new TInvalidDataValueException('assetmanager_source_directory_invalid', $src);
		}
	}
	public function publishTarFile($tarfile, $md5sum, $checkTimestamp=false)
	{
		if(isset($this->_published[$md5sum]))
			return $this->_published[$md5sum];
		else if(($fullpath=realpath($md5sum))===false || !is_file($fullpath))
			throw new TInvalidDataValueException('assetmanager_tarchecksum_invalid',$md5sum);
		else
		{
			$dir=$this->hash(dirname($fullpath));
			$fileName=basename($fullpath);
			$dst=$this->_basePath.DIRECTORY_SEPARATOR.$dir;
			if(!is_file($dst.DIRECTORY_SEPARATOR.$fileName) || $checkTimestamp || $this->getApplication()->getMode()!==TApplicationMode::Performance)
			{
				if(@filemtime($dst.DIRECTORY_SEPARATOR.$fileName)<@filemtime($fullpath))
				{
					$this->copyFile($fullpath,$dst);
					$this->deployTarFile($tarfile,$dst);
				}
			}
			return $this->_published[$md5sum]=$this->_baseUrl.'/'.$dir;
		}
	}
	protected function deployTarFile($path,$destination)
	{
		if(($fullpath=realpath($path))===false || !is_file($fullpath))
			throw new TIOException('assetmanager_tarfile_invalid',$path);
		else
		{
			Prado::using('System.IO.TTarFileExtractor');
			$tar = new TTarFileExtractor($fullpath);
			return $tar->extract($destination);
		}
	}
}
class TGlobalization extends TModule
{
	private $_defaultCharset = 'UTF-8';
	private $_defaultCulture = 'en';
	private $_charset=null;
	private $_culture=null;
	private $_translation;
	public function init($xml)
	{
		if($this->_charset===null)
			$this->_charset=$this->getDefaultCharset();
		if($this->_culture===null)
			$this->_culture=$this->getDefaultCulture();
		if($xml!==null)
		{
			$translation = $xml->getElementByTagName('translation');
			if($translation)
				$this->setTranslationConfiguration($translation->getAttributes());
		}
		$this->getApplication()->setGlobalization($this);
	}
	public function getDefaultCulture()
	{
		return $this->_defaultCulture;
	}
	public function setDefaultCulture($culture)
	{
		$this->_defaultCulture = str_replace('-','_',$culture);
	}
	public function getDefaultCharset()
	{
		return $this->_defaultCharset;
	}
	public function setDefaultCharset($charset)
	{
		$this->_defaultCharset = $charset;
	}
	public function getCulture()
	{
		return $this->_culture;
	}
	public function setCulture($culture)
	{
		$this->_culture = str_replace('-','_',$culture);
	}
	public function getCharset()
	{
		return $this->_charset;
	}
	public function setCharset($charset)
	{
		$this->_charset = $charset;
	}
	public function getTranslationConfiguration()
	{
		return $this->_translation;
	}
	protected function setTranslationConfiguration(TMap $config)
	{
		if($config['type'] == 'XLIFF' || $config['type'] == 'gettext')
		{
			if($config['source'])
			{
				$config['source'] = Prado::getPathOfNamespace($config['source']);
				if(!is_dir($config['source']))
				{
					if(@mkdir($config['source'])===false)
					throw new TConfigurationException('globalization_source_path_failed',
						$config['source']);
					chmod($config['source'], PRADO_CHMOD); 
				}
			}
			else
			{
				throw new TConfigurationException("invalid source dir '{$config['source']}'");
			}
		}
		if($config['cache'])
		{
			$config['cache'] = $this->getApplication()->getRunTimePath().'/i18n';
			if(!is_dir($config['cache']))
			{
				if(@mkdir($config['cache'])===false)
					throw new TConfigurationException('globalization_cache_path_failed',
						$config['cache']);
				chmod($config['cache'], PRADO_CHMOD); 
			}
		}
		$this->_translation = $config;
	}
	public function getTranslationCatalogue()
	{
		return $this->_translation['catalogue'];
	}
	public function setTranslationCatalogue($value)
	{
		$this->_translation['catalogue'] = $value;
	}
	public function getCultureVariants($culture=null)
	{
		if(is_null($culture)) $culture = $this->getCulture();
		$variants = explode('_', $culture);
		$result = array();
		for(; count($variants) > 0; array_pop($variants))
			$result[] = implode('_', $variants);
		return $result;
	}
	public function getLocalizedResource($file,$culture=null)
	{
		$files = array();
		$variants = $this->getCultureVariants($culture);
		$path = pathinfo($file);
		foreach($variants as $variant)
			$files[] = $path['dirname'].DIRECTORY_SEPARATOR.$variant.DIRECTORY_SEPARATOR.$path['basename'];
		$filename = substr($path['basename'],0,strrpos($path['basename'],'.'));
		foreach($variants as $variant)
			$files[] = $path['dirname'].DIRECTORY_SEPARATOR.$filename.'.'.$variant.'.'.$path['extension'];
		$files[] = $file;
		return $files;
	}
}
class TApplication extends TComponent
{
	const STATE_OFF='Off';
	const STATE_DEBUG='Debug';
	const STATE_NORMAL='Normal';
	const STATE_PERFORMANCE='Performance';
	const PAGE_SERVICE_ID='page';
	const CONFIG_FILE='application.xml';
	const CONFIG_FILE_EXT='.xml';
	const RUNTIME_PATH='runtime';
	const CONFIGCACHE_FILE='config.cache';
	const GLOBAL_FILE='global.cache';
	private static $_steps=array(
		'onBeginRequest',
		'onLoadState',
		'onLoadStateComplete',
		'onAuthentication',
		'onAuthenticationComplete',
		'onAuthorization',
		'onAuthorizationComplete',
		'onPreRunService',
		'runService',
		'onSaveState',
		'onSaveStateComplete',
		'onPreFlushOutput',
		'flushOutput'
	);
	private $_id;
	private $_uniqueID;
	private $_requestCompleted=false;
	private $_step;
	private $_services;
	private $_service;
	private $_modules=array();
	private $_parameters;
	private $_configFile;
	private $_basePath;
	private $_runtimePath;
	private $_stateChanged=false;
	private $_globals=array();
	private $_cacheFile;
	private $_errorHandler;
	private $_request;
	private $_response;
	private $_session;
	private $_cache;
	private $_statePersister;
	private $_user;
	private $_globalization;
	private $_security;
	private $_assetManager;
	private $_authRules;
	private $_mode=TApplicationMode::Debug;
	public function __construct($basePath='protected',$cacheConfig=true)
	{
				Prado::setApplication($this);
		$this->resolvePaths($basePath);
		if($cacheConfig)
			$this->_cacheFile=$this->_runtimePath.DIRECTORY_SEPARATOR.self::CONFIGCACHE_FILE;
				$this->_uniqueID=md5($this->_runtimePath);
		$this->_parameters=new TMap;
		$this->_services=array(self::PAGE_SERVICE_ID=>array('TPageService',array(),null));
		Prado::setPathOfAlias('Application',$this->_basePath);
	}
	protected function resolvePaths($basePath)
	{
				if(empty($basePath) || ($basePath=realpath($basePath))===false)
			throw new TConfigurationException('application_basepath_invalid',$basePath);
		if(is_file($basePath.DIRECTORY_SEPARATOR.self::CONFIG_FILE))
			$configFile=$basePath.DIRECTORY_SEPARATOR.self::CONFIG_FILE;
		else if(is_file($basePath))
		{
			$configFile=$basePath;
			$basePath=dirname($configFile);
		}
		else
			$configFile=null;
				$runtimePath=$basePath.DIRECTORY_SEPARATOR.self::RUNTIME_PATH;
		if(is_writable($runtimePath))
		{
			if($configFile!==null)
			{
				$runtimePath.=DIRECTORY_SEPARATOR.basename($configFile).'-'.Prado::getVersion();
				if(!is_dir($runtimePath))
				{
					if(@mkdir($runtimePath)===false)
						throw new TConfigurationException('application_runtimepath_failed',$runtimePath);
					@chmod($runtimePath, PRADO_CHMOD); 				}
				$this->setConfigurationFile($configFile);
			}
			$this->setBasePath($basePath);
			$this->setRuntimePath($runtimePath);
		}
		else
			throw new TConfigurationException('application_runtimepath_invalid',$runtimePath);
	}
	public function run()
	{
		try
		{
			$this->initApplication();
			$n=count(self::$_steps);
			$this->_step=0;
			$this->_requestCompleted=false;
			while($this->_step<$n)
			{
				if($this->_mode===self::STATE_OFF)
					throw new THttpException(503,'application_unavailable');
				if($this->_requestCompleted)
					break;
				$method=self::$_steps[$this->_step];
				$this->$method();
				$this->_step++;
			}
		}
		catch(Exception $e)
		{
			$this->onError($e);
		}
		$this->onEndRequest();
	}
	public function completeRequest()
	{
		$this->_requestCompleted=true;
	}
	public function getRequestCompleted()
	{
		return $this->_requestCompleted;
	}
	public function getGlobalState($key,$defaultValue=null)
	{
		return isset($this->_globals[$key])?$this->_globals[$key]:$defaultValue;
	}
	public function setGlobalState($key,$value,$defaultValue=null)
	{
		$this->_stateChanged=true;
		if($value===$defaultValue)
			unset($this->_globals[$key]);
		else
			$this->_globals[$key]=$value;
	}
	public function clearGlobalState($key)
	{
		$this->_stateChanged=true;
		unset($this->_globals[$key]);
	}
	protected function loadGlobals()
	{
		$this->_globals=$this->getApplicationStatePersister()->load();
	}
	protected function saveGlobals()
	{
		if($this->_stateChanged)
		{
			$this->_stateChanged=false;
			$this->getApplicationStatePersister()->save($this->_globals);
		}
	}
	public function getID()
	{
		return $this->_id;
	}
	public function setID($value)
	{
		$this->_id=$value;
	}
	public function getUniqueID()
	{
		return $this->_uniqueID;
	}
	public function getMode()
	{
		return $this->_mode;
	}
	public function setMode($value)
	{
		$this->_mode=TPropertyValue::ensureEnum($value,'TApplicationMode');
	}
	public function getBasePath()
	{
		return $this->_basePath;
	}
	public function setBasePath($value)
	{
		$this->_basePath=$value;
	}
	public function getConfigurationFile()
	{
		return $this->_configFile;
	}
	public function setConfigurationFile($value)
	{
		$this->_configFile=$value;
	}
	public function getRuntimePath()
	{
		return $this->_runtimePath;
	}
	public function setRuntimePath($value)
	{
		$this->_runtimePath=$value;
	}
	public function getService()
	{
		return $this->_service;
	}
	public function setService($value)
	{
		$this->_service=$value;
	}
	public function setModule($id,IModule $module)
	{
		if(isset($this->_modules[$id]))
			throw new TConfigurationException('application_moduleid_duplicated',$id);
		else
			$this->_modules[$id]=$module;
	}
	public function getModule($id)
	{
		return isset($this->_modules[$id])?$this->_modules[$id]:null;
	}
	public function getModules()
	{
		return $this->_modules;
	}
	public function getParameters()
	{
		return $this->_parameters;
	}
	public function getRequest()
	{
		if(!$this->_request)
		{
			$this->_request=new THttpRequest;
			$this->_request->init(null);
		}
		return $this->_request;
	}
	public function setRequest(THttpRequest $request)
	{
		$this->_request=$request;
	}
	public function getResponse()
	{
		if(!$this->_response)
		{
			$this->_response=new THttpResponse;
			$this->_response->init(null);
		}
		return $this->_response;
	}
	public function setResponse(THttpResponse $response)
	{
		$this->_response=$response;
	}
	public function getSession()
	{
		if(!$this->_session)
		{
			$this->_session=new THttpSession;
			$this->_session->init(null);
		}
		return $this->_session;
	}
	public function setSession(THttpSession $session)
	{
		$this->_session=$session;
	}
	public function getErrorHandler()
	{
		if(!$this->_errorHandler)
		{
			$this->_errorHandler=new TErrorHandler;
			$this->_errorHandler->init(null);
		}
		return $this->_errorHandler;
	}
	public function setErrorHandler(TErrorHandler $handler)
	{
		$this->_errorHandler=$handler;
	}
	public function getSecurityManager()
	{
		if(!$this->_security)
		{
			$this->_security=new TSecurityManager;
			$this->_security->init(null);
		}
		return $this->_security;
	}
	public function setSecurityManager(TSecurityManager $sm)
	{
		$this->_security=$sm;
	}
	public function getAssetManager()
	{
		if(!$this->_assetManager)
		{
			$this->_assetManager=new TAssetManager;
			$this->_assetManager->init(null);
		}
		return $this->_assetManager;
	}
	public function setAssetManager(TAssetManager $value)
	{
		$this->_assetManager=$value;
	}
	public function getApplicationStatePersister()
	{
		if(!$this->_statePersister)
		{
			$this->_statePersister=new TApplicationStatePersister;
			$this->_statePersister->init(null);
		}
		return $this->_statePersister;
	}
	public function setApplicationStatePersister(IStatePersister $persister)
	{
		$this->_statePersister=$persister;
	}
	public function getCache()
	{
		return $this->_cache;
	}
	public function setCache(ICache $cache)
	{
		$this->_cache=$cache;
	}
	public function getUser()
	{
		return $this->_user;
	}
	public function setUser(IUser $user)
	{
		$this->_user=$user;
	}
	public function getGlobalization($createIfNotExists=true)
	{
		if($this->_globalization===null && $createIfNotExists)
			$this->_globalization=new TGlobalization;
		return $this->_globalization;
	}
	public function setGlobalization(TGlobalization $glob)
	{
		$this->_globalization=$glob;
	}
	public function getAuthorizationRules()
	{
		if($this->_authRules===null)
			$this->_authRules=new TAuthorizationRuleCollection;
		return $this->_authRules;
	}
	public function applyConfiguration($config,$withinService=false)
	{
		if($config->getIsEmpty())
			return;
				foreach($config->getAliases() as $alias=>$path)
			Prado::setPathOfAlias($alias,$path);
		foreach($config->getUsings() as $using)
			Prado::using($using);
				if(!$withinService)
		{
			foreach($config->getProperties() as $name=>$value)
				$this->setSubProperty($name,$value);
		}
				foreach($config->getParameters() as $id=>$parameter)
		{
			if(is_array($parameter))
			{
				$component=Prado::createComponent($parameter[0]);
				foreach($parameter[1] as $name=>$value)
					$component->setSubProperty($name,$value);
				$this->_parameters->add($id,$component);
			}
			else
				$this->_parameters->add($id,$parameter);
		}
				$modules=array();
		foreach($config->getModules() as $id=>$moduleConfig)
		{
			list($moduleClass, $initProperties, $configElement)=$moduleConfig;
			$module=Prado::createComponent($moduleClass);
			if(!is_string($id))
			{
				$id='_module'.count($this->_modules);
				$initProperties['id']=$id;
			}
			$this->setModule($id,$module);
			foreach($initProperties as $name=>$value)
				$module->setSubProperty($name,$value);
			$modules[]=array($module,$configElement);
		}
		foreach($modules as $module)
			$module[0]->init($module[1]);
				foreach($config->getServices() as $serviceID=>$serviceConfig)
			$this->_services[$serviceID]=$serviceConfig;
				foreach($config->getExternalConfigurations() as $filePath=>$condition)
		{
			if($condition!==true)
				$condition=$this->evaluateExpression($condition);
			if($condition)
			{
				if(($path=Prado::getPathOfNamespace($filePath,self::CONFIG_FILE_EXT))===null || !is_file($path))
					throw new TConfigurationException('application_includefile_invalid',$filePath);
				$c=new TApplicationConfiguration;
				$c->loadFromFile($path);
				$this->applyConfiguration($c,$withinService);
			}
		}
	}
	protected function initApplication()
	{
		if($this->_configFile!==null)
		{
			if($this->_cacheFile===null || @filemtime($this->_cacheFile)<filemtime($this->_configFile))
			{
				$config=new TApplicationConfiguration;
				$config->loadFromFile($this->_configFile);
				if($this->_cacheFile!==null)
					file_put_contents($this->_cacheFile,Prado::serialize($config),LOCK_EX);
			}
			else
				$config=Prado::unserialize(file_get_contents($this->_cacheFile));
			$this->applyConfiguration($config,false);
		}
		if(($serviceID=$this->getRequest()->resolveRequest(array_keys($this->_services)))===null)
			$serviceID=self::PAGE_SERVICE_ID;
		$this->startService($serviceID);
	}
	public function startService($serviceID)
	{
		if(isset($this->_services[$serviceID]))
		{
			list($serviceClass,$initProperties,$configElement)=$this->_services[$serviceID];
			$service=Prado::createComponent($serviceClass);
			if(!($service instanceof IService))
				throw new THttpException(500,'application_service_invalid',$serviceClass);
			if(!$service->getEnabled())
				throw new THttpException(500,'application_service_unavailable',$serviceClass);
			$service->setID($serviceID);
			$this->setService($service);
			foreach($initProperties as $name=>$value)
				$service->setSubProperty($name,$value);
			if($configElement!==null)
			{
				$config=new TApplicationConfiguration;
				$config->loadFromXml($configElement,$this->getBasePath());
				$this->applyConfiguration($config,true);
			}
			$service->init($configElement);
		}
		else
			throw new THttpException(500,'application_service_unknown',$serviceID);
	}
	public function onError($param)
	{
		Prado::log($param->getMessage(),TLogger::ERROR,'System.TApplication');
		$this->raiseEvent('OnError',$this,$param);
		$this->getErrorHandler()->handleError($this,$param);
	}
	public function onBeginRequest()
	{
		$this->raiseEvent('OnBeginRequest',$this,null);
	}
	public function onAuthentication()
	{
		$this->raiseEvent('OnAuthentication',$this,null);
	}
	public function onAuthenticationComplete()
	{
		$this->raiseEvent('OnAuthenticationComplete',$this,null);
	}
	public function onAuthorization()
	{
		$this->raiseEvent('OnAuthorization',$this,null);
	}
	public function onAuthorizationComplete()
	{
		$this->raiseEvent('OnAuthorizationComplete',$this,null);
	}
	public function onLoadState()
	{
		$this->loadGlobals();
		$this->raiseEvent('OnLoadState',$this,null);
	}
	public function onLoadStateComplete()
	{
		$this->raiseEvent('OnLoadStateComplete',$this,null);
	}
	public function onPreRunService()
	{
		$this->raiseEvent('OnPreRunService',$this,null);
	}
	public function runService()
	{
		if($this->_service)
			$this->_service->run();
	}
	public function onSaveState()
	{
		$this->raiseEvent('OnSaveState',$this,null);
		$this->saveGlobals();
	}
	public function onSaveStateComplete()
	{
		$this->raiseEvent('OnSaveStateComplete',$this,null);
	}
	public function onPreFlushOutput()
	{
		$this->raiseEvent('OnPreFlushOutput',$this,null);
	}
	public function flushOutput()
	{
		$this->getResponse()->flush();
	}
	public function onEndRequest()
	{
		$this->saveGlobals();  		$this->raiseEvent('OnEndRequest',$this,null);
	}
}
class TApplicationMode extends TEnumerable
{
	const Off='Off';
	const Debug='Debug';
	const Normal='Normal';
	const Performance='Performance';
}
class TApplicationConfiguration extends TComponent
{
	private $_properties=array();
	private $_usings=array();
	private $_aliases=array();
	private $_modules=array();
	private $_services=array();
	private $_parameters=array();
	private $_includes=array();
	private $_empty=true;
	public function loadFromFile($fname)
	{
		$dom=new TXmlDocument;
		$dom->loadFromFile($fname);
		$this->loadFromXml($dom,dirname($fname));
	}
	public function getIsEmpty()
	{
		return $this->_empty;
	}
	public function loadFromXml($dom,$configPath)
	{
				foreach($dom->getAttributes() as $name=>$value)
		{
			$this->_properties[$name]=$value;
			$this->_empty=false;
		}
		foreach($dom->getElements() as $element)
		{
			switch($element->getTagName())
			{
				case 'paths':
					$this->loadPathsXml($element,$configPath);
					break;
				case 'modules':
					$this->loadModulesXml($element,$configPath);
					break;
				case 'services':
					$this->loadServicesXml($element,$configPath);
					break;
				case 'parameters':
					$this->loadParametersXml($element,$configPath);
					break;
				case 'include':
					$this->loadExternalXml($element,$configPath);
					break;
				default:
										break;
			}
		}
	}
	protected function loadPathsXml($pathsNode,$configPath)
	{
		foreach($pathsNode->getElements() as $element)
		{
			switch($element->getTagName())
			{
				case 'alias':
				{
					if(($id=$element->getAttribute('id'))!==null && ($path=$element->getAttribute('path'))!==null)
					{
						$path=str_replace('\\','/',$path);
						if(preg_match('/^\\/|.:\\/|.:\\\\/',$path))								$p=realpath($path);
						else
							$p=realpath($configPath.DIRECTORY_SEPARATOR.$path);
						if($p===false || !is_dir($p))
							throw new TConfigurationException('appconfig_aliaspath_invalid',$id,$path);
						if(isset($this->_aliases[$id]))
							throw new TConfigurationException('appconfig_alias_redefined',$id);
						$this->_aliases[$id]=$p;
					}
					else
						throw new TConfigurationException('appconfig_alias_invalid');
					$this->_empty=false;
					break;
				}
				case 'using':
				{
					if(($namespace=$element->getAttribute('namespace'))!==null)
						$this->_usings[]=$namespace;
					else
						throw new TConfigurationException('appconfig_using_invalid');
					$this->_empty=false;
					break;
				}
				default:
					throw new TConfigurationException('appconfig_paths_invalid',$tagName);
			}
		}
	}
	protected function loadModulesXml($modulesNode,$configPath)
	{
		foreach($modulesNode->getElements() as $element)
		{
			if($element->getTagName()==='module')
			{
				$properties=$element->getAttributes();
				$id=$properties->itemAt('id');
				$type=$properties->remove('class');
				if($type===null)
					throw new TConfigurationException('appconfig_moduletype_required',$id);
				$element->setParent(null);
				if($id===null)
					$this->_modules[]=array($type,$properties->toArray(),$element);
				else
					$this->_modules[$id]=array($type,$properties->toArray(),$element);
				$this->_empty=false;
			}
			else
				throw new TConfigurationException('appconfig_modules_invalid',$element->getTagName());
		}
	}
	protected function loadServicesXml($servicesNode,$configPath)
	{
		foreach($servicesNode->getElements() as $element)
		{
			if($element->getTagName()==='service')
			{
				$properties=$element->getAttributes();
				if(($id=$properties->itemAt('id'))===null)
					throw new TConfigurationException('appconfig_serviceid_required');
				if(($type=$properties->remove('class'))===null)
					throw new TConfigurationException('appconfig_servicetype_required',$id);
				$element->setParent(null);
				$this->_services[$id]=array($type,$properties->toArray(),$element);
				$this->_empty=false;
			}
			else
				throw new TConfigurationException('appconfig_services_invalid',$element->getTagName());
		}
	}
	protected function loadParametersXml($parametersNode,$configPath)
	{
		foreach($parametersNode->getElements() as $element)
		{
			if($element->getTagName()==='parameter')
			{
				$properties=$element->getAttributes();
				if(($id=$properties->remove('id'))===null)
					throw new TConfigurationException('appconfig_parameterid_required');
				if(($type=$properties->remove('class'))===null)
				{
					if(($value=$properties->remove('value'))===null)
						$this->_parameters[$id]=$element;
					else
						$this->_parameters[$id]=$value;
				}
				else
					$this->_parameters[$id]=array($type,$properties->toArray());
				$this->_empty=false;
			}
			else
				throw new TConfigurationException('appconfig_parameters_invalid',$element->getTagName());
		}
	}
	protected function loadExternalXml($includeNode,$configPath)
	{
		if(($when=$includeNode->getAttribute('when'))===null)
			$when=true;
		if(($filePath=$includeNode->getAttribute('file'))===null)
			throw new TConfigurationException('appconfig_includefile_required');
		if(isset($this->_includes[$filePath]))
			$this->_includes[$filePath]='('.$this->_includes[$filePath].') || ('.$when.')';
		else
			$this->_includes[$filePath]=$when;
		$this->_empty=false;
	}
	public function getProperties()
	{
		return $this->_properties;
	}
	public function getAliases()
	{
		return $this->_aliases;
	}
	public function getUsings()
	{
		return $this->_usings;
	}
	public function getModules()
	{
		return $this->_modules;
	}
	public function getServices()
	{
		return $this->_services;
	}
	public function getParameters()
	{
		return $this->_parameters;
	}
	public function getExternalConfigurations()
	{
		return $this->_includes;
	}
}
class TApplicationStatePersister extends TModule implements IStatePersister
{
	const CACHE_NAME='prado:appstate';
	public function init($config)
	{
		$this->getApplication()->setApplicationStatePersister($this);
	}
	protected function getStateFilePath()
	{
		return $this->getApplication()->getRuntimePath().'/global.cache';
	}
	public function load()
	{
		if(($cache=$this->getApplication()->getCache())!==null && ($value=$cache->get(self::CACHE_NAME))!==false)
			return unserialize($value);
		else
		{
			if(($content=@file_get_contents($this->getStateFilePath()))!==false)
				return unserialize($content);
			else
				return null;
		}
	}
	public function save($state)
	{
		$content=serialize($state);
		$saveFile=true;
		if(($cache=$this->getApplication()->getCache())!==null)
		{
			if($cache->get(self::CACHE_NAME)===$content)
				$saveFile=false;
			else
				$cache->set(self::CACHE_NAME,$content);
		}
		if($saveFile)
		{
			$fileName=$this->getStateFilePath();
			file_put_contents($fileName,$content,LOCK_EX);
		}
	}
}
class TShellApplication extends TApplication
{
	public function run()
	{
		$this->initApplication();
	}
}
?>