Subversion-Projekte lars-tiefland.prado

Revision

Blame | Letzte Änderung | Log anzeigen | RSS feed

<?php
/**
 * File Name: pradolite.php
 * Last Update: 2009/01/11 20:12:48
 * 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.4';
        }
        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 ($item === null)
                                                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);
                if ($catalogue===null)
                        $catalogue=isset($config['catalogue'])?$config['catalogue']:'messages';
                Translation::init($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($catalogue)->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);
        }
        public function getErrorTemplatePath()
        {
                if($this->_templatePath===null)
                        $this->_templatePath=Prado::getFrameworkPath().'/Exceptions/templates';
                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->getMessage());
                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)
        {
                if(empty($value) && $expire === 0)
                        $this->delete($id);
                else
                {
                        $data=array($value,$dependency);
                        return $this->setValue($this->generateUniqueKey($id),serialize($data),$expire);
                }
        }
        public function add($id,$value,$expire=0,$dependency=null)
        {
                if(empty($value) && $expire === 0)
                        return false;
                $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(self::$_json === null)
                        self::$_json = Prado::createComponent('System.Web.Javascripts.TJSON');
                return self::$_json->encode($value);
        }
        public static function jsonDecode($value)
        {
                if(self::$_json === null)
                        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 getHttpProtocolVersion ()
        {
                return isset($_SERVER['SERVER_PROTOCOL'])?$_SERVER['SERVER_PROTOCOL']:'';
        }
        public function getRequestUri()
        {
                return $this->_requestUri;
        }
        public function getBaseUrl($forceSecureConnection=false)
        {
                $url=$this->getUrl();
                $scheme=($forceSecureConnection)?"https":$url->getScheme();
                $host=$url->getHost();
                if (($port=$url->getPort())) $host.=':'.$port;
                return $scheme.'://'.$host;
        }
        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 ()
        {
                if (($version=$this->getRequest()->getHttpProtocolVersion())==='')
                        header (' ', true, $this->_status);
                else
                        header($version.' '.$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();
        public function getIsValid();
        public function setIsValid($value);
}
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(self::$_pradoScripts === null)
                        {
                                $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);
                        chmod($scriptLoaderPath, PRADO_CHMOD);
                }
                $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(($dir = Prado::getPathOfNameSpace($base)) !== null) {
                                $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($class === null) {
                        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(extension_loaded('zlib'))
                        $str=gzcompress($str);
                if($page->getEnableStateEncryption())
                        $str=$sm->encrypt($str);
                return base64_encode($str);
        }
        public static function unserialize($page,$data)
        {
                $str=base64_decode($data);
                if($str==='')
                        return null;
                if($str!==false)
                {
                        $sm=$page->getApplication()->getSecurityManager();
                        if($page->getEnableStateEncryption())
                                $str=$sm->decrypt($str);
                        if(extension_loaded('zlib'))
                                $str=@gzuncompress($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]==='/')
                                                $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"dirname(\$this->getApplication()->getRequest()->getApplicationUrl()).'/$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 getSkins()
        {
                return $this->_skins;
        }
        protected function setSkins($value)
        {
                $this->_skins = $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=array();
        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=array_merge($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('assetmanager_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);
                                                @chmod($dst.DIRECTORY_SEPARATOR.$file, PRADO_CHMOD); 
                                        }
                                }
                                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;
        private $_pageServiceID = self::PAGE_SERVICE_ID;
        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($this->getPageServiceID()=>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 getPageServiceID()
        {
                return $this->_pageServiceID;
        }
        public function setPageServiceID($value)
        {
                $this->_pageServiceID=$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;
                if($this->_cacheFile)
                        $this->_cacheFile=$this->_runtimePath.DIRECTORY_SEPARATOR.self::CONFIGCACHE_FILE;
                                $this->_uniqueID=md5($this->_runtimePath);
        }
        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);
                }
                if(empty($this->_services))
                        $this->_services=array($this->getPageServiceID()=>array('TPageService',array(),null));
                                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=$this->getPageServiceID();
                $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();
        }
}
?>