PageRenderTime 165ms CodeModel.GetById 14ms app.highlight 79ms RepoModel.GetById 1ms app.codeStats 1ms

/protected/test.txt

http://github.com/phpnode/YiiJS
Plain Text | 13930 lines | 13545 code | 385 blank | 0 comment | 0 complexity | 29c971761f8a835f00acf162c4fa918b MD5 | raw file
    1/*global php, $, jQuery, alert, clearInterval, clearTimeout, document, event, frames, history, Image, location, name, navigator, Option, parent, screen, setInterval, setTimeout, window, XMLHttpRequest */
    2/**
    3 * Yii is a helper class serving common framework functionalities.
    4 * 
    5 * It encapsulates {@link YiiBase} which provides the actual implementation.
    6 * By writing your own Yii class, you can customize some functionalities of YiiBase.
    7 * 
    8 * @originalAuthor Qiang Xue <qiang.xue@gmail.com>
    9 * @version $Id: yii.js 2799 2011-01-01 19:31:13Z qiang.xue $
   10 * @package system
   11 * @since 1.0
   12 * @author Charles Pick
   13 * @class
   14 * @extends Yii.YiiBase
   15 */
   16var YII_DEBUG = true, YII_TRACE_LEVEL = 3, YII_BEGIN_TIME = new Date().getTime() / 1000, Yii = /** @lends Yii.prototype */{
   17	/**	
   18	 * @property {Array} class map used by the Yii autoloading mechanism.
   19	 * The array keys are the class names and the array values are the corresponding class file paths.
   20	 * @since 1.1.5
   21	 */
   22	classMap: {},
   23	_aliases: {},
   24	_imports: {},
   25	_includePaths: {},
   26	_app: null,
   27	_logger: null,
   28	/**	
   29	 * @property {Array} class map for core Yii classes.
   30	 * NOTE, DO NOT MODIFY THIS ARRAY MANUALLY. IF YOU CHANGE OR ADD SOME CORE CLASSES,
   31	 * PLEASE RUN 'build autoload' COMMAND TO UPDATE THIS ARRAY.
   32	 */
   33	_coreClasses: {'CApplication':'/base/CApplication.js','CApplicationComponent':'/base/CApplicationComponent.js','CBehavior':'/base/CBehavior.js','CComponent':'/base/CComponent.js','CErrorEvent':'/base/CErrorEvent.js','CErrorHandler':'/base/CErrorHandler.js','CException':'/base/CException.js','CExceptionEvent':'/base/CExceptionEvent.js','CHttpException':'/base/CHttpException.js','CModel':'/base/CModel.js','CModelBehavior':'/base/CModelBehavior.js','CModelEvent':'/base/CModelEvent.js','CModule':'/base/CModule.js','CSecurityManager':'/base/CSecurityManager.js','CStatePersister':'/base/CStatePersister.js','CApcCache':'/caching/CApcCache.js','CCache':'/caching/CCache.js','CDbCache':'/caching/CDbCache.js','CDummyCache':'/caching/CDummyCache.js','CEAcceleratorCache':'/caching/CEAcceleratorCache.js','CFileCache':'/caching/CFileCache.js','CMemCache':'/caching/CMemCache.js','CWinCache':'/caching/CWinCache.js','CXCache':'/caching/CXCache.js','CZendDataCache':'/caching/CZendDataCache.js','CCacheDependency':'/caching/dependencies/CCacheDependency.js','CChainedCacheDependency':'/caching/dependencies/CChainedCacheDependency.js','CDbCacheDependency':'/caching/dependencies/CDbCacheDependency.js','CDirectoryCacheDependency':'/caching/dependencies/CDirectoryCacheDependency.js','CExpressionDependency':'/caching/dependencies/CExpressionDependency.js','CFileCacheDependency':'/caching/dependencies/CFileCacheDependency.js','CGlobalStateCacheDependency':'/caching/dependencies/CGlobalStateCacheDependency.js','CAttributeCollection':'/collections/CAttributeCollection.js','CConfiguration':'/collections/CConfiguration.js','CList':'/collections/CList.js','CListIterator':'/collections/CListIterator.js','CMap':'/collections/CMap.js','CMapIterator':'/collections/CMapIterator.js','CQueue':'/collections/CQueue.js','CQueueIterator':'/collections/CQueueIterator.js','CStack':'/collections/CStack.js','CStackIterator':'/collections/CStackIterator.js','CTypedList':'/collections/CTypedList.js','CTypedMap':'/collections/CTypedMap.js','CConsoleApplication':'/console/CConsoleApplication.js','CConsoleCommand':'/console/CConsoleCommand.js','CConsoleCommandRunner':'/console/CConsoleCommandRunner.js','CHelpCommand':'/console/CHelpCommand.js','CDbCommand':'/db/CDbCommand.js','CDbConnection':'/db/CDbConnection.js','CDbDataReader':'/db/CDbDataReader.js','CDbException':'/db/CDbException.js','CDbMigration':'/db/CDbMigration.js','CDbTransaction':'/db/CDbTransaction.js','CActiveFinder':'/db/ar/CActiveFinder.js','CActiveRecord':'/db/ar/CActiveRecord.js','CActiveRecordBehavior':'/db/ar/CActiveRecordBehavior.js','CDbColumnSchema':'/db/schema/CDbColumnSchema.js','CDbCommandBuilder':'/db/schema/CDbCommandBuilder.js','CDbCriteria':'/db/schema/CDbCriteria.js','CDbExpression':'/db/schema/CDbExpression.js','CDbSchema':'/db/schema/CDbSchema.js','CDbTableSchema':'/db/schema/CDbTableSchema.js','CMssqlColumnSchema':'/db/schema/mssql/CMssqlColumnSchema.js','CMssqlCommandBuilder':'/db/schema/mssql/CMssqlCommandBuilder.js','CMssqlPdoAdapter':'/db/schema/mssql/CMssqlPdoAdapter.js','CMssqlSchema':'/db/schema/mssql/CMssqlSchema.js','CMssqlTableSchema':'/db/schema/mssql/CMssqlTableSchema.js','CMysqlColumnSchema':'/db/schema/mysql/CMysqlColumnSchema.js','CMysqlSchema':'/db/schema/mysql/CMysqlSchema.js','CMysqlTableSchema':'/db/schema/mysql/CMysqlTableSchema.js','COciColumnSchema':'/db/schema/oci/COciColumnSchema.js','COciCommandBuilder':'/db/schema/oci/COciCommandBuilder.js','COciSchema':'/db/schema/oci/COciSchema.js','COciTableSchema':'/db/schema/oci/COciTableSchema.js','CPgsqlColumnSchema':'/db/schema/pgsql/CPgsqlColumnSchema.js','CPgsqlSchema':'/db/schema/pgsql/CPgsqlSchema.js','CPgsqlTableSchema':'/db/schema/pgsql/CPgsqlTableSchema.js','CSqliteColumnSchema':'/db/schema/sqlite/CSqliteColumnSchema.js','CSqliteCommandBuilder':'/db/schema/sqlite/CSqliteCommandBuilder.js','CSqliteSchema':'/db/schema/sqlite/CSqliteSchema.js','CChoiceFormat':'/i18n/CChoiceFormat.js','CDateFormatter':'/i18n/CDateFormatter.js','CDbMessageSource':'/i18n/CDbMessageSource.js','CGettextMessageSource':'/i18n/CGettextMessageSource.js','CLocale':'/i18n/CLocale.js','CMessageSource':'/i18n/CMessageSource.js','CNumberFormatter':'/i18n/CNumberFormatter.js','CPhpMessageSource':'/i18n/CPhpMessageSource.js','CGettextFile':'/i18n/gettext/CGettextFile.js','CGettextMoFile':'/i18n/gettext/CGettextMoFile.js','CGettextPoFile':'/i18n/gettext/CGettextPoFile.js','CDbLogRoute':'/logging/CDbLogRoute.js','CEmailLogRoute':'/logging/CEmailLogRoute.js','CFileLogRoute':'/logging/CFileLogRoute.js','CLogFilter':'/logging/CLogFilter.js','CLogRoute':'/logging/CLogRoute.js','CLogRouter':'/logging/CLogRouter.js','CLogger':'/logging/CLogger.js','CProfileLogRoute':'/logging/CProfileLogRoute.js','CWebLogRoute':'/logging/CWebLogRoute.js','CDateTimeParser':'/utils/CDateTimeParser.js','CFileHelper':'/utils/CFileHelper.js','CFormatter':'/utils/CFormatter.js','CMarkdownParser':'/utils/CMarkdownParser.js','CPropertyValue':'/utils/CPropertyValue.js','CTimestamp':'/utils/CTimestamp.js','CVarDumper':'/utils/CVarDumper.js','CBooleanValidator':'/validators/CBooleanValidator.js','CCaptchaValidator':'/validators/CCaptchaValidator.js','CCompareValidator':'/validators/CCompareValidator.js','CDateValidator':'/validators/CDateValidator.js','CDefaultValueValidator':'/validators/CDefaultValueValidator.js','CEmailValidator':'/validators/CEmailValidator.js','CExistValidator':'/validators/CExistValidator.js','CFileValidator':'/validators/CFileValidator.js','CFilterValidator':'/validators/CFilterValidator.js','CInlineValidator':'/validators/CInlineValidator.js','CNumberValidator':'/validators/CNumberValidator.js','CRangeValidator':'/validators/CRangeValidator.js','CRegularExpressionValidator':'/validators/CRegularExpressionValidator.js','CRequiredValidator':'/validators/CRequiredValidator.js','CSafeValidator':'/validators/CSafeValidator.js','CStringValidator':'/validators/CStringValidator.js','CTypeValidator':'/validators/CTypeValidator.js','CUniqueValidator':'/validators/CUniqueValidator.js','CUnsafeValidator':'/validators/CUnsafeValidator.js','CUrlValidator':'/validators/CUrlValidator.js','CValidator':'/validators/CValidator.js','CActiveDataProvider':'/web/CActiveDataProvider.js','CArrayDataProvider':'/web/CArrayDataProvider.js','CAssetManager':'/web/CAssetManager.js','CBaseController':'/web/CBaseController.js','CCacheHttpSession':'/web/CCacheHttpSession.js','CClientScript':'/web/CClientScript.js','CController':'/web/CController.js','CDataProvider':'/web/CDataProvider.js','CDbHttpSession':'/web/CDbHttpSession.js','CExtController':'/web/CExtController.js','CFormModel':'/web/CFormModel.js','CHttpCookie':'/web/CHttpCookie.js','CHttpRequest':'/web/CHttpRequest.js','CHttpSession':'/web/CHttpSession.js','CHttpSessionIterator':'/web/CHttpSessionIterator.js','COutputEvent':'/web/COutputEvent.js','CPagination':'/web/CPagination.js','CSort':'/web/CSort.js','CSqlDataProvider':'/web/CSqlDataProvider.js','CTheme':'/web/CTheme.js','CThemeManager':'/web/CThemeManager.js','CUploadedFile':'/web/CUploadedFile.js','CUrlManager':'/web/CUrlManager.js','CWebApplication':'/web/CWebApplication.js','CWebModule':'/web/CWebModule.js','CWidgetFactory':'/web/CWidgetFactory.js','CAction':'/web/actions/CAction.js','CInlineAction':'/web/actions/CInlineAction.js','CViewAction':'/web/actions/CViewAction.js','CAccessControlFilter':'/web/auth/CAccessControlFilter.js','CAuthAssignment':'/web/auth/CAuthAssignment.js','CAuthItem':'/web/auth/CAuthItem.js','CAuthManager':'/web/auth/CAuthManager.js','CBaseUserIdentity':'/web/auth/CBaseUserIdentity.js','CDbAuthManager':'/web/auth/CDbAuthManager.js','CPhpAuthManager':'/web/auth/CPhpAuthManager.js','CUserIdentity':'/web/auth/CUserIdentity.js','CWebUser':'/web/auth/CWebUser.js','CFilter':'/web/filters/CFilter.js','CFilterChain':'/web/filters/CFilterChain.js','CInlineFilter':'/web/filters/CInlineFilter.js','CForm':'/web/form/CForm.js','CFormButtonElement':'/web/form/CFormButtonElement.js','CFormElement':'/web/form/CFormElement.js','CFormElementCollection':'/web/form/CFormElementCollection.js','CFormInputElement':'/web/form/CFormInputElement.js','CFormStringElement':'/web/form/CFormStringElement.js','CGoogleApi':'/web/helpers/CGoogleApi.js','CHtml':'/web/helpers/CHtml.js','CJSON':'/web/helpers/CJSON.js','CJavaScript':'/web/helpers/CJavaScript.js','CPradoViewRenderer':'/web/renderers/CPradoViewRenderer.js','CViewRenderer':'/web/renderers/CViewRenderer.js','CWebService':'/web/services/CWebService.js','CWebServiceAction':'/web/services/CWebServiceAction.js','CWsdlGenerator':'/web/services/CWsdlGenerator.js','CActiveForm':'/web/widgets/CActiveForm.js','CAutoComplete':'/web/widgets/CAutoComplete.js','CClipWidget':'/web/widgets/CClipWidget.js','CContentDecorator':'/web/widgets/CContentDecorator.js','CFilterWidget':'/web/widgets/CFilterWidget.js','CFlexWidget':'/web/widgets/CFlexWidget.js','CHtmlPurifier':'/web/widgets/CHtmlPurifier.js','CInputWidget':'/web/widgets/CInputWidget.js','CMarkdown':'/web/widgets/CMarkdown.js','CMaskedTextField':'/web/widgets/CMaskedTextField.js','CMultiFileUpload':'/web/widgets/CMultiFileUpload.js','COutputCache':'/web/widgets/COutputCache.js','COutputProcessor':'/web/widgets/COutputProcessor.js','CStarRating':'/web/widgets/CStarRating.js','CTabView':'/web/widgets/CTabView.js','CTextHighlighter':'/web/widgets/CTextHighlighter.js','CTreeView':'/web/widgets/CTreeView.js','CWidget':'/web/widgets/CWidget.js','CCaptcha':'/web/widgets/captcha/CCaptcha.js','CCaptchaAction':'/web/widgets/captcha/CCaptchaAction.js','CBasePager':'/web/widgets/pagers/CBasePager.js','CLinkPager':'/web/widgets/pagers/CLinkPager.js','CListPager':'/web/widgets/pagers/CListPager.js'},
   34	/**
   35	 * Augments a class with properties from another class
   36	 * @param {Object} receivingClass The class that should be augmented
   37	 * @param {Object} givingClass The class that donates the properties
   38	 */
   39	augment: function (receivingClass, givingClass) {
   40		var methodName;
   41		for (methodName in givingClass.prototype) {
   42			if(!receivingClass.prototype[methodName]) {
   43				receivingClass.prototype[methodName] = givingClass.prototype[methodName];
   44			}
   45		}
   46	},
   47	
   48	/**	
   49	 * @returns {String} the version of Yii framework
   50	 */
   51	getVersion: function () {
   52		return '1.1.8-dev';
   53	},
   54	/**	
   55	 * Creates a Web application instance.
   56	 * @param {Mixed} config application configuration.
   57	 * If a string, it is treated as the path of the file that contains the configuration;
   58	 * If an array, it is the actual configuration information.
   59	 * Please make sure you specify the {@link CApplication::basePath basePath} property in the configuration,
   60	 * which should point to the directory containing all application logic, template and data.
   61	 * If not, the directory will be defaulted to 'protected'.
   62	 */
   63	createWebApplication: function (config) {
   64		if (config === undefined) {
   65			config = null;
   66		}
   67		return Yii.createApplication('CWebApplication',config);
   68	},
   69	/**	
   70	 * Creates a console application instance.
   71	 * @param {Mixed} config application configuration.
   72	 * If a string, it is treated as the path of the file that contains the configuration;
   73	 * If an array, it is the actual configuration information.
   74	 * Please make sure you specify the {@link CApplication::basePath basePath} property in the configuration,
   75	 * which should point to the directory containing all application logic, template and data.
   76	 * If not, the directory will be defaulted to 'protected'.
   77	 */
   78	createConsoleApplication: function (config) {
   79		if (config === undefined) {
   80			config = null;
   81		}
   82		return Yii.createApplication('CConsoleApplication',config);
   83	},
   84	/**	
   85	 * Creates an application of the specified class.
   86	 * @param {String} classVar the application class name
   87	 * @param {Mixed} config application configuration. This parameter will be passed as the parameter
   88	 * to the constructor of the application class.
   89	 * @returns {Mixed} the application instance
   90	 * @since 1.0.10
   91	 */
   92	createApplication: function (classVar, config) {
   93		if (config === undefined) {
   94			config = null;
   95		}
   96		
   97		return new Yii[classVar](config);
   98		
   99	},
  100	/**	
  101	 * Returns the application singleton, null if the singleton has not been created yet.
  102	 * @returns {Yii.CApplication} the application singleton, null if the singleton has not been created yet.
  103	 */
  104	app: function () {
  105		return Yii._app;
  106	},
  107	/**	
  108	 * Stores the application instance in the class static member.
  109	 * This method helps implement a singleton pattern for CApplication.
  110	 * Repeated invocation of this method or the CApplication constructor
  111	 * will cause the throw of an exception.
  112	 * To retrieve the application instance, use {@link app()}.
  113	 * @param {Yii.CApplication} app the application instance. If this is null, the existing
  114	 * application singleton will be removed.
  115	 * @throws {Yii.CException} if multiple application instances are registered.
  116	 */
  117	setApplication: function (app) {
  118		var _app;
  119		if(Yii._app===null || app===null) {
  120			Yii._app=app;
  121		}
  122		else {
  123			throw new Yii.CException(Yii.t('yii','Yii application can only be created once.'));
  124		}
  125	},
  126	/**	
  127	 * @returns {String} the path of the framework
  128	 */
  129	getFrameworkPath: function () {
  130		return YII_PATH;
  131	},
  132	/**	
  133	 * Creates an object and initializes it based on the given configuration.
  134	 * 
  135	 * The specified configuration can be either a string or an array.
  136	 * If the former, the string is treated as the object type which can
  137	 * be either the class name or {@link Yii::getPathOfAlias class path alias}.
  138	 * If the latter, the 'class' element is treated as the object type,
  139	 * and the rest name-value pairs in the array are used to initialize
  140	 * the corresponding object properties.
  141	 * 
  142	 * Any additional parameters passed to this method will be
  143	 * passed to the constructor of the object being created.
  144	 * 
  145	 * NOTE: the array-typed configuration has been supported since version 1.0.1.
  146	 * 
  147	 * @param {Mixed} config the configuration. It can be either a string or an array.
  148	 * @returns {Mixed} the created object
  149	 * @throws {Yii.CException} if the configuration does not have a 'class' element.
  150	 */
  151	createComponent: function (config) {
  152		var type, n, args, object, classVar, key, value;
  153		
  154		if(typeof(config) === 'string') {
  155			type=config;
  156			config=[];
  157		}
  158		else if(config['class'] !== undefined) {
  159			type=config['class'];
  160			delete config['class'];
  161		}
  162		else {
  163			throw new Yii.CException(Yii.t('yii','Object configuration must be an array containing a "class" element.'));
  164		}
  165		if(!Yii[type]) {
  166			type=Yii.imports(type,true);
  167		}
  168		if((n=arguments.length)>1) {
  169			args=arguments;
  170			if(n===2) {
  171				object=new Yii[type](args[1]);
  172			}
  173			else if(n===3) {
  174				object=new Yii[type](args[1],args[2]);
  175			}
  176			else if(n===4) {
  177				object=new Yii[type](args[1],args[2],args[3]);
  178			}
  179			else if(n===4) {
  180				object=new Yii[type](args[1],args[2],args[3]);
  181			}
  182			else if(n===5) {
  183				object=new Yii[type](args[1],args[2],args[3],args[4]);
  184			}
  185		}
  186		else {
  187			object=new Yii[type]();
  188		}
  189		
  190		for (key in config) {
  191			if (config.hasOwnProperty(key)) {
  192				
  193				value = config[key];
  194				object.set(key,value);
  195			}
  196		}
  197		
  198		return object;
  199	},
  200	/**	
  201	 * Imports a class or a directory.
  202	 * 
  203	 * Importing a class is like including the corresponding class file.
  204	 * The main difference is that importing a class is much lighter because it only
  205	 * includes the class file when the class is referenced the first time.
  206	 * 
  207	 * Importing a directory is equivalent to adding a directory into the PHP include path.
  208	 * If multiple directories are imported, the directories imported later will take
  209	 * precedence in class file searching (i.e., they are added to the front of the PHP include path).
  210	 * 
  211	 * Path aliases are used to import a class or directory. For example,
  212	 * <ul>
  213	 *   <li><code>application.components.GoogleMap</code>: import the <code>GoogleMap</code> class.</li>
  214	 *   <li><code>application.components.*</code>: import the <code>components</code> directory.</li>
  215	 * </ul>
  216	 * 
  217	 * The same path alias can be imported multiple times, but only the first time is effective.
  218	 * Importing a directory does not import any of its subdirectories.
  219	 * 
  220	 * Starting from version 1.1.5, this method can also be used to import a class in namespace format
  221	 * (available for PHP 5.3 or above only). It is similar to importing a class in path alias format,
  222	 * except that the dot separator is replaced by the backslash separator. For example, importing
  223	 * <code>application\components\GoogleMap</code> is similar to importing <code>application.components.GoogleMap</code>.
  224	 * The difference is that the former class is using qualified name, while the latter unqualified.
  225	 * 
  226	 * Note, importing a class in namespace format requires that the namespace is corresponding to
  227	 * a valid path alias if we replace the backslash characters with dot characters.
  228	 * For example, the namespace <code>application\components</code> must correspond to a valid
  229	 * path alias <code>application.components</code>.
  230	 * 
  231	 * @param {String} alias path alias to be imported
  232	 * @param {Boolean} forceInclude whether to include the class file immediately. If false, the class file
  233	 * will be included only when the class is being used. This parameter is used only when
  234	 * the path alias refers to a class.
  235	 * @returns {String} the class name or the directory that this alias refers to
  236	 * @throws {Yii.CException} if the alias is invalid
  237	 */
  238	imports: function (alias, forceInclude) {
  239		var result, _imports, pos, namespace, path, classFile, classMap, className, isClass, _includePaths;
  240		if (forceInclude === undefined) {
  241			forceInclude = true;
  242		}
  243		if(Yii._imports[alias] !== undefined) {  // previously imported
  244			
  245			return Yii._imports[alias];
  246		}
  247		
  248		if(Yii[alias] !== undefined) {
  249			return (Yii._imports[alias]=alias);
  250		}
  251		if ((pos = alias.indexOf("/")) !== -1) {
  252			className = String(alias.split("/").pop());
  253			
  254			if (className.slice(-3) == ".js") {
  255				
  256				className = className.slice(0,-3);
  257			}
  258		
  259			if (Yii[className] !== undefined) {
  260				return (Yii._imports[alias] = className);
  261			}
  262			Yii.include(alias,!forceInclude);
  263			Yii.classMap[className] = alias;
  264			Yii._imports[alias] = className;
  265			
  266			return className; 
  267		}
  268		if((pos=alias.indexOf('.'))===-1) { // a simple class name
  269			result = Yii.autoload(alias, !forceInclude);
  270			if(forceInclude && !result) {
  271				throw new Yii.CException(Yii.t('yii','Alias "{alias}" is invalid. Make sure it points to an existing directory or file.',
  272				{'{alias}':alias}));				
  273			}
  274			Yii._imports[alias]=alias;
  275			return alias;
  276		}
  277		className=String(alias.split(".").pop());
  278		
  279		isClass=className!=='*';
  280		if (!isClass) {
  281			throw new Yii.CException("YiiJS does not support importing directories");
  282		}
  283		if(Yii[className] !== undefined) {
  284			return (Yii._imports[alias]=className);
  285		}
  286		
  287		else if((path=Yii.getPathOfAlias(alias))!==false) {
  288			Yii.include(path + ".js",!forceInclude);
  289			Yii.classMap[className]=path+'.js';
  290			return className;
  291		}
  292		else {
  293			throw new Yii.CException(Yii.t('yii','Alias "{alias}" is invalid. Make sure it points to an existing directory or file.',
  294				{'{alias}':alias}));
  295		}
  296	},
  297	/**	
  298	 * Translates an alias into a file path.
  299	 * Note, this method does not ensure the existence of the resulting file path.
  300	 * It only checks if the root alias is valid or not.
  301	 * @param {String} alias alias (e.g. system.web.CController)
  302	 * @returns {Mixed} file path corresponding to the alias, false if the alias is invalid.
  303	 */
  304	getPathOfAlias: function (alias) {
  305		var _aliases, pos, rootAlias, _app;
  306		if(Yii._aliases[alias] !== undefined) {
  307			return Yii._aliases[alias];
  308		}
  309		else if((pos=php.strpos(alias,'.'))!==false) {
  310			rootAlias=alias.slice(0, pos);
  311			if(Yii._aliases[rootAlias] !== undefined) {
  312				return (Yii._aliases[alias]=php.rtrim(Yii._aliases[rootAlias]+'/'+php.str_replace('.','/',alias.slice(pos+1)),'*'+'/'));
  313			}
  314			else if(Yii._app !== null && Yii._app instanceof Yii.CWebApplication){
  315				if(Yii._app.findModule(rootAlias)!==null) {
  316					return Yii.getPathOfAlias(alias);
  317				}
  318			}
  319		}
  320		return false;
  321	},
  322	/**	
  323	 * Create a path alias.
  324	 * Note, this method neither checks the existence of the path nor normalizes the path.
  325	 * @param {String} alias alias to the path
  326	 * @param {String} path the path corresponding to the alias. If this is null, the corresponding
  327	 * path alias will be removed.
  328	 */
  329	setPathOfAlias: function (alias, path) {
  330		var _aliases;
  331		if(php.empty(path)) {
  332			delete Yii._aliases[alias];
  333		}
  334		else {
  335			Yii._aliases[alias]=php.rtrim(path,'\\/');
  336		}
  337	},
  338	/**	
  339	 * Class autoload loader.
  340	 * @param {String} className class name
  341	 * @param {Boolean} async Whether to load this class
  342	 * via an asynchronous AJAX request, otherwise a blocking request is used, defaults to false.
  343	 * @returns {Boolean} whether the class has been loaded successfully
  344	 */
  345	autoload: function (className, async) {
  346		var _coreClasses, classMap, namespace, path, result;
  347		if (async === undefined) {
  348			async = true;
  349		}
  350		
  351		if(Yii._coreClasses[className] !== undefined) {
  352			if (Yii[className] !== undefined) {
  353				return true;
  354			}
  355		
  356			result = Yii.include(YII_PATH+Yii._coreClasses[className], async);
  357			if (!async) {
  358				return result;
  359			}
  360		}
  361		else if(Yii.classMap[className] !== undefined) {
  362			if (Yii[className] !== undefined) {
  363				return true;
  364			}
  365			result = Yii.include(Yii.classMap[className], async);
  366			if (!async) {
  367				return result;
  368			}
  369		}
  370		else {
  371			return Yii[className] !== undefined;
  372		}
  373		return true;
  374	},
  375	
  376	/**
  377	 * Includes a remote file, this will be evaled!
  378	 * @param {String} url The URL to load the file from
  379	 * @param {Boolean} async Whether to perform an asynchronous request or not, defaults to true.
  380	 * @param {Function} callback The callback to execute after the included file is evaled
  381	 * @returns {Mixed} either the jQuery ajax request if this is async, or
  382	 * if this is a blocking request returns the content or false depending on whether
  383	 * it succeeded or not.
  384	 */
  385	include: function (url, async, callback) {
  386		var options = {}, request;
  387		if (async === undefined) {
  388			async = true;
  389		}
  390		if (callback === undefined) {
  391			callback = function () {};
  392		}
  393		if(Yii._includePaths[url] !== undefined) {  // previously imported
  394			return Yii._includePaths[url];
  395		}
  396		options.url = url;
  397		options.async = async;
  398		options.cache = false;
  399		if (async) {
  400			options.success = function (res) {
  401				Yii._includePaths[url] = eval(res);
  402				callback(Yii._includePaths[url]);
  403			};
  404			options.error = function () {
  405				throw new Yii.CHttpException(404, Yii.t("system", "No such file"));
  406			};
  407			return jQuery.ajax(options);
  408		}
  409		else {
  410			
  411			request = jQuery.ajax(options);
  412			if (request.status > 399) {
  413				return false;
  414			}
  415			Yii._includePaths[url] = eval(request.responseText);
  416			callback(Yii._includePaths[url]);
  417			return Yii._includePaths[url];
  418			
  419			
  420		}
  421	},
  422	
  423	
  424	/**	
  425	 * Writes a trace message.
  426	 * This method will only log a message when the application is in debug mode.
  427	 * @param {String} msg message to be logged
  428	 * @param {String} category category of the message
  429	 * @see log
  430	 */
  431	trace: function (msg, category) {
  432		if (category === undefined) {
  433			category = 'application';
  434		}
  435		if(YII_DEBUG) {
  436			Yii.log(msg,Yii.CLogger.prototype.LEVEL_TRACE,category);
  437		}
  438	},
  439	/**	
  440	 * Logs a message.
  441	 * Messages logged by this method may be retrieved via {@link CLogger::getLogs}
  442	 * and may be recorded in different media, such as file, email, database, using
  443	 * {@link CLogRouter}.
  444	 * @param {String} msg message to be logged
  445	 * @param {String} level level of the message (e.g. 'trace', 'warning', 'error'). It is case-insensitive.
  446	 * @param {String} category category of the message (e.g. 'system.web'). It is case-insensitive.
  447	 */
  448	log: function (msg, level, category) {
  449		var _logger, traces, count, i, limit, trace, cmd;
  450		if (level === undefined) {
  451			level = 'info';
  452		}
  453		if (category === undefined) {
  454			category = 'application';
  455		}
  456		if(Yii._logger===null) {
  457			Yii._logger=new Yii.CLogger();
  458		}
  459		if(window['console'] !== undefined && YII_DEBUG && YII_TRACE_LEVEL>0 && level!==Yii.CLogger.prototype.LEVEL_PROFILE)	{
  460			cmd = "log";
  461			if (level === Yii.CLogger.prototype.LEVEL_ERROR) {
  462				cmd = "error";
  463			}
  464			else if (level === Yii.CLogger.prototype.LEVEL_WARNING) {
  465				cmd = "warn";
  466			}
  467			console[cmd](level + "\t" + php.str_pad(category,30," ") + "\t" + msg);
  468		}
  469		Yii._logger.log(msg,level,category);
  470	},
  471	/**	
  472	 * Marks the begin of a code block for profiling.
  473	 * This has to be matched with a call to {@link endProfile()} with the same token.
  474	 * The begin- and end- calls must also be properly nested, e.g.,
  475	 * <pre>
  476	 * Yii.beginProfile('block1');
  477	 * Yii.beginProfile('block2');
  478	 * Yii.endProfile('block2');
  479	 * Yii.endProfile('block1');
  480	 * </pre>
  481	 * The following sequence is not valid:
  482	 * <pre>
  483	 * Yii.beginProfile('block1');
  484	 * Yii.beginProfile('block2');
  485	 * Yii.endProfile('block1');
  486	 * Yii.endProfile('block2');
  487	 * </pre>
  488	 * @param {String} token token for the code block
  489	 * @param {String} category the category of this log message
  490	 * @see endProfile
  491	 */
  492	beginProfile: function (token, category) {
  493		if (category === undefined) {
  494			category = 'application';
  495		}
  496		Yii.log('begin:'+token,Yii.CLogger.prototype.LEVEL_PROFILE,category);
  497	},
  498	/**	
  499	 * Marks the end of a code block for profiling.
  500	 * This has to be matched with a previous call to {@link beginProfile()} with the same token.
  501	 * @param {String} token token for the code block
  502	 * @param {String} category the category of this log message
  503	 * @see beginProfile
  504	 */
  505	endProfile: function (token, category) {
  506		if (category === undefined) {
  507			category = 'application';
  508		}
  509		Yii.log('end:'+token,Yii.CLogger.prototype.LEVEL_PROFILE,category);
  510	},
  511	/**	
  512	 * @returns {Yii.CLogger} message logger
  513	 */
  514	getLogger: function () {
  515		var _logger;
  516		if(Yii._logger!==null) {
  517			return Yii._logger;
  518		}
  519		else {
  520			return (Yii._logger=new Yii.CLogger);
  521		}
  522	},
  523	/**	
  524	 * Returns a string that can be displayed on your Web page showing Powered-by-Yii information
  525	 * @returns {String} a string that can be displayed on your Web page showing Powered-by-Yii information
  526	 */
  527	powered: function () {
  528		return 'Powered by <a href="http://www.yiiframework.com/" rel="external">Yii Framework</a>.';
  529	},
  530	/**	
  531	 * Translates a message to the specified language.
  532	 * Starting from version 1.0.2, this method supports choice format (see {@link CChoiceFormat}),
  533	 * i.e., the message returned will be chosen from a few candidates according to the given
  534	 * number value. This feature is mainly used to solve plural format issue in case
  535	 * a message has different plural forms in some languages.
  536	 * @param {String} category message category. Please use only word letters. Note, category 'yii' is
  537	 * reserved for Yii framework core code use. See {@link CPhpMessageSource} for
  538	 * more interpretation about message category.
  539	 * @param {String} message the original message
  540	 * @param {Array} params parameters to be applied to the message using <code>strtr</code>.
  541	 * Starting from version 1.0.2, the first parameter can be a number without key.
  542	 * And in this case, the method will call {@link CChoiceFormat::format} to choose
  543	 * an appropriate message translation.
  544	 * Starting from version 1.1.6 you can pass parameter for {@link CChoiceFormat::format}
  545	 * or plural forms format without wrapping it with array.
  546	 * @param {String} source which message source application component to use.
  547	 * Defaults to null, meaning using 'coreMessages' for messages belonging to
  548	 * the 'yii' category and using 'messages' for the rest messages.
  549	 * @param {String} language the target language. If null (default), the {@link CApplication::getLanguage application language} will be used.
  550	 * This parameter has been available since version 1.0.3.
  551	 * @returns {String} the translated message
  552	 * @see CMessageSource
  553	 */
  554	t: function (category, message, params, source, language) {
  555		var _app, chunks, expressions, n, i;
  556		if (params === undefined) {
  557			params = {};
  558		}
  559		if (source === undefined) {
  560			source = null;
  561		}
  562		if (language === undefined) {
  563			language = null;
  564		}
  565		
  566		
  567		if(Yii._app!==null) {
  568			if(source===null) {
  569				source=(category==='yii'||category==='zii')?'coreMessages':'messages';
  570			}
  571			if((source=Yii._app.getComponent(source))!==null && source !== undefined) {
  572				message=source.translate(category,message,language);
  573			}
  574		}
  575		
  576		if(params==={} || params === []) {
  577			return message;
  578		}
  579		
  580		if(params[0] !== undefined) {
  581			// number choice
  582			if(php.strpos(message,'|')!==false) {
  583				if(php.strpos(message,'#')===false) {
  584					chunks=message.split('|');
  585					expressions=Yii._app.getLocale(language).getPluralRules();
  586					n=php.min(php.count(chunks),php.count(expressions));
  587					if(n) {
  588						for(i=0;i<n;i++) {
  589							chunks[i]=expressions[i]+'#'+chunks[i];
  590						}
  591						message=chunks.join('|');
  592					}
  593				}
  594				message=Yii.CChoiceFormat.format(message,params[0]);
  595			}
  596			if(params['{n}'] === undefined) {
  597				params['{n}']=params[0];
  598			}
  599			delete params[0];
  600		}
  601		if (params !== {}) {
  602			return php.strtr(message,params);
  603		}
  604		return message;
  605	},
  606	/**	
  607	 * Registers a new class autoloader.
  608	 * The new autoloader will be placed before {@link autoload} and after
  609	 * any other existing autoloaders.
  610	 * @param {Function} callback a valid PHP callback (function name or array($className,$methodName)).
  611	 * @since 1.0.10
  612	 */
  613	registerAutoloader: function (callback) {
  614		
  615	},
  616	/**
  617	 * Removes JSDoc comments from a string
  618	 * TODO: move this somewhere else
  619	 * @param {String} str the string to strip
  620	 * @returns {String} the stripped string
  621	 */
  622	removeComments: function (str) {
  623 
  624	    var uid = '_' + (new Date()),
  625	        primatives = [],
  626	        primIndex = 0;
  627	 
  628	    return (
  629	        str
  630	        .replace(/(['"])(\\\1|.)+?\1/g, function(match){
  631	            primatives[primIndex] = match;
  632	            return (uid + '') + primIndex++;
  633	        })
  634	        .replace(/([^\/])(\/(?!\*|\/)(\\\/|.)+?\/[gim]{0,3})/g, function(match, $1, $2){
  635	            primatives[primIndex] = $2;
  636	            return $1 + (uid + '') + primIndex++;
  637	        })
  638	        .replace(/\/\/.*?\/?\*.+?(?=\n|\r|$)|\/\*[\s\S]*?\/\/[\s\S]*?\*\//g, '')
  639	        .replace(/\/\/.+?(?=\n|\r|$)|\/\*[\s\S]+?\*\//g, '')
  640	        .replace(RegExp('\\/\\*[\\s\\S]+' + uid + '\\d+', 'g'), '')
  641	        .replace(RegExp(uid + '(\\d+)', 'g'), function(match, n){
  642	            return primatives[n];
  643	        })
  644	    );
  645	},
  646	/**
  647	 * Similar to PHP's preg_match_all
  648	 * @param {RegExp} regex The regular expression to match against
  649	 * @param {String} haystack The string to perform the regex on
  650	 * @returns {Array} an array of matches
  651	 */
  652	matchAll:  function (regex, haystack) {
  653		var matches = [], i, match;
  654		match = regex.exec(haystack);
  655			
  656		while (match !== null) {
  657			matches.push(match);
  658			match = regex.exec(haystack);
  659		}
  660		return matches;
  661	},
  662	/**
  663	 * Extends a class
  664	 */
  665	extend: function (childClass, parentClass, properties) {
  666		childClass.prototype = new Yii[parentClass](false);
  667		childClass.prototype.constructor = childClass; 
  668		if (properties !== undefined) {
  669			Yii.forEach(properties, function(name, value) {
  670				childClass.prototype[name] = value;
  671			});
  672		}
  673	},
  674	
  675	/**
  676	 * Implements foreach in JavaScript
  677	 * @param {Mixed} itemList a list of items to iterate through
  678	 * @param {Function} callback The callback function, it will recieve 2 parameters, key and value
  679	 * if the callback returns false, the loop will break.
  680	 */
  681	forEach: function (itemList, callback) {
  682		var i, limit;
  683		if (typeof itemList === "function") {
  684			return Yii.forEach(itemList(), callback);
  685		}
  686		if (Object.prototype.toString.call(itemList) === '[object Array]' || itemList instanceof Yii.CList || itemList instanceof Yii.CStack) {
  687			limit = itemList.length;
  688			for (i = 0; i < limit; i++) {
  689				if (i === "forEach") {
  690					continue;
  691				}
  692				else if (callback(i, itemList[i]) === false) {
  693					break;
  694				}
  695			}
  696		}
  697		else {
  698			for (i in itemList) {
  699				if (itemList.hasOwnProperty(i)) {
  700					if (i === "forEach") {
  701						continue;
  702					}
  703					else if (callback(i, itemList[i]) === false) {
  704						break;
  705					}	
  706				}
  707			}
  708		}
  709		return itemList;
  710	},
  711	
  712	/**
  713	 * Filter an array of items
  714	 */
  715	filter: function (items, block) {
  716        var values = [];
  717        var thisp = arguments[1];
  718        for (var i = 0; i < items.length; i++)
  719            if (block.call(thisp, items[i]))
  720                values.push(items[i]);
  721        return values;
  722    }
  723};
  724/**
  725 * A shortcut to application properties.
  726 * Supports virtual getters and setters, e.g:
  727 * <pre>
  728 * $app("securityManager.validationKey") === Yii.app().getSecurityManager().getValidationKey();
  729 * </pre>
  730 */
  731var $app = function(selector, setVal) {
  732	var stack, parts, i, limit, item, getter, last;
  733	if (selector === undefined || php.trim(selector).length === 0) {
  734		return Yii.app();
  735	}
  736	parts = selector.split(".");
  737	
  738	limit = parts.length;
  739	last = limit - 1;
  740	stack = Yii.app();
  741	for (i = 0; i < limit; i++) {
  742		
  743		if (stack instanceof Yii.CComponent) {
  744			if (setVal !== undefined) {
  745				return stack.set(parts.join("."),setVal);
  746			}
  747			return stack.get(parts.join("."));
  748		}
  749		item = parts.shift();
  750		if (i === last && setVal !== undefined) {
  751			if (stack[item] !== undefined) {
  752				stack[item] = setVal;
  753				return setVal;
  754			}
  755			else if (stack.get !== undefined) {
  756				stack = stack.set.call(stack, item, setVal);
  757				return setVal;
  758			}
  759			else {
  760				throw new Yii.CException("No such property: " + item);
  761			}
  762		}
  763		else {
  764			if (stack[item] !== undefined) {
  765				stack = stack[item];
  766			}
  767			else if (stack.get !== undefined) {
  768				stack = stack.get.call(stack, item);
  769			}
  770			else {
  771				throw new Yii.CException("No such property: " + item);
  772			}
  773		}
  774	}
  775	
  776	return stack;
  777};/*global Yii, php, $, jQuery, alert, clearInterval, clearTimeout, document, event, frames, history, Image, location, name, navigator, Option, parent, screen, setInterval, setTimeout, window, XMLHttpRequest */
  778/**
  779 * CComponent is the base class for all components.
  780 * 
  781 * CComponent implements the protocol of defining, using properties and events.
  782 * 
  783 * A property is defined by a getter method, and/or a setter method.
  784 * Properties can be accessed in the way like accessing normal object members.
  785 * Reading or writing a property will cause the invocation of the corresponding
  786 * getter or setter method, e.g
  787 * <pre>
  788 * a=component.text;     // equivalent to $a=$component->getText();
  789 * component.text='abc';  // equivalent to $component->setText('abc');
  790 * </pre>
  791 * The signatures of getter and setter methods are as follows,
  792 * <pre>
  793 * // getter, defines a readable property 'text'
  794 * public function getText() { +++ }
  795 * // setter, defines a writable property 'text' with $value to be set to the property
  796 * public function setText(value) { +++ }
  797 * </pre>
  798 * 
  799 * An event is defined by the presence of a method whose name starts with 'on'.
  800 * The event name is the method name. When an event is raised, functions
  801 * (called event handlers) attached to the event will be invoked automatically.
  802 * 
  803 * An event can be raised by calling {@link raiseEvent} method, upon which
  804 * the attached event handlers will be invoked automatically in the order they
  805 * are attached to the event. Event handlers must have the following signature,
  806 * <pre>
  807 * function eventHandler(event) { +++ }
  808 * </pre>
  809 * where $event includes parameters associated with the event.
  810 * 
  811 * To attach an event handler to an event, see {@link attachEventHandler}.
  812 * You can also use the following syntax:
  813 * <pre>
  814 * component.onClick=callback;    // or $component->onClick->add($callback);
  815 * </pre>
  816 * where $callback refers to a valid PHP callback. Below we show some callback examples:
  817 * <pre>
  818 * 'handleOnClick'                   // handleOnClick() is a global function
  819 * [object,'handleOnClick']    // using $object->handleOnClick()
  820 * ['Page','handleOnClick']     // using Page::handleOnClick()
  821 * </pre>
  822 * 
  823 * To raise an event, use {@link raiseEvent}. The on-method defining an event is
  824 * commonly written like the following:
  825 * <pre>
  826 * public function onClick(event)
  827 * {
  828 *     this.raiseEvent('onClick',event);
  829 * }
  830 * </pre>
  831 * where <code>$event</code> is an instance of {@link CEvent} or its child class.
  832 * One can then raise the event by calling the on-method instead of {@link raiseEvent} directly.
  833 * 
  834 * Both property names and event names are case-insensitive.
  835 * 
  836 * Starting from version 1.0.2, CComponent supports behaviors. A behavior is an
  837 * instance of {@link IBehavior} which is attached to a component. The methods of
  838 * the behavior can be invoked as if they belong to the component. Multiple behaviors
  839 * can be attached to the same component.
  840 * 
  841 * To attach a behavior to a component, call {@link attachBehavior}; and to detach the behavior
  842 * from the component, call {@link detachBehavior}.
  843 * 
  844 * A behavior can be temporarily enabled or disabled by calling {@link enableBehavior}
  845 * or {@link disableBehavior}, respectively. When disabled, the behavior methods cannot
  846 * be invoked via the component.
  847 * 
  848 * Starting from version 1.1.0, a behavior's properties (either its public member variables or
  849 * its properties defined via getters and/or setters) can be accessed through the component it
  850 * is attached to.
  851 * 
  852 * @originalAuthor Qiang Xue <qiang.xue@gmail.com>
  853 * @version $Id: CComponent.php 3066 2011-03-13 14:22:55Z qiang.xue $
  854 * @package system.base
  855 * @since 1.0
  856 * @author Charles Pick
  857 * @class
  858 */
  859Yii.CComponent = function CComponent() {
  860};
  861Yii.CComponent.prototype._e = null;
  862Yii.CComponent.prototype._m = null;
  863/**
  864 * Gets the class name for this item.
  865 * Since JavaScript doesn't really support this we 
  866 * abuse function declarations to implement it,
  867 * for example instead of:
  868 * <pre>
  869 * Yii.Blah = function() { ... }
  870 * </pre>
  871 * we use:
  872 * <pre>
  873 * Yii.Blah = function Blah() { ... }
  874 * </pre>
  875 * We can now retrieve the name of the class by inspecting the constructor.
  876 */
  877Yii.CComponent.prototype.getClassName = function() {
  878	var matches, className;
  879	
  880	matches = /function(.*)\((.*)\)/.exec((this).constructor);
  881	if (matches) {
  882		return php.trim(matches[1]);
  883	}
  884};
  885/**
  886 * Returns a property value, an event handler list or a behavior based on its name.
  887 * Do not call this method. This is a PHP magic method that we override
  888 * to allow using the following syntax to read a property or obtain event handlers:
  889 * <pre>
  890 * value=component.propertyName;
  891 * handlers=component.eventName;
  892 * </pre>
  893 * @param {String} name the property name or event name
  894 * @returns {Mixed} the property value, event handlers attached to the event, or the named behavior (since version 1.0.2)
  895 * @throws {Yii.CException} if the property or event is not defined
  896 * @see __set
  897 */
  898Yii.CComponent.prototype.get = function (name) {
  899		var getter, i, object, nameParts = [], limit;
  900		
  901		if (name.indexOf !== undefined && name.indexOf(".") !== -1) {
  902			nameParts = name.split(".");
  903			name = nameParts.shift();
  904		}
  905		if (this[name] !== undefined) {
  906			object = this[name];
  907			if (nameParts.length > 0) {
  908				if (object instanceof Yii.CComponent) {
  909					return object.get(nameParts.join("."));
  910				}
  911				limit = nameParts.length;
  912				for (i = 0; i < limit; i++) {
  913					name = nameParts.shift();
  914					object = object[name];
  915					if (nameParts.length === 0) {
  916						return object;
  917					}
  918					
  919					if (object instanceof Yii.CComponent) {
  920						return object.get(nameParts.join("."));
  921					}
  922				}
  923			}
  924			return object;
  925		}
  926		getter='get'+php.ucfirst(name);
  927		if(php.method_exists(this,getter)) {
  928			object = this[getter]();
  929			if (nameParts.length > 0) {
  930				if (object instanceof Yii.CComponent) {
  931					return object.get(nameParts.join("."));
  932				}
  933				limit = nameParts.length;
  934				for (i = 0; i < limit; i++) {
  935					name = nameParts.shift();
  936					object = object[name];
  937					if (nameParts.length === 0) {
  938						return object;
  939					}
  940					
  941					if (object instanceof Yii.CComponent) {
  942						return object.get(nameParts.join("."));
  943					}
  944					
  945				}
  946			}
  947			return object;
  948		}
  949		else if(php.strncasecmp(name,'on',2)===0 && php.method_exists(this,name)) {
  950			// duplicating getEventHandlers() here for performance
  951			name=name.toLowerCase();
  952			if(this._e[name] === undefined) {
  953				this._e[name]=new Yii.CList();
  954			}
  955			return this._e[name];
  956		}
  957		else if(this._m !== null && this._m[name] !== undefined) {
  958			return this._m[name];
  959		}
  960		else if(this._m !== null) {
  961			for (i in this._m) {
  962				if (this._m.hasOwnProperty(i)) {
  963					
  964					object = this._m[i];
  965					try {
  966						if(object.getEnabled() && (php.property_exists(object,name) || object.canGetProperty(name))) {
  967							if (nameParts.length > 0) {
  968								return object.get(nameParts.join("."));
  969							}
  970							return object.get(name);
  971						}
  972					}
  973					catch (e) {
  974						console.log(e);
  975					}
  976				}
  977			}
  978		}
  979		console.log(this.getClassName() + " : " + name);
  980		throw new Yii.CException(Yii.t('yii','Property "{class}.{property}" is not defined.',
  981			{'{class}':this.getClassName(), '{property}':name}));
  982	};
  983/**
  984 * Sets value of a component property.
  985 * Do not call this method. This is a PHP magic method that we override
  986 * to allow using the following syntax to set a property or attach an event handler
  987 * <pre>
  988 * this.propertyName=value;
  989 * this.eventName=callback;
  990 * </pre>
  991 * @param {String} name the property name or the event name
  992 * @param {Mixed} value the property value or callback
  993 * @throws {Yii.CException} if the property/event is not defined or the property is read only.
  994 * @see __get
  995 */
  996Yii.CComponent.prototype.set = function (name, value) {
  997		var setter, i, object, nameParts = [];
  998		if (name.indexOf(".") !== -1) {
  999			nameParts = name.split(".");
 1000			name = nameParts.pop();
 1001			return (this.get(nameParts.join("."))[name] = value);
 1002		}
 1003		if (this[name] !== undefined) {
 1004			return (this[name] = value);
 1005		}
 1006		
 1007		setter='set'+php.ucfirst(name);
 1008		if(php.method_exists(this,setter)) {
 1009			return this[setter](value);
 1010		}
 1011		else if(php.strncasecmp(name,'on',2)===0 && php.method_exists(this,name)) {
 1012			// duplicating getEventHandlers() here for performance
 1013			name=name.toLowerCase();
 1014			if(this._e[name] === undefined) {
 1015				this._e[name]=new Yii.CList();
 1016			}
 1017			return this._e[name].add(value);
 1018		}
 1019		else if(this._m !== null) {
 1020			for (i in this._m) {
 1021				if (this._m.hasOwnProperty(i)) {
 1022					
 1023					object = this._m[i];
 1024					
 1025					if(object.getEnabled() && (php.property_exists(object,name) || object.canSetProperty(name))) {
 1026						return (object.set(name,value));
 1027					}
 1028				}
 1029			}
 1030		}
 1031		if(php.method_exists(this,'get'+php.ucfirst(name))) {
 1032			throw new Yii.CException(Yii.t('yii','Property "{class}.{property}" is read only.',
 1033				{'{class}':this.getClassName(), '{property}':name}));
 1034		}
 1035		else {
 1036			throw new Yii.CException(Yii.t('yii','Property "{class}.{property}" is not defined.',
 1037				{'{class}':this.getClassName(), '{property}':name}));
 1038		}
 1039	};
 1040/**
 1041 * Checks if a property value is null.
 1042 * Do not call this method. This is a PHP magic method that we override
 1043 * to allow using isset() to detect if a component property is set or not.
 1044 * @param {String} name the property name or the event name
 1045 * @since 1.0.1
 1046 */
 1047Yii.CComponent.prototype.isset = function (name) {
 1048		var getter, i, object, nameParts = [], value;
 1049		if (name.indexOf(".") !== -1) {
 1050			nameParts = name.split(".");
 1051			name = nameParts.pop();
 1052			try {
 1053				value = this.get(nameParts.join("."))[name];
 1054				if (value !== undefined && value !== null) {
 1055					return true;
 1056				}
 1057				return false;
 1058			}
 1059			catch (e) {
 1060				return false;
 1061			}
 1062		}
 1063		if (this[name] !== undefined) {
 1064			return true;
 1065		}
 1066		getter='get'+php.ucfirst(name);
 1067		if(php.method_exists(this,getter)) {
 1068			return (this[getter]()!==null);
 1069		}
 1070		else if(php.strncasecmp(name,'on',2)===0 && php.method_exists(this,name))
 1071		{
 1072			name=name.toLowerCase();
 1073			return this._e !== null && this._e[name] !== undefined && this._e[name].getCount();
 1074		}
 1075		else if(this._m !== null) {
 1076			if(this._m[name] !== undefined) {
 1077				return true;
 1078			}
 1079			for (i in this._m) {
 1080				if (this._m.hasOwnProperty(i)) {
 1081					object = this._m[i];
 1082					if(object.getEnabled() && (php.property_exists(object,name) || object.canGetProperty(name))) {
 1083						return true;
 1084					}
 1085				}
 1086			}
 1087		}
 1088		return false;
 1089	};
 1090/**
 1091 * Sets a component property to be null.
 1092 * Do not call this method. This is a PHP magic method that we override
 1093 * to allow using unset() to set a component property to be null.
 1094 * @param {String} name the property name or the event name
 1095 * @throws {Yii.CException} if the property is read only.
 1096 * @since 1.0.1
 1097 */
 1098Yii.CComponent.prototype.unset = function (name) {
 1099		var setter, i, object, nameParts = [];
 1100		if (name.indexOf(".") !== -1) {
 1101			nameParts = name.split(".");
 1102			name = nameParts.pop();
 1103			object = this.get(nameParts.join("."))[name];
 1104			if (object.unset !== undefined) {
 1105				return object.unset(name);
 1106			} 
 1107			return (this.get(nameParts.join("."))[name] = null);
 1108		}
 1109		setter='set'+php.ucfirst(name);
 1110		if (this[name] !== undefined) {
 1111			this[name] = null; 
 1112			return;
 1113		}
 1114		else if(php.method_exists(this,setter)) {
 1115			this[setter](null);
 1116		}
 1117		else if(php.strncasecmp(name,'on',2)===0 && php.method_exists(this,name)) {
 1118			delete this._e[name.toLowerCase()];
 1119		}
 1120		else if(this._m !== null)
 1121		{
 1122			if(this._m[name] !== undefined) {
 1123				this.detachBehavior(name);
 1124			}
 1125			else
 1126			{
 1127				for (i in this._m) {
 1128					if (this._m.hasOwnProperty(i)) {
 1129						object = this._m[i];
 1130						if(object.getEnabled())	{
 1131							if(php.property_exists(object,name)) {
 1132								return (object[name]=null);
 1133							}
 1134							else if(object.canSetProperty(name)) {
 1135								return object[setter](null);
 1136							}
 1137						}
 1138					}
 1139				}
 1140			}
 1141		}
 1142		else if(php.method_exists(this,'get'+name)) {
 1143			throw new Yii.CException(Yii.t('yii','Property "{class}.{property}" is read only.',
 1144				{'{class}':this.getClassName(), '{property}':name}));
 1145		}
 1146	};
 1147/**
 1148 * Calls the named method which is not a class method.
 1149 * Do not call this method. This is a PHP magic method that we override
 1150 * to implement the behavior feature.
 1151 * @param {String} name the method name
 1152 * @param {Array} parameters method parameters
 1153 * @returns {Mixed} the method return value
 1154 * @since 1.0.2
 1155 */
 1156Yii.CComponent.prototype.call = function (name, parameters) {
 1157		var i, object;
 1158		if (this[name] !== undefined) {
 1159			return php.call_user_func_array([this,name],parameters);
 1160		}
 1161		else if(this._m!==null) {
 1162			for (i in this._m) {
 1163				if (this._m.hasOwnProperty(i)) {
 1164					object = this._m[i];
 1165					if(object.getEnabled() && php.method_exists(object,name)) {
 1166						return php.call_user_func_array([object,name],parameters);
 1167					}
 1168				}
 1169			}
 1170		}
 1171		
 1172		throw new Yii.CException(Yii.t('yii','{class} does not have a method named "{name}".',
 1173			{'{class}':this.getClassName(), '{name}':name}));
 1174	};
 1175/**
 1176 * Returns the named behavior object.
 1177 * The name 'asa' stands for 'as a'.
 1178 * @param {String} behavior the behavior name
 1179 * @returns {IBehavior} the behavior object, or null if the behavior does not exist
 1180 * @since 1.0.2
 1181 */
 1182Yii.CComponent.prototype.asa = function (behavior) {
 1183		return this._m !== null && this._m[behavior] !== undefined ? this._m[behavior] : null;
 1184	};
 1185/**
 1186 * Attaches a list of behaviors to the component.
 1187 * Each behavior is indexed by its name and should be an instance of
 1188 * {@link IBehavior}, a string specifying the behavior class, or an
 1189 * array of the following structure:
 1190 * <pre>
 1191 * {
 1192 *     'class':'path.to.BehaviorClass',
 1193 *     'property1':'value1',
 1194 *     'property2':'value2',
 1195 * }
 1196 * </pre>
 1197 * @param {Array} behaviors list of behaviors to be attached to the component
 1198 * @since 1.0.2
 1199 */
 1200Yii.CComponent.prototype.attachBehaviors = function (behaviors) {
 1201		var name, behavior;
 1202		for (name in behaviors) {
 1203			if (behaviors.hasOwnProperty(name)) {
 1204				behavior = behaviors[name];
 1205				this.attachBehavior(name,behavior);
 1206			}
 1207		}
 1208	};
 1209/**
 1210 * Detaches all behaviors from the component.
 1211 * @since 1.0.2
 1212 */
 1213Yii.CComponent.prototype.detachBehaviors = function () {
 1214		var name, behavior;
 1215		if(this._m!==null) {
 1216			for (name in this._m) {
 1217				if (this._m.hasOwnProperty(name)) {
 1218					behavior = this._m[name];
 1219					this.detachBehavior(name);
 1220				}
 1221			}
 1222			this._m=null;
 1223		}
 1224	};
 1225/**
 1226 * Attaches a behavior to this component.
 1227 * This method will create the behavior object based on the given
 1228 * configuration. After that, the behavior object will be initialized
 1229 * by calling its {@link IBehavior::attach} method.
 1230 * @param {String} name the behavior's name. It should uniquely identify this behavior.
 1231 * @param {Mixed} behavior the behavior configuration. This is passed as the first
 1232 * parameter to {@link YiiBase::createComponent} to create the behavior object.
 1233 * @returns {IBehavior} the behavior object
 1234 * @since 1.0.2
 1235 */
 1236Yii.CComponent.prototype.attachBehavior = function (name, behavior) {
 1237		if(!(behavior instanceof Yii.CBehavior)) {
 1238			behavior=Yii.createComponent(behavior);
 1239		}
 1240		behavior.setEnabled(true);
 1241		behavior.attach(this);
 1242		if (this._m === null) {
 1243			this._m = {};
 1244		}
 1245		return (this._m[name]=behavior);
 1246	};
 1247/**
 1248 * Detaches a behavior from the component.
 1249 * The behavior's {@link IBehavior::detach} method will be invoked.
 1250 * @param {String} name the behavior's name. It uniquely identifies the behavior.
 1251 * @returns {IBehavior} the detached behavior. Null if the behavior does not exist.
 1252 * @since 1.0.2
 1253 */
 1254Yii.CComponent.prototype.detachBehavior = function (name) {
 1255		var behavior;
 1256		if(this._m[name] !== undefined) {
 1257			this._m[name].detach(this);
 1258			behavior=this._m[name];
 1259			delete this._m[name];
 1260			return behavior;
 1261		}
 1262	};
 1263/**
 1264 * Enables all behaviors attached to this component.
 1265 * @since 1.0.2
 1266 */
 1267Yii.CComponent.prototype.enableBehaviors = function () {
 1268		var i, behavior;
 1269		if(this._m!==null) {
 1270			for (i in this._m) {
 1271				if (this._m.hasOwnProperty(i)) {
 1272					behavior = this._m[i];
 1273					behavior.setEnabled(true);
 1274				}
 1275			}
 1276		}
 1277	};
 1278/**
 1279 * Disables all behaviors attached to this component.
 1280 * @since 1.0.2
 1281 */
 1282Yii.CComponent.prototype.disableBehaviors = function () {
 1283		var i, behavior;
 1284		if(this._m!==null) {
 1285			for (i in this._m) {
 1286				if (this._m.hasOwnProperty(i)) {
 1287					behavior = this._m[i];
 1288					behavior.setEnabled(false);
 1289				}
 1290			}
 1291		}
 1292	};
 1293/**
 1294 * Enables an attached behavior.
 1295 * A behavior is only effective when it is enabled.
 1296 * A behavior is enabled when first attached.
 1297 * @param {String} name the behavior's name. It uniquely identifies the behavior.
 1298 * @since 1.0.2
 1299 */
 1300Yii.CComponent.prototype.enableBehavior = function (name) {
 1301		if(this._m !== null && this._m[name] !== undefined) {
 1302			this._m[name].setEnabled(true);
 1303		}
 1304	};
 1305/**
 1306 * Disables an attached behavior.
 1307 * A behavior is only effective when it is enabled.
 1308 * @param {String} name the behavior's name. It uniquely identifies the behavior.
 1309 * @since 1.0.2
 1310 */
 1311Yii.CComponent.prototype.disableBehavior = function (name) {
 1312		if(this._m !== null && this._m[name] !== undefined) {
 1313			this._m[name].setEnabled(false);
 1314		}
 1315	};
 1316/**
 1317 * Determines whether a property is defined.
 1318 * A property is defined if there is a getter or setter method
 1319 * defined in the class. Note, property names are case-insensitive.
 1320 * @param {String} name the property name
 1321 * @returns {Boolean} whether the property is defined
 1322 * @see canGetProperty
 1323 * @see canSetProperty
 1324 */
 1325Yii.CComponent.prototype.hasProperty = function (name) {
 1326		return this[name] !== undefined || php.method_exists(this,'get'+php.ucfirst(name)) || php.method_exists(this,'set'+php.ucfirst(name));
 1327	};
 1328/**
 1329 * Determines whether a property can be read.
 1330 * A property can be read if the class has a getter method
 1331 * for the property name. Note, property name is case-insensitive.
 1332 * @param {String} name the property name
 1333 * @returns {Boolean} whether the property can be read
 1334 * @see canSetProperty
 1335 */
 1336Yii.CComponent.prototype.canGetProperty = function (name) {
 1337		return this[name] !== undefined || php.method_exists(this,'get'+php.ucfirst(name));
 1338	};
 1339/**
 1340 * Determines whether a property can be set.
 1341 * A property can be written if the class has a setter method
 1342 * for the property name. Note, property name is case-insensitive.
 1343 * @param {String} name the property name
 1344 * @returns {Boolean} whether the property can be written
 1345 * @see canGetProperty
 1346 */
 1347Yii.CComponent.prototype.canSetProperty = function (name) {
 1348		return this[name] !== undefined || php.method_exists(this,'set'+php.ucfirst(name));
 1349	};
 1350/**
 1351 * Determines whether an event is defined.
 1352 * An event is defined if the class has a method named like 'onXXX'.
 1353 * Note, event name is case-insensitive.
 1354 * @param {String} name the event name
 1355 * @returns {Boolean} whether an event is defined
 1356 */
 1357Yii.CComponent.prototype.hasEvent = function (name) {
 1358		return !php.strncasecmp(name,'on',2) && php.method_exists(this,name);
 1359	};
 1360/**
 1361 * Checks whether the named event has attached handlers.
 1362 * @param {String} name the event name
 1363 * @returns {Boolean} whether an event has been attached one or several handlers
 1364 */
 1365Yii.CComponent.prototype.hasEventHandler = function (name) {
 1366		
 1367		return this._e !== null && this._e[name] !== undefined && this._e[name].getCount()>0;
 1368	};
 1369/**
 1370 * Returns the list of attached event handlers for an event.
 1371 * @param {String} name the event name
 1372 * @returns {Yii.CList} list of attached event handlers for the event
 1373 * @throws {Yii.CException} if the event is not defined
 1374 */
 1375Yii.CComponent.prototype.getEventHandlers = function (name) {
 1376		if(this.hasEvent(name))	{
 1377			
 1378			if (this._e === null) {
 1379				this._e = {};
 1380			}
 1381			if(this._e[name] === undefined) {
 1382				this._e[name]=new Yii.CList();
 1383			}
 1384			return this._e[name];
 1385		}
 1386		else {
 1387			throw new Yii.CException(Yii.t('yii','Event "{class}.{event}" is not defined.',
 1388				{'{class}':this.getClassName(), '{event}':name}));
 1389		}
 1390	};
 1391/**
 1392 * Attaches an event handler to an event.
 1393 * 
 1394 * An event handler must be a valid PHP callback, i.e., a string referring to
 1395 * a global function name, or an array containing two elements with
 1396 * the first element being an object and the second element a method name
 1397 * of the object.
 1398 * 
 1399 * An event handler must be defined with the following signature,
 1400 * <pre>
 1401 * function handlerName(event) {}
 1402 * </pre>
 1403 * where $event includes parameters associated with the event.
 1404 * 
 1405 * This is a convenient method of attaching a handler to an event.
 1406 * It is equivalent to the following code:
 1407 * <pre>
 1408 * component.getEventHandlers(eventName).add(eventHandler);
 1409 * </pre>
 1410 * 
 1411 * Using {@link getEventHandlers}, one can also specify the excution order
 1412 * of multiple handlers attaching to the same event. For example:
 1413 * <pre>
 1414 * component.getEventHandlers(eventName).insertAt(0,eventHandler);
 1415 * </pre>
 1416 * makes the handler to be invoked first.
 1417 * 
 1418 * @param {String} name the event name
 1419 * @param {Yii.Callback} handler the event handler
 1420 * @throws {Yii.CException} if the event is not defined
 1421 * @see detachEventHandler
 1422 */
 1423Yii.CComponent.prototype.attachEventHandler = function (name, handler) {
 1424		this.getEventHandlers(name).add(handler);
 1425	};
 1426/**
 1427 * Detaches an existing event handler.
 1428 * This method is the opposite of {@link attachEventHandler}.
 1429 * @param {String} name event name
 1430 * @param {Yii.Callback} handler the event handler to be removed
 1431 * @returns {Boolean} if the detachment process is successful
 1432 * @see attachEventHandler
 1433 */
 1434Yii.CComponent.prototype.detachEventHandler = function (name, handler) {
 1435		if(this.hasEventHandler(name)) {
 1436			return this.getEventHandlers(name).remove(handler)!==false;
 1437		}
 1438		else {
 1439			return false;
 1440		}
 1441	};
 1442/**
 1443 * Raises an event.
 1444 * This method represents the happening of an event. It invokes
 1445 * all attached handlers for the event.
 1446 * @param {String} name the event name
 1447 * @param {Yii.CEvent} event the event parameter
 1448 * @throws {Yii.CException} if the event is undefined or an event handler is invalid.
 1449 */
 1450Yii.CComponent.prototype.raiseEvent = function (name, event) {
 1451		var i, handler, object, method, limit;
 1452		if(this._e !== null && this._e[name] !== undefined)	{
 1453			limit = this._e[name].length;
 1454			for (i = 0; i < limit; i++) {
 1455				handler = this._e[name][i];
 1456				if(typeof(handler) === 'string') {
 1457					php.call_user_func(handler,event);
 1458				}
 1459				if(Object.prototype.toString.call(handler) === '[object Array]') {
 1460					// an array: 0 - object, 1 - method name
 1461					object = handler[0];
 1462					method = handler[1];
 1463					
 1464					if(typeof(object) === 'string') {	// static method call
 1465						php.call_user_func(handler,event);
 1466					}
 1467					else if(php.method_exists(object,method)) {
 1468				
 1469						object[method](event);
 1470					}
 1471					else {
 1472						throw new Yii.CException(Yii.t('yii','Event "{class}.{event}" is attached with an invalid handler "{handler}".',
 1473							{'{class}':this.getClassName(), '{event}':name, '{handler}':handler[1]}));
 1474					}
 1475				}
 1476				else if (typeof handler === "function") { // callback function
 1477					php.call_user_func(handler,event);
 1478				}
 1479				else {
 1480					console.log(i);
 1481					console.log(name);
 1482					console.log(handler);
 1483					throw new Yii.CException(Yii.t('yii','Event "{class}.{event}" is attached with an invalid handler "{handler}".',
 1484						{'{class}':this.getClassName(), '{event}':name, '{handler}':handler}));
 1485				}
 1486				// stop further handling if param.handled is set true
 1487				if((event instanceof Yii.CEvent) && event.handled) {
 1488					return;
 1489				}
 1490				
 1491			}
 1492		}
 1493		else if(YII_DEBUG && !this.hasEvent(name)) {
 1494			throw new Yii.CException(Yii.t('yii','Event "{class}.{event}" is not defined.',
 1495				{'{class}':this.getClassName(), '{event}':name}));
 1496		}
 1497	};
 1498/**
 1499 * Evaluates a PHP expression or callback under the context of this component.
 1500 * 
 1501 * Valid PHP callback can be class method name in the form of
 1502 * array(ClassName/Object, MethodName), or anonymous function (only available in PHP 5.3.0 or above).
 1503 * 
 1504 * If a PHP callback is used, the corresponding function/method signature should be
 1505 * <pre>
 1506 * function foo(param1, param2, +++, component) { +++ }
 1507 * </pre>
 1508 * where the array elements in the second parameter to this method will be passed
 1509 * to the callback as $param1, $param2, ...; and the last parameter will be the component itself.
 1510 * 
 1511 * If a PHP expression is used, the second parameter will be "extracted" into PHP variables
 1512 * that can be directly accessed in the expression. See {@link http://us.php.net/manual/en/function.extract.php PHP extract}
 1513 * for more details. In the expression, the component object can be accessed using $this.
 1514 * 
 1515 * @param {Mixed} _expression_ a PHP expression or PHP callback to be evaluated.
 1516 * @param {Array} _data_ additional parameters to be passed to the above expression/callback.
 1517 * @returns {Mixed} the expression result
 1518 * @since 1.1.0
 1519 */
 1520Yii.CComponent.prototype.evaluateExpression = function (_expression_, _data_) {
 1521		if (_data_ === undefined) {
 1522			_data_ = [];
 1523		}
 1524		if(typeof(_expression_) === 'string')
 1525		{
 1526			php.extract(_data_);
 1527			return eval('return '+_expression_+';');
 1528		}
 1529		else
 1530		{
 1531			_data_.push(this);
 1532			return php.call_user_func_array(_expression_, _data_);
 1533		}
 1534	}/*global Yii, php, $, jQuery, alert, clearInterval, clearTimeout, document, event, frames, history, Image, location, name, navigator, Option, parent, screen, setInterval, setTimeout, window, XMLHttpRequest */
 1535/**
 1536 * CApplicationComponent is the base class for application component classes.
 1537 * 
 1538 * CApplicationComponent implements the basic methods required by {@link IApplicationComponent}.
 1539 * 
 1540 * When developing an application component, try to put application component initialization code in
 1541 * the {@link init()} method instead of the constructor. This has the advantage that
 1542 * the application component can be customized through application configuration.
 1543 * 
 1544 * @originalAuthor Qiang Xue <qiang.xue@gmail.com>
 1545 * @version $Id: CApplicationComponent.php 2799 2011-01-01 19:31:13Z qiang.xue $
 1546 * @package system.base
 1547 * @since 1.0
 1548 * @author Charles Pick
 1549 * @class
 1550 * @extends Yii.CComponent
 1551 */
 1552Yii.CApplicationComponent = function CApplicationComponent() {
 1553};
 1554Yii.CApplicationComponent.prototype = new Yii.CComponent();
 1555Yii.CApplicationComponent.prototype.constructor =  Yii.CApplicationComponent;
 1556/**
 1557 * @var {Array} the behaviors that should be attached to this component.
 1558 * The behaviors will be attached to the component when {@link init} is called.
 1559 * Please refer to {@link CModel::behaviors} on how to specify the value of this property.
 1560 * @since 1.0.2
 1561 */
 1562Yii.CApplicationComponent.prototype.behaviors = [];
 1563Yii.CApplicationComponent.prototype._initialized = false;
 1564/**
 1565 * Initializes the application component.
 1566 * This method is required by {@link IApplicationComponent} and is invoked by application.
 1567 * If you override this method, make sure to call the parent implementation
 1568 * so that the application component can be marked as initialized.
 1569 */
 1570Yii.CApplicationComponent.prototype.init = function () {
 1571		this.attachBehaviors(this.behaviors);
 1572		this._initialized=true;
 1573	};
 1574/**
 1575 * Checks if this application component bas been initialized.
 1576 * @returns {Boolean} whether this application component has been initialized (ie, {@link init()} is invoked).
 1577 */
 1578Yii.CApplicationComponent.prototype.getIsInitialized = function () {
 1579		return this._initialized;
 1580};/*global Yii, php, $, jQuery, alert, clearInterval, clearTimeout, document, event, frames, history, Image, location, name, navigator, Option, parent, screen, setInterval, setTimeout, window, XMLHttpRequest */
 1581/**
 1582 * CException represents a generic exception for all purposes.
 1583 * 
 1584 * @originalAuthor Qiang Xue <qiang.xue@gmail.com>
 1585 * @version $Id: CException.php 2799 2011-01-01 19:31:13Z qiang.xue $
 1586 * @package system.base
 1587 * @since 1.0
 1588 * @author Charles Pick
 1589 * @class
 1590 * @extends Yii.Exception
 1591 */
 1592Yii.CException = function CException (message) {
 1593	if (message === false) {
 1594		return;
 1595	}
 1596	this.message = message;
 1597	
 1598
 1599};
 1600Yii.CException.prototype = new Error();
 1601Yii.CException.prototype.constructor = Yii.CException;
 1602/**
 1603 * Gets a basic stack trace
 1604 * @returns {Array} An array of function calls
 1605 */
 1606Yii.CException.prototype.stacktrace = function () {
 1607	function st2(f) {
 1608		return !f ? [] : 
 1609		st2(f.caller).concat([f.toString().split('(')[0].substring(9) + '(' + Array.prototype.slice.call(f.arguments).join(',') + ')']);
 1610	}
 1611	return st2(arguments.callee.caller);
 1612};
 1613
 1614/**
 1615 * Gets the stack trace as a string
 1616 * @returns {String} the stack trace, latest item first
 1617 */
 1618Yii.CException.prototype.getTraceAsString = function () {
 1619	return this.stacktrace().reverse().join("\n");
 1620};
 1621
 1622/**
 1623 * Gets the exception message
 1624 * @returns {String} the message associated with this error
 1625 */
 1626Yii.CException.prototype.getMessage = function () {
 1627	return this.message;
 1628}
 1629/*global Yii, php, $, jQuery, alert, clearInterval, clearTimeout, document, event, frames, history, Image, location, name, navigator, Option, parent, screen, setInterval, setTimeout, window, XMLHttpRequest */
 1630/**
 1631 * CEvent is the base class for all event classes.
 1632 * 
 1633 * It encapsulates the parameters associated with an event.
 1634 * The {@link sender} property describes who raises the event.
 1635 * And the {@link handled} property indicates if the event is handled.
 1636 * If an event handler sets {@link handled} to true, those handlers
 1637 * that are not invoked yet will not be invoked anymore.
 1638 * 
 1639 * @originalAuthor Qiang Xue <qiang.xue@gmail.com>
 1640 * @version $Id: CComponent.php 3066 2011-03-13 14:22:55Z qiang.xue $
 1641 * @package system.base
 1642 * @since 1.0
 1643 * @author Charles Pick
 1644 * @class
 1645 * @extends Yii.CComponent
 1646 */
 1647Yii.CEvent = function CEvent(sender, params) {
 1648	if (sender !== false) {
 1649		this.construct(sender, params);
 1650	}
 1651};
 1652Yii.CEvent.prototype = new Yii.CComponent();
 1653Yii.CEvent.prototype.constructor =  Yii.CEvent;
 1654/**
 1655 * @var {Object} the sender of this event
 1656 */
 1657Yii.CEvent.prototype.sender = null;
 1658/**
 1659 * @var {Boolean} whether the event is handled. Defaults to false.
 1660 * When a handler sets this true, the rest of the uninvoked event handlers will not be invoked anymore.
 1661 */
 1662Yii.CEvent.prototype.handled = false;
 1663/**
 1664 * @var {Mixed} additional event parameters.
 1665 * @since 1.1.7
 1666 */
 1667Yii.CEvent.prototype.params = null;
 1668/**
 1669 * Constructor.
 1670 * @param {Mixed} sender sender of the event
 1671 * @param {Mixed} params additional parameters for the event
 1672 */
 1673Yii.CEvent.prototype.construct = function (sender, params) {
 1674	if (sender === undefined) {
 1675		sender = null;
 1676	}
 1677	if (params === undefined) {
 1678		params = null;
 1679	}
 1680	this.sender=sender;
 1681	this.params=params;
 1682};/*global Yii, php, $, jQuery, alert, clearInterval, clearTimeout, document, event, frames, history, Image, location, name, navigator, Option, parent, screen, setInterval, setTimeout, window, XMLHttpRequest */
 1683/**
 1684 * CEnumerable is the base class for all enumerable types.
 1685 * 
 1686 * To define an enumerable type, extend CEnumberable and define string constants.
 1687 * Each constant represents an enumerable value.
 1688 * The constant name must be the same as the constant value.
 1689 * For example,
 1690 * <pre>
 1691 * class TextAlign extends Yii.CEnumerable
 1692 * {
 1693 *     const Left='Left';
 1694 *     const Right='Right';
 1695 * }
 1696 * </pre>
 1697 * Then, one can use the enumerable values such as TextAlign::Left and
 1698 * TextAlign::Right.
 1699 * 
 1700 * @originalAuthor Qiang Xue <qiang.xue@gmail.com>
 1701 * @version $Id: CComponent.php 3066 2011-03-13 14:22:55Z qiang.xue $
 1702 * @package system.base
 1703 * @since 1.0
 1704 * @author Charles Pick
 1705 * @class
 1706 */
 1707Yii.CEnumerable = function CEnumerable () {
 1708};
 1709/*global Yii, php, $, jQuery, alert, clearInterval, clearTimeout, document, event, frames, history, Image, location, name, navigator, Option, parent, screen, setInterval, setTimeout, window, XMLHttpRequest */
 1710/**
 1711 * CModule is the base class for module and application classes.
 1712 * 
 1713 * CModule mainly manages application components and sub-modules.
 1714 * 
 1715 * @originalAuthor Qiang Xue <qiang.xue@gmail.com>
 1716 * @version $Id: CModule.php 3001 2011-02-24 16:42:44Z alexander.makarow $
 1717 * @package system.base
 1718 * @since 1.0.4
 1719 * @author Charles Pick
 1720 * @class
 1721 * @extends Yii.CComponent
 1722 */
 1723Yii.CModule = function CModule (id, parent, config) {
 1724	if (id !== false) {
 1725		this.models = {};
 1726		this.views = {};
 1727		this.controllers = {};
 1728		
 1729		this.construct(id, parent, config);
 1730	}
 1731};
 1732Yii.CModule.prototype = new Yii.CComponent();
 1733Yii.CModule.prototype.constructor =  Yii.CModule;
 1734/**
 1735 * @var {Array} the IDs of the application components that should be preloaded.
 1736 */
 1737Yii.CModule.prototype.preload = [];
 1738/**
 1739 * @var {Array} the behaviors that should be attached to the module.
 1740 * The behaviors will be attached to the module when {@link init} is called.
 1741 * Please refer to {@link CModel::behaviors} on how to specify the value of this property.
 1742 */
 1743Yii.CModule.prototype.behaviors = {};
 1744Yii.CModule.prototype._id = null;
 1745Yii.CModule.prototype._parentModule = null;
 1746Yii.CModule.prototype._basePath = null;
 1747Yii.CModule.prototype._modulePath = null;
 1748Yii.CModule.prototype._params = null;
 1749Yii.CModule.prototype._modules = {};
 1750Yii.CModule.prototype._moduleConfig = {};
 1751Yii.CModule.prototype._components = {};
 1752Yii.CModule.prototype._componentConfig = {};
 1753/**
 1754 * jQuery events to delegate for this module.
 1755 * Array should be of the following format:
 1756 * <pre>
 1757 * [
 1758 * 	['#selector a.someLink', 'click', function (e) { alert("clicked!")}],
 1759 * 	['#selector form', 'submit', function (e) { alert('Submitted!'); e.preventDefault(); }]
 1760 * ] 
 1761 * </pre>
 1762 * These events will be bound to their selectors when the module is run
 1763 * @var Array
 1764 */
 1765Yii.CModule.prototype.delegates = [];
 1766
 1767/**
 1768 * Holds a list of models belonging to this module
 1769 */
 1770Yii.CModule.prototype.models = {};
 1771/**
 1772 * Holds a list of views belonging to this module
 1773 */
 1774Yii.CModule.prototype.views = {};
 1775/**
 1776 * Holds a list of controllers belonging to this module
 1777 */
 1778Yii.CModule.prototype.controllers = {};
 1779/**
 1780 * Constructor.
 1781 * @param {String} id the ID of this module
 1782 * @param {Yii.CModule} parent the parent module (if any)
 1783 * @param {Mixed} config the module configuration. It can be either an array or
 1784 * the path of a PHP file returning the configuration array.
 1785 */
 1786Yii.CModule.prototype.construct = function (id, parent, config) {
 1787		if (config === undefined) {
 1788			config = {};
 1789		}
 1790		this._id=id;
 1791		this._parentModule=parent;
 1792		// set basePath at early as possible to avoid trouble
 1793		
 1794		if(config.basePath !== undefined) {
 1795			this.setBasePath(config.basePath);
 1796			delete config.basePath;
 1797		}
 1798		Yii.setPathOfAlias(id,this.getBasePath());
 1799		this.preinit();
 1800		this.configure(config);
 1801		this.attachBehaviors(this.behaviors);
 1802		this.preloadComponents();
 1803		this.init();
 1804	};
 1805/**
 1806 * Getter magic method.
 1807 * This method is overridden to support accessing application components
 1808 * like reading module properties.
 1809 * @param {String} name application component or property name
 1810 * @returns {Mixed} the named property value
 1811 */
 1812Yii.CModule.prototype.get = function (name) {
 1813		if(this.hasComponent(name)) {
 1814			return this.getComponent(name);
 1815		}
 1816		else {
 1817			return Yii.CComponent.prototype.get.call(this, name);
 1818		}
 1819	};
 1820
 1821
 1822
 1823/**
 1824 * Checks if a property value is null.
 1825 * This method overrides the parent implementation by checking
 1826 * if the named application component is loaded.
 1827 * @param {String} name the property name or the event name
 1828 * @returns {Boolean} whether the property value is null
 1829 */
 1830Yii.CModule.prototype.isset = function (name) {
 1831		if(this.hasComponent(name)) {
 1832			return this.getComponent(name)!==null;
 1833		}
 1834		else {
 1835			return Yii.CComponent.prototype.isset.call(this, name);
 1836		}
 1837	};
 1838/**
 1839 * Returns the module ID.
 1840 * @returns {String} the module ID.
 1841 */
 1842Yii.CModule.prototype.getId = function () {
 1843		return this._id;
 1844	};
 1845/**
 1846 * Sets the module ID.
 1847 * @param {String} id the module ID
 1848 */
 1849Yii.CModule.prototype.setId = function (id) {
 1850		this._id=id;
 1851	};
 1852/**
 1853 * Returns the root directory of the module.
 1854 * @returns {String} the root directory of the module. Defaults to the directory containing the module class.
 1855 */
 1856Yii.CModule.prototype.getBasePath = function () {
 1857		var classVar;
 1858		if(this._basePath===null) {
 1859			classVar=new ReflectionClass(php.get_class(this));
 1860			this._basePath=php.dirname(classVar.getFileName());
 1861		}
 1862		return this._basePath;
 1863	};
 1864/**
 1865 * Sets the root directory of the module.
 1866 * This method can only be invoked at the beginning of the constructor.
 1867 * @param {String} path the root directory of the module.
 1868 */
 1869Yii.CModule.prototype.setBasePath = function (path) {
 1870		this._basePath=path;
 1871	};
 1872/**
 1873 * Returns user-defined parameters.
 1874 * @returns {Yii.CAttributeCollection} the list of user-defined parameters
 1875 */
 1876Yii.CModule.prototype.getParams = function () {
 1877		if(this._params!==null) {
 1878			return this._params;
 1879		}
 1880		else
 1881		{
 1882			this._params=new Yii.CAttributeCollection();
 1883			this._params.caseSensitive=true;
 1884			return this._params;
 1885		}
 1886	};
 1887/**
 1888 * Sets user-defined parameters.
 1889 * @param {Array} value user-defined parameters. This should be in name-value pairs.
 1890 */
 1891Yii.CModule.prototype.setParams = function (value) {
 1892		var params, k, v;
 1893		params=this.getParams();
 1894		for (k in value) {
 1895			if (value.hasOwnProperty(k)) {
 1896				v = value[k];
 1897				params.add(k,v);
 1898			}
 1899		}
 1900	};
 1901/**
 1902 * Returns the directory that contains the application modules.
 1903 * @returns {String} the directory that contains the application modules. Defaults to the 'modules' subdirectory of {@link basePath}.
 1904 */
 1905Yii.CModule.prototype.getModulePath = function () {
 1906		if(this._modulePath!==null) {
 1907			return this._modulePath;
 1908		}
 1909		else {
 1910			return (this._modulePath=this.getBasePath()+"/"+'modules');
 1911		}
 1912	};
 1913/**
 1914 * Sets the directory that contains the application modules.
 1915 * @param {String} value the directory that contains the application modules.
 1916 */
 1917Yii.CModule.prototype.setModulePath = function (value) {
 1918		this._modulePath = value;
 1919		
 1920	};
 1921/**
 1922 * Sets the aliases that are used in the module.
 1923 * @param {Array} aliases list of aliases to be imported
 1924 */
 1925Yii.CModule.prototype.setImport = function (aliases) {
 1926		var i, alias;
 1927		for (i in aliases) {
 1928			if (aliases.hasOwnProperty(i)) {
 1929				alias = aliases[i];
 1930				Yii.imports(alias);
 1931			}
 1932		}
 1933	};
 1934/**
 1935 * Defines the root aliases.
 1936 * @param {Array} mappings list of aliases to be defined. The array keys are root aliases,
 1937 * while the array values are paths or aliases corresponding to the root aliases.
 1938 * For example,
 1939 * <pre>
 1940 * {
 1941 *    'models':'application.models',              // an existing alias
 1942 *    'extensions':'application.extensions',      // an existing alias
 1943 *    'backend':php.dirname(__FILE__)+'/../backend',  // a directory
 1944 * }
 1945 * </pre>
 1946 * @since 1.0.5
 1947 */
 1948Yii.CModule.prototype.setAliases = function (mappings) {
 1949		var path, alias, name;
 1950		for (name in mappings) {
 1951			if (mappings.hasOwnProperty(name)) {
 1952				alias = mappings[name];
 1953				if((path=Yii.getPathOfAlias(alias))!==false) {
 1954					Yii.setPathOfAlias(name,path);
 1955				}
 1956				else {
 1957					Yii.setPathOfAlias(name,alias);
 1958				}
 1959			}
 1960		}
 1961	};
 1962/**
 1963 * Returns the parent module.
 1964 * @returns {Yii.CModule} the parent module. Null if this module does not have a parent.
 1965 */
 1966Yii.CModule.prototype.getParentModule = function () {
 1967		return this._parentModule;
 1968	};
 1969/**
 1970 * Retrieves the named application module.
 1971 * The module has to be declared in {@link modules}. A new instance will be created
 1972 * when calling this method with the given ID for the first time.
 1973 * @param {String} id application module ID (case-sensitive)
 1974 * @returns {Yii.CModule} the module instance, null if the module is disabled or does not exist.
 1975 */
 1976Yii.CModule.prototype.getModule = function (id) {
 1977		var config, classVar, module;
 1978		if(this._modules[id] !== undefined) {
 1979			return this._modules[id];
 1980		}
 1981		else if(this._moduleConfig[id] !== undefined) {
 1982			config=this._moduleConfig[id];
 1983			if(config.enabled === undefined || config.enabled) {
 1984				Yii.trace("Loading \"" + id + "\" module",'system.base.CModule');
 1985				classVar=config['class'];
 1986				delete config['class'];
 1987				if(this===Yii.app()) {
 1988					module=Yii.createComponent(classVar,id,null,config);
 1989				}
 1990				else {
 1991					module=Yii.createComponent(classVar,this.getId()+'/'+id,this,config);
 1992				}
 1993				return (this._modules[id]=module);
 1994			}
 1995		}
 1996	};
 1997/**
 1998 * Returns a value indicating whether the specified module is installed.
 1999 * @param {String} id the module ID
 2000 * @returns {Boolean} whether the specified module is installed.
 2001 * @since 1.1.2
 2002 */
 2003Yii.CModule.prototype.hasModule = function (id) {
 2004		return this._moduleConfig[id] !== undefined || this._modules[id] !== undefined;
 2005	};
 2006/**
 2007 * Returns the configuration of the currently installed modules.
 2008 * @returns {Array} the configuration of the currently installed modules (module ID => configuration)
 2009 */
 2010Yii.CModule.prototype.getModules = function () {
 2011		return this._moduleConfig;
 2012	};
 2013/**
 2014 * Configures the sub-modules of this module.
 2015 * 
 2016 * Call this method to declare sub-modules and configure them with their initial property values.
 2017 * The parameter should be an array of module configurations. Each array element represents a single module,
 2018 * which can be either a string representing the module ID or an ID-configuration pair representing
 2019 * a module with the specified ID and the initial property values.
 2020 * 
 2021 * For example, the following array declares two modules:
 2022 * <pre>
 2023 * {
 2024 *     'admin',                // a single module ID
 2025 *     'payment':{       // ID-configuration pair
 2026 *         'server':'paymentserver.com',
 2027 *     },
 2028 * }
 2029 * </pre>
 2030 * 
 2031 * By default, the module class is determined using the expression <code>ucfirst($moduleID).'Module'</code>.
 2032 * And the class file is located under <code>modules/$moduleID</code>.
 2033 * You may override this default by explicitly specifying the 'class' option in the configuration.
 2034 * 
 2035 * You may also enable or disable a module by specifying the 'enabled' option in the configuration.
 2036 * 
 2037 * @param {Array} modules module configurations.
 2038 */
 2039Yii.CModule.prototype.setModules = function (modules) {
 2040		var id, module;
 2041		for (id in modules) {
 2042			if (modules.hasOwnProperty(id)) {
 2043				module = modules[id];
 2044				if(php.is_int(id)) {
 2045					id=module;
 2046					module={};
 2047				}
 2048				if(module['class'] === undefined) {
 2049					Yii.setPathOfAlias(id,this.getModulePath()+"/"+id);
 2050					module['class'] = id+'.'+php.ucfirst(id)+'Module';
 2051				}
 2052				if(this._moduleConfig[id] !== undefined) {
 2053					this._moduleConfig[id]=Yii.CMap.mergeArray(this._moduleConfig[id],module);
 2054				}
 2055				else {
 2056					this._moduleConfig[id]=module;
 2057				}
 2058			}
 2059		}
 2060	};
 2061/**
 2062 * Checks whether the named component exists.
 2063 * @param {String} id application component ID
 2064 * @returns {Boolean} whether the named application component exists (including both loaded and disabled.)
 2065 */
 2066Yii.CModule.prototype.hasComponent = function (id) {
 2067		return this._components[id] !== undefined || this._componentConfig[id] !== undefined;
 2068	};
 2069/**
 2070 * Retrieves the named application component.
 2071 * @param {String} id application component ID (case-sensitive)
 2072 * @param {Boolean} createIfNull whether to create the component if it doesn't exist yet. This parameter
 2073 * has been available since version 1.0.6.
 2074 * @returns {CApplicationComponent} the application component instance, null if the application component is disabled or does not exist.
 2075 * @see hasComponent
 2076 */
 2077Yii.CModule.prototype.getComponent = function (id, createIfNull) {
 2078		var config, component;
 2079		if (createIfNull === undefined) {
 2080			createIfNull = true;
 2081		}
 2082		if(this._components[id] !== undefined) {
 2083			return this._components[id];
 2084		}
 2085		else if(this._componentConfig[id] !== undefined && createIfNull) {
 2086			config=this._componentConfig[id];
 2087			if(config.enabled === undefined || config.enabled) {
 2088				Yii.trace("Loading \"" + id + "\" application component",'system.CModule');
 2089				
 2090				delete config.enabled;
 2091				component=Yii.createComponent(config);
 2092				
 2093				component.init();
 2094				return (this._components[id]=component);
 2095			}
 2096		}
 2097		
 2098	};
 2099/**
 2100 * Puts a component under the management of the module.
 2101 * The component will be initialized by calling its {@link CApplicationComponent::init() init()}
 2102 * method if it has not done so.
 2103 * @param {String} id component ID
 2104 * @param {CApplicationComponent} component the component to be added to the module.
 2105 * If this parameter is null, it will unload the component from the module.
 2106 */
 2107Yii.CModule.prototype.setComponent = function (id, component) {
 2108		if(component===null) {
 2109			delete this._components[id];
 2110		}
 2111		else {
 2112			this._components[id]=component;
 2113			if(!component.getIsInitialized()) {
 2114				component.init();
 2115			}
 2116		}
 2117	};
 2118/**
 2119 * Returns the application components.
 2120 * @param {Boolean} loadedOnly whether to return the loaded components only. If this is set false,
 2121 * then all components specified in the configuration will be returned, whether they are loaded or not.
 2122 * Loaded components will be returned as objects, while unloaded components as configuration arrays.
 2123 * This parameter has been available since version 1.1.3.
 2124 * @returns {Array} the application components (indexed by their IDs)
 2125 */
 2126Yii.CModule.prototype.getComponents = function (loadedOnly) {
 2127		if (loadedOnly === undefined) {
 2128			loadedOnly = true;
 2129		}
 2130		if(loadedOnly) {
 2131			return this._components;
 2132		}
 2133		else {
 2134			return php.array_merge(this._componentConfig, this._components);
 2135		}
 2136	};
 2137/**
 2138 * Sets the application components.
 2139 * 
 2140 * When a configuration is used to specify a component, it should consist of
 2141 * the component's initial property values (name-value pairs). Additionally,
 2142 * a component can be enabled (default) or disabled by specifying the 'enabled' value
 2143 * in the configuration.
 2144 * 
 2145 * If a configuration is specified with an ID that is the same as an existing
 2146 * component or configuration, the existing one will be replaced silently.
 2147 * 
 2148 * The following is the configuration for two components:
 2149 * <pre>
 2150 * {
 2151 *     'db':{
 2152 *         'class':'CDbConnection',
 2153 *         'connectionString':'sqlite:path/to/file.db',
 2154 *     },
 2155 *     'cache':{
 2156 *         'class':'CDbCache',
 2157 *         'connectionID':'db',
 2158 *         'enabled':!YII_DEBUG,  // enable caching in non-debug mode
 2159 *     ),
 2160 * }
 2161 * </pre>
 2162 * 
 2163 * @param {Array} components application components(id=>component configuration or instances)
 2164 * @param {Boolean} merge whether to merge the new component configuration with the existing one.
 2165 * Defaults to true, meaning the previously registered component configuration of the same ID
 2166 * will be merged with the new configuration. If false, the existing configuration will be replaced completely.
 2167 */
 2168Yii.CModule.prototype.setComponents = function (components, merge) {
 2169		var component, id;
 2170		if (merge === undefined) {
 2171			merge = true;
 2172		}
 2173		for (id in components) {
 2174			if (components.hasOwnProperty(id)) {
 2175				component = components[id];
 2176				if(component instanceof Yii.CApplicationComponent) {
 2177					this.setComponent(id,component);
 2178				}
 2179				else if(this._componentConfig[id] !== undefined && merge) {
 2180					this._componentConfig[id]=Yii.CMap.prototype.mergeArray(this._componentConfig[id],component);
 2181				}
 2182				else {
 2183					this._componentConfig[id]=component;
 2184				}
 2185			}
 2186		}
 2187	};
 2188/**
 2189 * Configures the module with the specified configuration.
 2190 * @param {Array} config the configuration array
 2191 */
 2192Yii.CModule.prototype.configure = function (config) {
 2193		var key, value;
 2194		if(typeof config === 'object')	{
 2195			for (key in config) {
 2196				if (config.hasOwnProperty(key)) {
 2197					value = config[key];
 2198					this.set(key,value);
 2199				}
 2200			}
 2201		}
 2202	};
 2203/**
 2204 * Loads static application components.
 2205 */
 2206Yii.CModule.prototype.preloadComponents = function () {
 2207		var i, id;
 2208		for (i in this.preload) {
 2209			if (this.preload.hasOwnProperty(i)) {
 2210				id = this.preload[i];
 2211				this.getComponent(id);
 2212			}
 2213		}
 2214	};
 2215/**
 2216 * Preinitializes the module.
 2217 * This method is called at the beginning of the module constructor.
 2218 * You may override this method to do some customized preinitialization work.
 2219 * Note that at this moment, the module is not configured yet.
 2220 * @see init
 2221 */
 2222Yii.CModule.prototype.preinit = function () {
 2223	};
 2224/**
 2225 * Initializes the module.
 2226 * This method is called at the end of the module constructor.
 2227 * Note that at this moment, the module has been configured, the behaviors
 2228 * have been attached and the application components have been registered.
 2229 * @see preinit
 2230 */
 2231Yii.CModule.prototype.init = function () {
 2232	Yii.forEach(this.delegates, function(i, item) {
 2233		jQuery("body").undelegate(item[0], item[1]).delegate(item[0], item[1], item[2]);
 2234	});
 2235};/*global Yii, php, $, jQuery, alert, clearInterval, clearTimeout, document, event, frames, history, Image, location, name, navigator, Option, parent, screen, setInterval, setTimeout, window, XMLHttpRequest */
 2236/**
 2237 * CList implements an integer-indexed collection class.
 2238 * 
 2239 * You can access, append, insert, remove an item by using
 2240 * {@link itemAt}, {@link add}, {@link insertAt}, {@link remove}, and {@link removeAt}.
 2241 * To get the number of the items in the list, use {@link getCount}.
 2242 * CList can also be used like a regular array as follows,
 2243 * <pre>
 2244 * list.push(item);  // append at the end
 2245 * list[index]=item; // $index must be between 0 and $list->Count
 2246 * delete list[index]; // remove the item at $index
 2247 * if(list[index] !== undefined) { // if the list has an item at $index
 2248 * for (index in list) // traverse each item in the list
 2249 * n=php.count(list);
 2250 * 		} // returns the number of items in the list
 2251 * </pre>
 2252 * 
 2253 * To extend CList by doing additional operations with each addition or removal
 2254 * operation (e.g. performing type check), override {@link insertAt()}, and {@link removeAt()}.
 2255 * 
 2256 * @originalAuthor Qiang Xue <qiang.xue@gmail.com>
 2257 * @version $Id: CList.php 3001 2011-02-24 16:42:44Z alexander.makarow $
 2258 * @package system.collections
 2259 * @since 1.0
 2260 * @author Charles Pick
 2261 * @class
 2262 * @extends Yii.CComponent
 2263 */
 2264Yii.CList = function CList (data, readOnly) {
 2265	if (data !== false) {
 2266		this.construct(data, readOnly);
 2267	}
 2268	
 2269};
 2270Yii.CList.prototype = new Array();
 2271Yii.CList.prototype.constructor =  Yii.CList;
 2272Yii.augment(Yii.CList, Yii.CComponent);
 2273/**
 2274 * @var {Boolean} whether this list is read-only
 2275 */
 2276Yii.CList.prototype._r = false;
 2277/**
 2278 * Constructor.
 2279 * Initializes the list with an array or an iterable object.
 2280 * @param {Array} data the initial data. Default is null, meaning no initialization.
 2281 * @param {Boolean} readOnly whether the list is read-only
 2282 * @throws {Yii.CException} If data is not null and neither an array nor an iterator.
 2283 */
 2284Yii.CList.prototype.construct = function (data, readOnly) {
 2285		if (data === undefined) {
 2286			data = null;
 2287		}
 2288		if (readOnly === undefined) {
 2289			readOnly = false;
 2290		}
 2291		if(data!==null) {
 2292			this.copyFrom(data);
 2293		}
 2294		this.setReadOnly(readOnly);
 2295	};
 2296/**
 2297 * @returns {Boolean} whether this list is read-only or not. Defaults to false.
 2298 */
 2299Yii.CList.prototype.getReadOnly = function () {
 2300		return this._r;
 2301	};
 2302/**
 2303 * @param {Boolean} value whether this list is read-only or not
 2304 */
 2305Yii.CList.prototype.setReadOnly = function (value) {
 2306		this._r=value;
 2307	};
 2308
 2309
 2310/**
 2311 * Returns the number of items in the list.
 2312 * @returns {Integer} the number of items in the list
 2313 */
 2314Yii.CList.prototype.getCount = function () {
 2315		return this.length;
 2316	};
 2317/**
 2318 * Returns the item at the specified offset.
 2319 * This method is exactly the same as {@link offsetGet}.
 2320 * @param {Integer} index the index of the item
 2321 * @returns {Mixed} the item at the index
 2322 * @throws {Yii.CException} if the index is out of the range
 2323 */
 2324Yii.CList.prototype.itemAt = function (index) {
 2325		if(this[index] !== undefined) {
 2326			return this[index];
 2327		}
 2328		else {
 2329			throw new Yii.CException(Yii.t('yii','List index "{index}" is out of bound.',
 2330				{'{index}':index}));
 2331		}
 2332	};
 2333/**
 2334 * Appends an item at the end of the list.
 2335 * @param {Mixed} item new item
 2336 * @returns {Integer} the zero-based index at which the item is added
 2337 */
 2338Yii.CList.prototype.add = function (item) {
 2339		return this.push(item);
 2340	};
 2341	
 2342/**
 2343 * Appends an item at the end of the list, fails if the list is read only.
 2344 * @param {Mixed} item new item
 2345 * @returns {Integer} the zero-based index at which the item is added
 2346 */
 2347Yii.CList.prototype.push = function (item) {
 2348		if (!this._r) {
 2349			return Array.prototype.push.call(this, item);
 2350		}
 2351		else {
 2352			throw new Yii.CException(Yii.t('yii','The list is read only.'));
 2353		}
 2354	};
 2355	
 2356/**
 2357 * Pops an item off the end of the list, fails if the list is read only.
 2358 * @returns {Mixed} the popped item
 2359 */
 2360Yii.CList.prototype.pop = function () {
 2361		if (!this._r) {
 2362			return Array.prototype.pop.call(this);
 2363		}
 2364		else {
 2365			throw new Yii.CException(Yii.t('yii','The list is read only.'));
 2366		}
 2367	};
 2368	
 2369/**
 2370 * Shifts an item off the start of the list, fails if the list is read only.
 2371 * @returns {Mixed} the shifted item
 2372 */
 2373Yii.CList.prototype.shift = function () {
 2374		if (!this._r) {
 2375			return Array.prototype.shift.call(this);
 2376		}
 2377		else {
 2378			throw new Yii.CException(Yii.t('yii','The list is read only.'));
 2379		}
 2380	};
 2381/**
 2382 * Inserts an item at the specified position.
 2383 * Original item at the position and the next items
 2384 * will be moved one step towards the end.
 2385 * @param {Integer} index the specified position.
 2386 * @param {Mixed} item new item
 2387 * @throws {Yii.CException} If the index specified exceeds the bound or the list is read-only
 2388 */
 2389Yii.CList.prototype.insertAt = function (index, item) {
 2390		if(!this._r)
 2391		{
 2392			if(index===this.length) {
 2393				this[this.length + 1]=item;
 2394			}
 2395			else if(index>=0 && index<this.length)
 2396			{
 2397				php.array_splice(this,index,0,[item]);
 2398			}
 2399			else {
 2400				throw new Yii.CException(Yii.t('yii','List index "{index}" is out of bound.',
 2401					{'{index}':index}));
 2402		}
 2403		}
 2404		else {
 2405			throw new Yii.CException(Yii.t('yii','The list is read only.'));
 2406		}
 2407	};
 2408/**
 2409 * Removes an item from the list.
 2410 * The list will first search for the item.
 2411 * The first item found will be removed from the list.
 2412 * @param {Mixed} item the item to be removed.
 2413 * @returns {Integer} the index at which the item is being removed
 2414 * @throws {Yii.CException} If the item does not exist
 2415 */
 2416Yii.CList.prototype.remove = function (item) {
 2417		var index;
 2418		if((index=this.indexOf(item))>=0)
 2419		{
 2420			this.removeAt(index);
 2421			return index;
 2422		}
 2423		else {
 2424			return false;
 2425		}
 2426	};
 2427/**
 2428 * Removes an item at the specified position.
 2429 * @param {Integer} index the index of the item to be removed.
 2430 * @returns {Mixed} the removed item.
 2431 * @throws {Yii.CException} If the index specified exceeds the bound or the list is read-only
 2432 */
 2433Yii.CList.prototype.removeAt = function (index) {
 2434		var item;
 2435		if(!this._r) {
 2436			if(index>=0 && index<this.length) {
 2437				if(index===this.length) {
 2438					return this.pop();
 2439				}
 2440				else
 2441				{
 2442					item=this[index];
 2443					php.array_splice(this,index,1);
 2444					return item;
 2445				}
 2446			}
 2447			else {
 2448				throw new Yii.CException(Yii.t('yii','List index "{index}" is out of bound.',
 2449					{'{index}':index}));
 2450			}
 2451		}
 2452		else {
 2453			throw new Yii.CException(Yii.t('yii','The list is read only.'));
 2454		}
 2455	};
 2456/**
 2457 * Removes all items in the list.
 2458 */
 2459Yii.CList.prototype.clear = function () {
 2460		var i;
 2461		for(i=this.length - 1; i >= 0; --i) {
 2462			this.removeAt(i);
 2463		}
 2464	};
 2465/**
 2466 * @param {Mixed} item the item
 2467 * @returns {Boolean} whether the list contains the item
 2468 */
 2469Yii.CList.prototype.contains = function (item) {
 2470		return this.indexOf(item) >= 0;
 2471	};
 2472
 2473/**
 2474 * @returns {Array} the list of items in array
 2475 */
 2476Yii.CList.prototype.toArray = function () {
 2477	var ret = [], i, limit;
 2478	limit = this.length;
 2479	for (i = 0; i < limit; i++) {
 2480		ret.push(this[i]);
 2481	}
 2482	return ret;
 2483};
 2484/**
 2485 * Copies iterable data into the list.
 2486 * Note, existing data in the list will be cleared first.
 2487 * @param {Mixed} data the data to be copied from, must be an array or object implementing Traversable
 2488 * @throws {Yii.CException} If data is neither an array nor a Traversable.
 2489 */
 2490Yii.CList.prototype.copyFrom = function (data) {
 2491		var i, item, limit;
 2492		if(Object.prototype.toString.call(data) === '[object Array]' || (data instanceof Array)) {
 2493			if(this.length > 0) {
 2494				this.clear();
 2495			}
 2496			if(data instanceof Yii.CList) {
 2497				data=data.toArray();
 2498			}
 2499			for (i = 0, limit = data.length; i < limit; i++) {
 2500				item = data[i];
 2501				this.add(item);
 2502			}
 2503		}
 2504		else if(data!==null) {
 2505			throw new Yii.CException(Yii.t('yii','List data must be an array or an object implementing Traversable.'));
 2506		}
 2507	};
 2508/**
 2509 * Merges iterable data into the map.
 2510 * New data will be appended to the end of the existing data.
 2511 * @param {Mixed} data the data to be merged with, must be an array or object implementing Traversable
 2512 * @throws {Yii.CException} If data is neither an array nor an iterator.
 2513 */
 2514Yii.CList.prototype.mergeWith = function (data) {
 2515		var i, item;
 2516		if(Object.prototype.toString.call(data) === '[object Array]' || (data instanceof Array))
 2517		{
 2518			if(data instanceof Yii.CList) {
 2519				data=data.toArray();
 2520			}
 2521			for (i in data) {
 2522				if (data.hasOwnProperty(i)) {
 2523					item = data[i];
 2524					this.add(item);
 2525				}
 2526			}
 2527		}
 2528		else if(data!==null) {
 2529			throw new Yii.CException(Yii.t('yii','List data must be an array or an object implementing Traversable.'));
 2530		}
 2531	};
 2532/**
 2533 * Provides convenient access to Yii.forEach()
 2534 * @param {Function} callback The callback function, this will receive 2 parameters, key and value
 2535 * @returns {Yii.CList} the list
 2536 */
 2537Yii.CList.prototype.forEach = function(callback) {
 2538	return Yii.forEach(this,callback);
 2539};
 2540/*global Yii, php, $, jQuery, alert, clearInterval, clearTimeout, document, event, frames, history, Image, location, name, navigator, Option, parent, screen, setInterval, setTimeout, window, XMLHttpRequest */
 2541/**
 2542 * CMap implements a collection that takes key-value pairs.
 2543 * 
 2544 * You can access, add or remove an item with a key by using
 2545 * {@link itemAt}, {@link add}, and {@link remove}.
 2546 * To get the number of the items in the map, use {@link getCount}.
 2547 * CMap can also be used like a regular array as follows,
 2548 * <pre>
 2549 * map[key]=value; // add a key-value pair
 2550 * delete map[key]; // remove the value with the specified key
 2551 * if(map[key] !== undefined) { // if the map contains the key
 2552 *     for (key in map) // traverse the items in the map
 2553 *         n=php.count(map);
 2554 * }  // returns the number of items in the map
 2555 * </pre>
 2556 * 
 2557 * @originalAuthor Qiang Xue <qiang.xue@gmail.com>
 2558 * @version $Id: CMap.php 3153 2011-04-01 12:50:06Z qiang.xue $
 2559 * @package system.collections
 2560 * @since 1.0
 2561 * @author Charles Pick
 2562 * @class
 2563 * @extends Yii.CComponent
 2564 */
 2565Yii.CMap = function CMap (data, readOnly) {
 2566	if (data !== false) {
 2567		this.construct(data, readOnly);
 2568	}
 2569	
 2570};
 2571Yii.CMap.prototype = new Yii.CComponent();
 2572Yii.CMap.prototype.constructor =  Yii.CMap;
 2573
 2574
 2575/**
 2576 * Constructor.
 2577 * Initializes the list with an array or an iterable object.
 2578 * @param {Object} data the intial data. Default is null, meaning no initialization.
 2579 * @throws {Yii.CException} If data is not null and neither an array nor an iterator.
 2580 */
 2581Yii.CMap.prototype.construct = function (data) {
 2582		if (data === undefined) {
 2583			data = null;
 2584		}
 2585		
 2586		if(data!==null) {
 2587			this.copyFrom(data);
 2588		}
 2589	};
 2590
 2591/**
 2592 * Returns the number of items in the map.
 2593 * @returns {Integer} number of items in the map.
 2594 */
 2595Yii.CMap.prototype.count = function () {
 2596		return this.getCount();
 2597	};
 2598/**
 2599 * Returns the number of items in the map.
 2600 * @returns {Integer} the number of items in the map
 2601 */
 2602Yii.CMap.prototype.getCount = function () {
 2603		var total = 0, i;
 2604		for (i in this) {
 2605			if (this.hasOwnProperty(i)) {
 2606				total++;
 2607			}
 2608		}
 2609		
 2610		return total;
 2611	};
 2612
 2613/**
 2614 * @returns {Array} the key list
 2615 */
 2616Yii.CMap.prototype.getKeys = function () {
 2617		var i, keys = [];
 2618		for (i in this) {
 2619			if (this.hasOwnProperty(i)) {
 2620				keys.push(i);
 2621			}
 2622		}
 2623		return keys;
 2624	};
 2625/**
 2626 * Returns the item with the specified key.
 2627 * @param {Mixed} key the key
 2628 * @returns {Mixed} the element at the offset, null if no element is found at the offset
 2629 */
 2630Yii.CMap.prototype.itemAt = function (key) {
 2631		if(this[key] !== undefined) {
 2632			return this[key];
 2633		}
 2634		else {
 2635			return null;
 2636		}
 2637	};
 2638/**
 2639 * Adds an item into the map.
 2640 * Note, if the specified key already exists, the old value will be overwritten.
 2641 * @param {Mixed} key key
 2642 * @param {Mixed} value value
 2643 * @throws {Yii.CException} if the map is read-only
 2644 */
 2645Yii.CMap.prototype.add = function (key, value) {
 2646		if (key === null) {
 2647			key = this.count();
 2648		}
 2649		this[key] = value;
 2650	};
 2651/**
 2652 * Removes an item from the map by its key.
 2653 * @param {Mixed} key the key of the item to be removed
 2654 * @returns {Mixed} the removed value, null if no such key exists.
 2655 * @throws {Yii.CException} if the map is read-only
 2656 */
 2657Yii.CMap.prototype.remove = function (key) {
 2658		var value;
 2659		if(this[key] !== undefined) {
 2660			value=this[key];
 2661			delete this[key];
 2662			return value;
 2663		}
 2664	};
 2665/**
 2666 * Removes all items in the map.
 2667 */
 2668Yii.CMap.prototype.clear = function () {
 2669		var i, keyList, key;
 2670		for (i in this) {
 2671			if (this.hasOwnProperty(i)) {
 2672				this.remove(i);
 2673			}
 2674		}
 2675	};
 2676/**
 2677 * @param {Mixed} key the key
 2678 * @returns {Boolean} whether the map contains an item with the specified key
 2679 */
 2680Yii.CMap.prototype.contains = function (key) {
 2681		return this[key] !== undefined;
 2682	};
 2683/**
 2684 * @returns {Array} the list of items in array
 2685 */
 2686Yii.CMap.prototype.toArray = function () {
 2687		var i, ret = [];
 2688		for (i in this) {
 2689			if (this.hasOwnProperty(i)) {
 2690				ret.push(this[i]);
 2691			}
 2692		}
 2693		return ret;
 2694	};
 2695/**
 2696 * @returns {Object} the list of items in object
 2697 */
 2698Yii.CMap.prototype.toObject = function () {
 2699		var i, ret = {};
 2700		for (i in this) {
 2701			if (this.hasOwnProperty(i)) {
 2702				ret[i] = this[i];
 2703			}
 2704		}
 2705		return ret;
 2706	};
 2707/**
 2708 * Copies iterable data into the map.
 2709 * Note, existing data in the map will be cleared first.
 2710 * @param {Mixed} data the data to be copied from, must be an array or object implementing Traversable
 2711 * @throws {Yii.CException} If data is neither an array nor an iterator.
 2712 */
 2713Yii.CMap.prototype.copyFrom = function (data) {
 2714		var key, value;
 2715		if(typeof data === "object") {
 2716			if(this.getCount()>0) {
 2717				this.clear();
 2718			}
 2719			if(data instanceof Yii.CMap) {
 2720				data=data.toObject();
 2721			}
 2722			for (key in data) {
 2723				if (data.hasOwnProperty(key)) {
 2724					value = data[key];
 2725					this.add(key,value);
 2726				}
 2727			}
 2728		}
 2729		else if(data!==null) {
 2730			throw new Yii.CException(Yii.t('yii','Map data must be an array or an object implementing Traversable.'));
 2731		}
 2732	};
 2733/**
 2734 * Merges iterable data into the map.
 2735 * 
 2736 * Existing elements in the map will be overwritten if their keys are the same as those in the source.
 2737 * If the merge is recursive, the following algorithm is performed:
 2738 * <ul>
 2739 * <li>the map data is saved as $a, and the source data is saved as $b;</li>
 2740 * <li>if $a and $b both have an array indxed at the same string key, the arrays will be merged using this algorithm;</li>
 2741 * <li>any integer-indexed elements in $b will be appended to $a and reindxed accordingly;</li>
 2742 * <li>any string-indexed elements in $b will overwrite elements in $a with the same index;</li>
 2743 * </ul>
 2744 * 
 2745 * @param {Mixed} data the data to be merged with, must be an array or object implementing Traversable
 2746 * @param {Boolean} recursive whether the merging should be recursive.
 2747 * 
 2748 * @throws {Yii.CException} If data is neither an array nor an iterator.
 2749 */
 2750Yii.CMap.prototype.mergeWith = function (data, recursive) {
 2751		var d, key, value;
 2752		if (recursive === undefined) {
 2753			recursive = true;
 2754		}
 2755		if(typeof data === "object") {
 2756			if(data instanceof Yii.CMap) {
 2757				data=data.toObject();
 2758			}
 2759			else if(data instanceof Yii.CList) {
 2760				data=data.toArray();
 2761			}
 2762			if(recursive) {
 2763				this.mergeArray(this,data);
 2764			}
 2765			else
 2766			{
 2767				for (key in data) {
 2768					if (data.hasOwnProperty(key)) {
 2769						value = data[key];
 2770						this.add(key,value);
 2771					}
 2772				}
 2773			}
 2774		}
 2775		else if(data!==null) {
 2776			throw new Yii.CException(Yii.t('yii','Map data must be an array or an object implementing Traversable.'));
 2777		}
 2778	};
 2779/**
 2780 * Merges two arrays into one recursively.
 2781 * If each array has an element with the same string key value, the latter
 2782 * will overwrite the former (different from array_merge_recursive).
 2783 * Recursive merging will be conducted if both arrays have an element of array
 2784 * type and are having the same key.
 2785 * For integer-keyed elements, the elements from the latter array will
 2786 * be appended to the former array.
 2787 * @param {Array} a array to be merged to
 2788 * @param {Array} b array to be merged from
 2789 * @returns {Array} the merged array (the original arrays are not changed.)
 2790 * @see mergeWith
 2791 */
 2792Yii.CMap.prototype.mergeArray = function (a, b) {
 2793		var k, v;
 2794		for (k in b) {
 2795			if (b.hasOwnProperty(k)) {
 2796				v = b[k];
 2797				if((typeof(k) === 'number' && (k % 1 ? false : true))) {
 2798					a[k] !== undefined ? a.push(v) : a[k]=v;
 2799				}
 2800				else if (a[k] !== undefined && typeof a[k] === "object") {
 2801					a[k]=this.mergeArray(a[k],v);
 2802				}
 2803				else {
 2804					a[k]=v;
 2805				}
 2806			}
 2807		}
 2808		return a;
 2809	};
 2810/**
 2811 * Provides convenient access to Yii.forEach()
 2812 * @param {Function} callback The callback function, this will receive 2 parameters, key and value
 2813 * @returns {Yii.CMap} the map
 2814 */
 2815Yii.CMap.prototype.forEach = function(callback) {
 2816	return Yii.forEach(this,callback);
 2817};/*global Yii, php, $, jQuery, alert, clearInterval, clearTimeout, document, event, frames, history, Image, location, name, navigator, Option, parent, screen, setInterval, setTimeout, window, XMLHttpRequest */
 2818/**
 2819 * CValidator is the base class for all validators.
 2820 * 
 2821 * Child classes must implement the {@link validateAttribute} method.
 2822 * 
 2823 * The following properties are defined in CValidator:
 2824 * <ul>
 2825 * <li>{@link attributes}: array, list of attributes to be validated;</li>
 2826 * <li>{@link message}: string, the customized error message. The message
 2827 *   may contain placeholders that will be replaced with the actual content.
 2828 *   For example, the "{attribute}" placeholder will be replaced with the label
 2829 *   of the problematic attribute. Different validators may define additional
 2830 *   placeholders.</li>
 2831 * <li>{@link on}: string, in which scenario should the validator be in effect.
 2832 *   This is used to match the 'on' parameter supplied when calling {@link CModel::validate}.</li>
 2833 * </ul>
 2834 * 
 2835 * When using {@link createValidator} to create a validator, the following aliases
 2836 * are recognized as the corresponding built-in validator classes:
 2837 * <ul>
 2838 * <li>required: {@link CRequiredValidator}</li>
 2839 * <li>filter: {@link CFilterValidator}</li>
 2840 * <li>match: {@link CRegularExpressionValidator}</li>
 2841 * <li>email: {@link CEmailValidator}</li>
 2842 * <li>url: {@link CUrlValidator}</li>
 2843 * <li>unique: {@link CUniqueValidator}</li>
 2844 * <li>compare: {@link CCompareValidator}</li>
 2845 * <li>length: {@link CStringValidator}</li>
 2846 * <li>in: {@link CRangeValidator}</li>
 2847 * <li>numerical: {@link CNumberValidator}</li>
 2848 * <li>captcha: {@link CCaptchaValidator}</li>
 2849 * <li>type: {@link CTypeValidator}</li>
 2850 * <li>file: {@link CFileValidator}</li>
 2851 * <li>default: {@link CDefaultValueValidator}</li>
 2852 * <li>exist: {@link CExistValidator}</li>
 2853 * <li>boolean: {@link CBooleanValidator}</li>
 2854 * <li>date: {@link CDateValidator}</li>
 2855 * <li>safe: {@link CSafeValidator}</li>
 2856 * <li>unsafe: {@link CUnsafeValidator}</li>
 2857 * </ul>
 2858 * 
 2859 * @originalAuthor Qiang Xue <qiang.xue@gmail.com>
 2860 * @version $Id: CValidator.php 3160 2011-04-03 01:08:23Z qiang.xue $
 2861 * @package system.validators
 2862 * @since 1.0
 2863 * @author Charles Pick
 2864 * @class
 2865 * @extends Yii.CComponent
 2866 */
 2867Yii.CValidator = function CValidator() {
 2868};
 2869Yii.CValidator.prototype = new Yii.CComponent();
 2870Yii.CValidator.prototype.constructor =  Yii.CValidator;
 2871/**
 2872 * @var {Object} list of built-in validators (name=>class)
 2873 */
 2874Yii.CValidator.prototype.builtInValidators = {
 2875		'required':'Yii.CRequiredValidator',
 2876		'filter':'Yii.CFilterValidator',
 2877		'match':'Yii.CRegularExpressionValidator',
 2878		'email':'Yii.CEmailValidator',
 2879		'url':'Yii.CUrlValidator',
 2880		'unique':'Yii.CUniqueValidator',
 2881		'compare':'Yii.CCompareValidator',
 2882		'length':'Yii.CStringValidator',
 2883		'in':'Yii.CRangeValidator',
 2884		'numerical':'Yii.CNumberValidator',
 2885		'captcha':'Yii.CCaptchaValidator',
 2886		'type':'Yii.CTypeValidator',
 2887		'file':'Yii.CFileValidator',
 2888		'default':'Yii.CDefaultValueValidator',
 2889		'exist':'Yii.CExistValidator',
 2890		'boolean':'Yii.CBooleanValidator',
 2891		'safe':'Yii.CSafeValidator',
 2892		'unsafe':'Yii.CUnsafeValidator',
 2893		'date':'Yii.CDateValidator'
 2894	};
 2895/**
 2896 * @var {Array} list of attributes to be validated.
 2897 */
 2898Yii.CValidator.prototype.attributes = null;
 2899/**
 2900 * @var {String} the user-defined error message. Different validators may define various
 2901 * placeholders in the message that are to be replaced with actual values. All validators
 2902 * recognize "{attribute}" placeholder, which will be replaced with the label of the attribute.
 2903 */
 2904Yii.CValidator.prototype.message = null;
 2905/**
 2906 * @var {Boolean} whether this validation rule should be skipped if when there is already a validation
 2907 * error for the current attribute. Defaults to false.
 2908 * @since 1.1.1
 2909 */
 2910Yii.CValidator.prototype.skipOnError = false;
 2911/**
 2912 * @var {Array} list of scenarios that the validator should be applied.
 2913 * Each array value refers to a scenario name with the same name as its array key.
 2914 */
 2915Yii.CValidator.prototype.on = null;
 2916/**
 2917 * @var {Boolean} whether attributes listed with this validator should be considered safe for massive assignment.
 2918 * Defaults to true.
 2919 * @since 1.1.4
 2920 */
 2921Yii.CValidator.prototype.safe = true;
 2922/**
 2923 * @var {Boolean} whether to perform client-side validation. Defaults to true.
 2924 * Please refer to {@link CActiveForm::enableClientValidation} for more details about client-side validation.
 2925 * @since 1.1.7
 2926 */
 2927Yii.CValidator.prototype.enableClientValidation = true;
 2928/**
 2929 * Validates a single attribute.
 2930 * This method should be overridden by child classes.
 2931 * @param {Yii.CModel} object the data object being validated
 2932 * @param {String} attribute the name of the attribute to be validated.
 2933 */
 2934Yii.CValidator.prototype.validateAttribute = function (object, attribute) {
 2935	};
 2936/**
 2937 * Creates a validator object.
 2938 * @param {String} name the name or class of the validator
 2939 * @param {Yii.CModel} object the data object being validated that may contain the inline validation method
 2940 * @param {Mixed} attributes list of attributes to be validated. This can be either an array of
 2941 * the attribute names or a string of comma-separated attribute names.
 2942 * @param {Array} params initial values to be applied to the validator properties
 2943 * @returns {Yii.CValidator} the validator
 2944 */
 2945Yii.CValidator.prototype.createValidator = function (name, object, attributes, params) {
 2946		var n, on, validator, builtInValidators, className, value, nameParts, i, limit, classObject;
 2947		if (params === undefined) {
 2948			params = [];
 2949		}
 2950		if(typeof(attributes) === 'string') {
 2951			attributes=attributes.split(/[\s,]+/);
 2952		}
 2953		if(params.on !== undefined) {
 2954			if(Object.prototype.toString.call(params.on) === '[object Array]') {
 2955				on=params.on;
 2956			}
 2957			else {
 2958				on=params.on.split(/[\s,]+/);
 2959			}
 2960		}
 2961		else {
 2962			on=[];
 2963		}
 2964		if (object[name] !== undefined && typeof object[name] === "function") {
 2965			validator=new Yii.CInlineValidator();
 2966			validator.attributes=attributes;
 2967			validator.method=name;
 2968			validator.params=params;
 2969			if(params.skipOnError !== undefined) {
 2970				validator.skipOnError=params.skipOnError;
 2971			}
 2972		}
 2973		else {
 2974			params.attributes = attributes;
 2975			if(this.builtInValidators[name] !== undefined) {
 2976				className = this.builtInValidators[name];
 2977			}
 2978			else {
 2979				className = name;
 2980			}
 2981			
 2982			if (className.slice(0,3) === "Yii") {
 2983				
 2984				validator=new Yii[className.slice(4)]();
 2985				
 2986			}
 2987			else {
 2988				validator = new window[className]();
 2989			}
 2990			for (n in params) {
 2991				if (params.hasOwnProperty(n)) {
 2992					value = params[n];
 2993					validator[n]=value;
 2994				}
 2995			}
 2996			
 2997		}
 2998		validator.on=php.empty(on) ? [] : php.array_combine(on,on);
 2999		return validator;
 3000	};
 3001/**
 3002 * Validates the specified object.
 3003 * @param {Yii.CModel} object the data object being validated
 3004 * @param {Array} attributes the list of attributes to be validated. Defaults to null,
 3005 * meaning every attribute listed in {@link attributes} will be validated.
 3006 */
 3007Yii.CValidator.prototype.validate = function (object, attributes) {
 3008		var i, attribute, self = this;
 3009		
 3010		if (attributes === undefined) {
 3011			attributes = null;
 3012		}
 3013		if(Object.prototype.toString.call(attributes) === '[object Array]') {
 3014			attributes=php.array_intersect(this.attributes,attributes);
 3015		}
 3016		else {
 3017			attributes=this.attributes;
 3018		}
 3019		
 3020		Yii.forEach(attributes, function(i,attribute) {
 3021			if(!self.skipOnError || !object.hasErrors(attribute)) {
 3022				self.validateAttribute(object,attribute);
 3023			}
 3024		});
 3025	
 3026	};
 3027/**
 3028 * Returns the JavaScript needed for performing client-side validation.
 3029 * Do not override this method if the validator does not support client-side validation.
 3030 * Two predefined JavaScript variables can be used:
 3031 * <ul>
 3032 * <li>value: the value to be validated</li>
 3033 * <li>messages: an array used to hold the validation error messages for the value</li>
 3034 * </ul>
 3035 * @param {Yii.CModel} object the data object being validated
 3036 * @param {String} attribute the name of the attribute to be validated.
 3037 * @returns {String} the client-side validation script. Null if the validator does not support client-side validation.
 3038 * @see CActiveForm::enableClientValidation
 3039 * @since 1.1.7
 3040 */
 3041Yii.CValidator.prototype.clientValidateAttribute = function (object, attribute) {
 3042	};
 3043/**
 3044 * Returns a value indicating whether the validator applies to the specified scenario.
 3045 * A validator applies to a scenario as long as any of the following conditions is met:
 3046 * <ul>
 3047 * <li>the validator's "on" property is empty</li>
 3048 * <li>the validator's "on" property contains the specified scenario</li>
 3049 * </ul>
 3050 * @param {String} scenario scenario name
 3051 * @returns {Boolean} whether the validator applies to the specified scenario.
 3052 * @since 1.0.2
 3053 */
 3054Yii.CValidator.prototype.applyTo = function (scenario) {
 3055		return php.empty(this.on) || this.on[scenario] !== undefined;
 3056	};
 3057/**
 3058 * Adds an error about the specified attribute to the active record.
 3059 * This is a helper method that performs message selection and internationalization.
 3060 * @param {Yii.CModel} object the data object being validated
 3061 * @param {String} attribute the attribute being validated
 3062 * @param {String} message the error message
 3063 * @param {Array} params values for the placeholders in the error message
 3064 */
 3065Yii.CValidator.prototype.addError = function (object, attribute, message, params) {
 3066		if (params === undefined) {
 3067			params = [];
 3068		}
 3069		params['{attribute}']=object.getAttributeLabel(attribute);
 3070		
 3071		object.addError(attribute,php.strtr(message,params));
 3072	};
 3073/**
 3074 * Checks if the given value is empty.
 3075 * A value is considered empty if it is null, an empty array, or the trimmed result is an empty string.
 3076 * Note that this method is different from PHP empty(). It will return false when the value is 0.
 3077 * @param {Mixed} value the value to be checked
 3078 * @param {Boolean} trim whether to perform trimming before checking if the string is empty. Defaults to false.
 3079 * @returns {Boolean} whether the value is empty
 3080 * @since 1.0.9
 3081 */
 3082Yii.CValidator.prototype.isEmpty = function (value, trim) {
 3083		if (trim === undefined) {
 3084			trim = false;
 3085		}
 3086		return value===null || value===[] || value==='' || trim && (/boolean|number|string/).test(typeof value) && php.trim(value)==='';
 3087	}/*global Yii, php, $, jQuery, alert, clearInterval, clearTimeout, document, event, frames, history, Image, location, name, navigator, Option, parent, screen, setInterval, setTimeout, window, XMLHttpRequest */
 3088/**
 3089 * CMessageSource is the base class for message translation repository classes.
 3090 * 
 3091 * A message source is an application component that provides message internationalization (i18n).
 3092 * It stores messages translated in different languages and provides
 3093 * these translated versions when requested.
 3094 * 
 3095 * A concrete class must implement {@link loadMessages} or override {@link translateMessage}.
 3096 * 
 3097 * @originalAuthor Qiang Xue <qiang.xue@gmail.com>
 3098 * @version $Id: CMessageSource.php 2798 2011-01-01 19:29:03Z qiang.xue $
 3099 * @package system.i18n
 3100 * @since 1.0
 3101 * @author Charles Pick
 3102 * @class
 3103 * @extends Yii.CApplicationComponent
 3104 */
 3105Yii.CMessageSource = function CMessageSource () {
 3106	
 3107};
 3108Yii.CMessageSource.prototype = new Yii.CApplicationComponent();
 3109Yii.CMessageSource.prototype.constructor =  Yii.CMessageSource;
 3110/**
 3111 * @var {Boolean} whether to force message translation when the source and target languages are the same.
 3112 * Defaults to false, meaning translation is only performed when source and target languages are different.
 3113 * @since 1.1.4
 3114 */
 3115Yii.CMessageSource.prototype.forceTranslation = false;
 3116Yii.CMessageSource.prototype._language = null;
 3117Yii.CMessageSource.prototype._messages = {};
 3118/**
 3119 * Loads the message translation for the specified language and category.
 3120 * @param {String} category the message category
 3121 * @param {String} language the target language
 3122 * @returns {Object} the loaded messages
 3123 */
 3124Yii.CMessageSource.prototype.loadMessages = function (category, language) {
 3125	};
 3126/**
 3127 * @returns {String} the language that the source messages are written in.
 3128 * Defaults to {@link CApplication::language application language}.
 3129 */
 3130Yii.CMessageSource.prototype.getLanguage = function () {
 3131		return this._language===null ? Yii.app().sourceLanguage : this._language;
 3132	};
 3133/**
 3134 * @param {String} language the language that the source messages are written in.
 3135 */
 3136Yii.CMessageSource.prototype.setLanguage = function (language) {
 3137		this._language=Yii.CLocale.prototype.getCanonicalID(language);
 3138	};
 3139/**
 3140 * Translates a message to the specified language.
 3141 * 
 3142 * Note, if the specified language is the same as
 3143 * the {@link getLanguage source message language}, messages will NOT be translated.
 3144 * 
 3145 * If the message is not found in the translations, an {@link onMissingTranslation}
 3146 * event will be raised. Handlers can mark this message or do some
 3147 * default handling. The {@link CMissingTranslationEvent::message}
 3148 * property of the event parameter will be returned.
 3149 * 
 3150 * @param {String} category the message category
 3151 * @param {String} message the message to be translated
 3152 * @param {String} language the target language. If null (default), the {@link CApplication::getLanguage application language} will be used.
 3153 * This parameter has been available since version 1.0.3.
 3154 * @returns {String} the translated message (or the original message if translation is not needed)
 3155 */
 3156Yii.CMessageSource.prototype.translate = function (category, message, language) {
 3157		if (language === undefined) {
 3158			language = null;
 3159		}
 3160		if(language===null) {
 3161			language=Yii.app().getLanguage();
 3162		}
 3163		if(this.forceTranslation || language!==this.getLanguage()) {
 3164			return this.translateMessage(category,message,language);
 3165		}
 3166		else {
 3167			return message;
 3168		}
 3169	};
 3170/**
 3171 * Translates the specified message.
 3172 * If the message is not found, an {@link onMissingTranslation}
 3173 * event will be raised.
 3174 * @param {String} category the category that the message belongs to
 3175 * @param {String} message the message to be translated
 3176 * @param {String} language the target language
 3177 * @returns {String} the translated message
 3178 */
 3179Yii.CMessageSource.prototype.translateMessage = function (category, message, language) {
 3180		var key, event;
 3181		key=language+'.'+category;
 3182		if(this._messages[key] === undefined) {
 3183			this._messages[key]=this.loadMessages(category,language);
 3184		}
 3185		if(this._messages[key][message] !== undefined && this._messages[key][message]!=='') {
 3186			return this._messages[key][message];
 3187		}
 3188		else if(this.hasEventHandler('onMissingTranslation'))
 3189		{
 3190			event=new Yii.CMissingTranslationEvent(this,category,message,language);
 3191			this.onMissingTranslation(event);
 3192			return event.message;
 3193		}
 3194		else {
 3195			return message;
 3196		}
 3197	};
 3198/**
 3199 * Raised when a message cannot be translated.
 3200 * Handlers may log this message or do some default handling.
 3201 * The {@link CMissingTranslationEvent::message} property
 3202 * will be returned by {@link translateMessage}.
 3203 * @param {Yii.CMissingTranslationEvent} event the event parameter
 3204 */
 3205Yii.CMessageSource.prototype.onMissingTranslation = function (event) {
 3206		this.raiseEvent('onMissingTranslation',event);
 3207	};/*global Yii, php, $, jQuery, alert, clearInterval, clearTimeout, document, event, frames, history, Image, location, name, navigator, Option, parent, screen, setInterval, setTimeout, window, XMLHttpRequest */
 3208/**
 3209 * CFilter is the base class for all filters.
 3210 * 
 3211 * A filter can be applied before and after an action is executed.
 3212 * It can modify the context that the action is to run or decorate the result that the
 3213 * action generates.
 3214 * 
 3215 * Override {@link preFilter()} to specify the filtering logic that should be applied
 3216 * before the action, and {@link postFilter()} for filtering logic after the action.
 3217 * 
 3218 * @originalAuthor Qiang Xue <qiang.xue@gmail.com>
 3219 * @version $Id: CFilter.php 2799 2011-01-01 19:31:13Z qiang.xue $
 3220 * @package system.web.filters
 3221 * @since 1.0
 3222 * @author Charles Pick
 3223 * @class
 3224 * @extends Yii.CComponent
 3225 */
 3226Yii.CFilter = function CFilter () {
 3227};
 3228Yii.CFilter.prototype = new Yii.CComponent();
 3229Yii.CFilter.prototype.constructor =  Yii.CFilter;
 3230/**
 3231 * Performs the filtering.
 3232 * The default implementation is to invoke {@link preFilter}
 3233 * and {@link postFilter} which are meant to be overridden
 3234 * child classes. If a child class needs to override this method,
 3235 * make sure it calls <code>$filterChain->run()</code>
 3236 * if the action should be executed.
 3237 * @param {Yii.CFilterChain} filterChain the filter chain that the filter is on.
 3238 */
 3239Yii.CFilter.prototype.filter = function (filterChain) {
 3240		if(this.preFilter(filterChain))
 3241		{
 3242			filterChain.run();
 3243			this.postFilter(filterChain);
 3244		}
 3245	};
 3246/**
 3247 * Initializes the filter.
 3248 * This method is invoked after the filter properties are initialized
 3249 * and before {@link preFilter} is called.
 3250 * You may override this method to include some initialization logic.
 3251 * @since 1.1.4
 3252 */
 3253Yii.CFilter.prototype.init = function () {
 3254	};
 3255/**
 3256 * Performs the pre-action filtering.
 3257 * @param {Yii.CFilterChain} filterChain the filter chain that the filter is on.
 3258 * @returns {Boolean} whether the filtering process should continue and the action
 3259 * should be executed.
 3260 */
 3261Yii.CFilter.prototype.preFilter = function (filterChain) {
 3262		return true;
 3263	};
 3264/**
 3265 * Performs the post-action filtering.
 3266 * @param {Yii.CFilterChain} filterChain the filter chain that the filter is on.
 3267 */
 3268Yii.CFilter.prototype.postFilter = function (filterChain) {
 3269	};/*global Yii, php, $, jQuery, alert, clearInterval, clearTimeout, document, event, frames, history, Image, location, name, navigator, Option, parent, screen, setInterval, setTimeout, window, XMLHttpRequest */
 3270/**
 3271 * CViewRenderer is the base class for view renderer classes.
 3272 * 
 3273 * A view renderer is an application component that renders views written
 3274 * in a customized syntax.
 3275 * 
 3276 * Once installing a view renderer as a 'viewRenderer' application component,
 3277 * the normal view rendering process will be intercepted by the renderer.
 3278 * The renderer will first parse the source view file and then render the
 3279 * the resulting view file.
 3280 * 
 3281 * Parsing results are saved as temporary files that may be stored
 3282 * under the application runtime directory or together with the source view file.
 3283 * 
 3284 * @originalAuthor Steve Heyns http://customgothic.com/
 3285 * @originalAuthor Qiang Xue <qiang.xue@gmail.com>
 3286 * @version $Id: CViewRenderer.php 2799 2011-01-01 19:31:13Z qiang.xue $
 3287 * @package system.web.renderers
 3288 * @since 1.0
 3289 * @author Charles Pick
 3290 * @class
 3291 * @extends Yii.CApplicationComponent
 3292 */
 3293Yii.CViewRenderer = function CViewRenderer () {
 3294};
 3295Yii.CViewRenderer.prototype = new Yii.CApplicationComponent();
 3296Yii.CViewRenderer.prototype.constructor =  Yii.CViewRenderer;
 3297
 3298/**
 3299 * @var {String} the extension name of the view file. Defaults to '.html'.
 3300 * @since 1.0.9
 3301 */
 3302Yii.CViewRenderer.prototype.fileExtension = '.html';
 3303
 3304/**
 3305 * Renders a view file.
 3306 * @param {Yii.CBaseController} context the controller or widget who is rendering the view file.
 3307 * @param {String} sourceFile the view file path
 3308 * @param {Mixed} data the data to be passed to the view
 3309 * @param {Boolean} returnVar whether the rendering result should be returned
 3310 * @returns {Mixed} the rendering result, or null if the rendering result is not needed.
 3311 */
 3312Yii.CViewRenderer.prototype.renderFile = function (context, sourceFile, data, returnVar) {
 3313		var file, viewFile;
 3314		
 3315		viewFile=this.getViewFile(sourceFile);
 3316		
 3317		return context.renderInternal(viewFile,data,returnVar);
 3318	};
 3319/**
 3320 * Generates the resulting view file path.
 3321 * @param {String} file source view file path
 3322 * @returns {String} resulting view file path
 3323 */
 3324Yii.CViewRenderer.prototype.getViewFile = function (file) {
 3325		return file;
 3326	};/*global Yii, php, $, jQuery, alert, clearInterval, clearTimeout, document, event, frames, history, Image, location, name, navigator, Option, parent, screen, setInterval, setTimeout, window, XMLHttpRequest */
 3327/**
 3328 * CFormElement is the base class for presenting all kinds of form element.
 3329 * 
 3330 * CFormElement implements the way to get and set arbitrary attributes.
 3331 * 
 3332 * @originalAuthor Qiang Xue <qiang.xue@gmail.com>
 3333 * @version $Id: CFormElement.php 3001 2011-02-24 16:42:44Z alexander.makarow $
 3334 * @package system.web.form
 3335 * @since 1.1
 3336 * @author Charles Pick
 3337 * @class
 3338 * @extends Yii.CComponent
 3339 */
 3340Yii.CFormElement = function CFormElement (config, parent) {
 3341	if (config !== false) {
 3342		this.construct(config, parent);
 3343	}
 3344};
 3345Yii.CFormElement.prototype = new Yii.CComponent();
 3346Yii.CFormElement.prototype.constructor =  Yii.CFormElement;
 3347/**
 3348 * @var {Array} list of attributes (name=>value) for the HTML element represented by this object.
 3349 */
 3350Yii.CFormElement.prototype.attributes = {};
 3351Yii.CFormElement.prototype._parent = null;
 3352Yii.CFormElement.prototype._visible = null;
 3353/**
 3354 * Renders this element.
 3355 * @returns {String} the rendering result
 3356 */
 3357Yii.CFormElement.prototype.render = function () {
 3358	};
 3359/**
 3360 * Constructor.
 3361 * @param {Mixed} config the configuration for this element.
 3362 * @param {Mixed} parent the direct parent of this element.
 3363 * @see configure
 3364 */
 3365Yii.CFormElement.prototype.construct = function (config, parent) {
 3366		
 3367		this.configure(config);
 3368		this._parent=parent;
 3369	};
 3370/**
 3371 * Converts the object to a string.
 3372 * This is a PHP magic method.
 3373 * The default implementation simply calls {@link render} and return
 3374 * the rendering result.
 3375 * @returns {String} the string representation of this object.
 3376 */
 3377Yii.CFormElement.prototype.toString = function () {
 3378		return this.render();
 3379	};
 3380/**
 3381 * Returns a property value or an attribute value.
 3382 * Do not call this method. This is a PHP magic method that we override
 3383 * to allow using the following syntax to read a property or attribute:
 3384 * <pre>
 3385 * value=element.propertyName;
 3386 * value=element.attributeName;
 3387 * </pre>
 3388 * @param {String} name the property or attribute name
 3389 * @returns {Mixed} the property or attribute value
 3390 * @throws {Yii.CException} if the property or attribute is not defined
 3391 * @see __set
 3392 */
 3393Yii.CFormElement.prototype.get = function (name) {
 3394		var getter;
 3395		getter='get'+php.ucfirst(name);
 3396		if(php.method_exists(this,getter)) {
 3397			return this[getter]();
 3398		}
 3399		else if(this.attributes[name] !== undefined) {
 3400			return this.attributes[name];
 3401		}
 3402		else {
 3403			throw new Yii.CException(Yii.t('yii','Property "{class}.{property}" is not defined.',
 3404				{'{class}':this.getClassName(), '{property}':name}));
 3405		}
 3406	};
 3407/**
 3408 * Sets value of a property or attribute.
 3409 * Do not call this method. This is a PHP magic method that we override
 3410 * to allow using the following syntax to set a property or attribute.
 3411 * <pre>
 3412 * this.propertyName=value;
 3413 * this.attributeName=value;
 3414 * </pre>
 3415 * @param {String} name the property or attribute name
 3416 * @param {Mixed} value the property or attribute value
 3417 * @see __get
 3418 */
 3419Yii.CFormElement.prototype.set = function (name, value) {
 3420		var setter;
 3421		setter='set'+php.ucfirst(name);
 3422		
 3423		if(php.method_exists(this,setter)) {
 3424			this[setter](value);
 3425		}
 3426		else if (this[name] !== undefined) {
 3427			this[name] = value;
 3428		}
 3429		else {
 3430			this.attributes[name]=value;
 3431		}
 3432	};
 3433/**
 3434 * Configures this object with property initial values.
 3435 * @param {Mixed} config the configuration for this object. This can be an array
 3436 * representing the property names and their initial values.
 3437 * It can also be a string representing the file name of the PHP script
 3438 * that returns a configuration array.
 3439 */
 3440Yii.CFormElement.prototype.configure = function (config) {
 3441		var name, value;
 3442		
 3443		for (name in config) {
 3444			if (config.hasOwnProperty(name)) {
 3445				value = config[name];
 3446				this.set(name,value);
 3447			}
 3448		}
 3449	};
 3450/**
 3451 * Returns a value indicating whether this element is visible and should be rendered.
 3452 * This method will call {@link evaluateVisible} to determine the visibility of this element.
 3453 * @returns {Boolean} whether this element is visible and should be rendered.
 3454 */
 3455Yii.CFormElement.prototype.getVisible = function () {
 3456		if(this._visible===null) {
 3457			this._visible=this.evaluateVisible();
 3458		}
 3459		return this._visible;
 3460	};
 3461/**
 3462 * @param {Boolean} value whether this element is visible and should be rendered.
 3463 */
 3464Yii.CFormElement.prototype.setVisible = function (value) {
 3465		this._visible=value;
 3466	};
 3467/**
 3468 * @returns {Mixed} the direct parent of this element. This could be either a {@link CForm} object or a {@link CBaseController} object
 3469 * (a controller or a widget).
 3470 */
 3471Yii.CFormElement.prototype.getParent = function () {
 3472		return this._parent;
 3473	};
 3474/**
 3475 * Evaluates the visibility of this element.
 3476 * Child classes should override this method to implement the actual algorithm
 3477 * for determining the visibility.
 3478 * @returns {Boolean} whether this element is visible. Defaults to true.
 3479 */
 3480Yii.CFormElement.prototype.evaluateVisible = function () {
 3481		return true;
 3482	};/*global Yii, php, $, jQuery, alert, clearInterval, clearTimeout, document, event, frames, history, Image, location, name, navigator, Option, parent, screen, setInterval, setTimeout, window, XMLHttpRequest */
 3483/**
 3484 * CBaseController is the base class for {@link CController} and {@link CWidget}.
 3485 * 
 3486 * It provides the common functionalities shared by controllers who need to render views.
 3487 * 
 3488 * CBaseController also implements the support for the following features:
 3489 * <ul>
 3490 * <li>{@link CClipWidget Clips} : a clip is a piece of captured output that can be inserted elsewhere.</li>
 3491 * <li>{@link CWidget Widgets} : a widget is a self-contained sub-controller with its own view and model.</li>
 3492 * <li>{@link COutputCache Fragment cache} : fragment cache selectively caches a portion of the output.</li>
 3493 * </ul>
 3494 * 
 3495 * To use a widget in a view, use the following in the view:
 3496 * <pre>
 3497 * this.widget('path.to.widgetClass',{'property1':'value1',+++});
 3498 * </pre>
 3499 * or
 3500 * <pre>
 3501 * this.beginWidget('path.to.widgetClass',{'property1':'value1',+++});
 3502 * // ... display other contents here
 3503 * this.endWidget();
 3504 * </pre>
 3505 * 
 3506 * To create a clip, use the following:
 3507 * <pre>
 3508 * this.beginClip('clipID');
 3509 * // ... display the clip contents
 3510 * this.endClip();
 3511 * </pre>
 3512 * Then, in a different view or place, the captured clip can be inserted as:
 3513 * <pre>
 3514 * document.write(this.clips['clipID']);
 3515 * </pre>
 3516 * 
 3517 * To use fragment cache, do as follows,
 3518 * <pre>
 3519 * if(this.beginCache('cacheID',{'property1':'value1',+++})
 3520 * {
 3521 *     // ... display the content to be cached here
 3522 *    this.endCache();
 3523 * }
 3524 * </pre>
 3525 * 
 3526 * @originalAuthor Qiang Xue <qiang.xue@gmail.com>
 3527 * @version $Id: CBaseController.php 2799 2011-01-01 19:31:13Z qiang.xue $
 3528 * @package system.web
 3529 * @since 1.0
 3530 * @author Charles Pick
 3531 * @class
 3532 * @extends Yii.CComponent
 3533 */
 3534Yii.CBaseController = function CBaseController() {
 3535};
 3536Yii.CBaseController.prototype = new Yii.CComponent();
 3537Yii.CBaseController.prototype.constructor =  Yii.CBaseController;
 3538Yii.CBaseController.prototype._widgetStack = [];
 3539/**
 3540 * Returns the view script file according to the specified view name.
 3541 * This method must be implemented by child classes.
 3542 * @param {String} viewName view name
 3543 * @returns {String} the file path for the named view. False if the view cannot be found.
 3544 */
 3545Yii.CBaseController.prototype.getViewFile = function (viewName) {
 3546	};
 3547/**
 3548 * Renders a view file.
 3549 * 
 3550 * @param {String} viewFile view file path
 3551 * @param {Array} data data to be extracted and made available to the view
 3552 * @param {Function} callback The callback to execute
 3553 * @throws {Yii.CException} if the view file does not exist
 3554 */
 3555Yii.CBaseController.prototype.renderFile = function (viewFile, data, callback) {
 3556		var renderer;
 3557		if (data === undefined) {
 3558			data = null;
 3559		}
 3560		if((renderer=Yii.app().getViewRenderer())!==undefined && renderer.fileExtension==='.'+(viewFile.split(".").pop())) {
 3561			return renderer.renderFile(this,viewFile,data,callback);
 3562		}
 3563		else {
 3564			return this.renderInternal(viewFile,data,callback);
 3565		}
 3566		
 3567	};
 3568/**
 3569 * Renders a view file.
 3570 * This method includes the view file as a JavaScript script
 3571 * and captures the display result if required.
 3572 * @param {String} viewFile view file
 3573 * @param {Array} data data to be extracted and made available to the view file
 3574 * @param {Function} callback The callback to execute with the rendering result
 3575 * @returns {String} the rendering result. Null if the rendering result is not required.
 3576 */
 3577Yii.CBaseController.prototype.renderInternal = function (_viewFile_, _data_, _callback_) {
 3578		var data;
 3579		if (_data_ === undefined) {
 3580			_data_ = null;
 3581		}
 3582		
 3583		return Yii.include(_viewFile_,true, _callback_);
 3584		
 3585	};
 3586/**
 3587 * Creates a widget and initializes it.
 3588 * This method first creates the specified widget instance.
 3589 * It then configures the widget's properties with the given initial values.
 3590 * At the end it calls {@link CWidget::init} to initialize the widget.
 3591 * Starting from version 1.1, if a {@link CWidgetFactory widget factory} is enabled,
 3592 * this method will use the factory to create the widget, instead.
 3593 * @param {String} className class name (can be in path alias format)
 3594 * @param {Array} properties initial property values
 3595 * @returns {Yii.CWidget} the fully initialized widget instance.
 3596 */
 3597Yii.CBaseController.prototype.createWidget = function (className, properties) {
 3598		var widget;
 3599		if (properties === undefined) {
 3600			properties = [];
 3601		}
 3602		widget=Yii.app().getWidgetFactory().createWidget(this,className,properties);
 3603		
 3604		widget.init();
 3605		return widget;
 3606	};
 3607/**
 3608 * Creates a widget and executes it.
 3609 * @param {String} className the widget class name or class in dot syntax (e.g. application.widgets.MyWidget)
 3610 * @param {Array} properties list of initial property values for the widget (Property Name => Property Value)
 3611 * @param {Boolean} captureOutput whether to capture the output of the widget. If true, the method will capture
 3612 * and return the output generated by the widget. If false, the output will be directly sent for display
 3613 * and the widget object will be returned. This parameter is available since version 1.1.2.
 3614 * @returns {Mixed} the widget instance when $captureOutput is false, or the widget output when $captureOutput is true.
 3615 */
 3616Yii.CBaseController.prototype.widget = function (className, properties, captureOutput) {
 3617		var widget;
 3618		if (properties === undefined) {
 3619			properties = [];
 3620		}
 3621		widget=this.createWidget(className,properties);
 3622		return(widget.run());
 3623		
 3624	};
 3625/**
 3626 * Creates a widget and executes it.
 3627 * This method is similar to {@link widget()} except that it is expecting
 3628 * a {@link endWidget()} call to end the execution.
 3629 * @param {String} className the widget class name or class in dot syntax (e.g. application.widgets.MyWidget)
 3630 * @param {Array} properties list of initial property values for the widget (Property Name => Property Value)
 3631 * @returns {Yii.CWidget} the widget created to run
 3632 * @see endWidget
 3633 */
 3634Yii.CBaseController.prototype.beginWidget = function (className, properties) {
 3635		var widget;
 3636		if (properties === undefined) {
 3637			properties = [];
 3638		}
 3639		widget=this.createWidget(className,properties);
 3640		
 3641		this._widgetStack.push(widget);
 3642		return widget;
 3643	};
 3644/**
 3645 * Ends the execution of the named widget.
 3646 * This method is used together with {@link beginWidget()}.
 3647 * @param {String} id optional tag identifying the method call for debugging purpose.
 3648 * @returns {Yii.CWidget} the widget just ended running
 3649 * @throws {Yii.CException} if an extra endWidget call is made
 3650 * @see beginWidget
 3651 */
 3652Yii.CBaseController.prototype.endWidget = function (id) {
 3653		var widget;
 3654		if (id === undefined) {
 3655			id = '';
 3656		}
 3657		if((widget=php.array_pop(this._widgetStack))!==null)
 3658		{
 3659			widget.run();
 3660			return widget;
 3661		}
 3662		else {
 3663			throw new Yii.CException(Yii.t('yii','{controller} has an extra endWidget({id}) call in its view.',
 3664				{'{controller}':php.get_class(this),'{id}':id}));
 3665		}
 3666	};
 3667/**
 3668 * Begins recording a clip.
 3669 * This method is a shortcut to beginning {@link CClipWidget}.
 3670 * @param {String} id the clip ID.
 3671 * @param {Array} properties initial property values for {@link CClipWidget}.
 3672 */
 3673Yii.CBaseController.prototype.beginClip = function (id, properties) {
 3674		if (properties === undefined) {
 3675			properties = [];
 3676		}
 3677		properties.id=id;
 3678		this.beginWidget('CClipWidget',properties);
 3679	};
 3680/**
 3681 * Ends recording a clip.
 3682 * This method is an alias to {@link endWidget}.
 3683 */
 3684Yii.CBaseController.prototype.endClip = function () {
 3685		this.endWidget('CClipWidget');
 3686	};
 3687/**
 3688 * Begins fragment caching.
 3689 * This method will display cached content if it is availabe.
 3690 * If not, it will start caching and would expect a {@link endCache()}
 3691 * call to end the cache and save the content into cache.
 3692 * A typical usage of fragment caching is as follows,
 3693 * <pre>
 3694 * if(this.beginCache(id))
 3695 * {
 3696 *     // ...generate content here
 3697 *     this.endCache();
 3698 * }
 3699 * </pre>
 3700 * @param {String} id a unique ID identifying the fragment to be cached.
 3701 * @param {Array} properties initial property values for {@link COutputCache}.
 3702 * @returns {Boolean} whether we need to generate content for caching. False if cached version is available.
 3703 * @see endCache
 3704 */
 3705Yii.CBaseController.prototype.beginCache = function (id, properties) {
 3706		var cache;
 3707		if (properties === undefined) {
 3708			properties = [];
 3709		}
 3710		properties.id=id;
 3711		cache=this.beginWidget('COutputCache',properties);
 3712		if(cache.getIsContentCached())
 3713		{
 3714			this.endCache();
 3715			return false;
 3716		}
 3717		else {
 3718			return true;
 3719		}
 3720	};
 3721/**
 3722 * Ends fragment caching.
 3723 * This is an alias to {@link endWidget}.
 3724 * @see beginCache
 3725 */
 3726Yii.CBaseController.prototype.endCache = function () {
 3727		this.endWidget('COutputCache');
 3728	};
 3729/**
 3730 * Begins the rendering of content that is to be decorated by the specified view.
 3731 * @param {Mixed} view the name of the view that will be used to decorate the content. The actual view script
 3732 * is resolved via {@link getViewFile}. If this parameter is null (default),
 3733 * the default layout will be used as the decorative view.
 3734 * Note that if the current controller does not belong to
 3735 * any module, the default layout refers to the application's {@link CWebApplication::layout default layout};
 3736 * If the controller belongs to a module, the default layout refers to the module's
 3737 * {@link CWebModule::layout default layout}.
 3738 * @param {Object} data the variables (name=>value) to be extracted and made available in the decorative view.
 3739 * This parameter has been available since version 1.0.4
 3740 * @see beginContent
 3741 * @see CContentDecorator
 3742 */
 3743Yii.CBaseController.prototype.beginContent = function (view, data) {
 3744		if (view === undefined) {
 3745			view = null;
 3746		}
 3747		if (data === undefined) {
 3748			data = {};
 3749		}
 3750		this.beginWidget('CContentDecorator',{'view':view, 'data':data});
 3751	};
 3752/**
 3753 * Ends the rendering of content.
 3754 * @see beginContent
 3755 */
 3756Yii.CBaseController.prototype.endContent = function () {
 3757		this.endWidget('CContentDecorator');
 3758	}/*global Yii, php, $, jQuery, alert, clearInterval, clearTimeout, document, event, frames, history, Image, location, name, navigator, Option, parent, screen, setInterval, setTimeout, window, XMLHttpRequest */
 3759/**
 3760 * CWidget is the base class for widgets.
 3761 * 
 3762 * A widget is a self-contained component that may generate presentation
 3763 * based on model data.  It can be viewed as a micro-controller that embeds
 3764 * into the controller-managed views.
 3765 * 
 3766 * Compared with {@link CController controller}, a widget has neither actions nor filters.
 3767 * 
 3768 * Usage is described at {@link CBaseController} and {@link CBaseController::widget}.
 3769 * 
 3770 * @originalAuthor Qiang Xue <qiang.xue@gmail.com>
 3771 * @version $Id: CWidget.php 3097 2011-03-17 20:01:03Z qiang.xue $
 3772 * @package system.web.widgets
 3773 * @since 1.0
 3774 * @author Charles Pick
 3775 * @class
 3776 * @extends Yii.CBaseController
 3777 */
 3778Yii.CWidget = function CWidget() {
 3779};
 3780Yii.CWidget.prototype = new Yii.CBaseController();
 3781Yii.CWidget.prototype.constructor =  Yii.CWidget;
 3782/**
 3783 * @var {String} the prefix to the IDs of the {@link actions}.
 3784 * When a widget is declared an action provider in {@link CController::actions},
 3785 * a prefix can be specified to differentiate its action IDs from others.
 3786 * The same prefix should then also be used to configure this property
 3787 * when the widget is used in a view of the controller.
 3788 * @since 1.0.1
 3789 */
 3790Yii.CWidget.prototype.actionPrefix = null;
 3791/**
 3792 * @var {Mixed} the name of the skin to be used by this widget. Defaults to 'default'.
 3793 * If this is set as false, no skin will be applied to this widget.
 3794 * @see CWidgetFactory
 3795 * @since 1.1
 3796 */
 3797Yii.CWidget.prototype.skin = 'default';
 3798/**
 3799 * @var {Object} view paths for different types of widgets
 3800 */
 3801Yii.CWidget.prototype._viewPaths = {};
 3802/**
 3803 * @var {Integer} the counter for generating implicit IDs.
 3804 */
 3805Yii.CWidget.prototype._counter = 0;
 3806/**
 3807 * @var {String} id of the widget.
 3808 */
 3809Yii.CWidget.prototype._id = null;
 3810/**
 3811 * @var {Yii.CBaseController} owner/creator of this widget. It could be either a widget or a controller.
 3812 */
 3813Yii.CWidget.prototype._owner = null;
 3814/**
 3815 * Returns a list of actions that are used by this widget.
 3816 * The structure of this method's return value is similar to
 3817 * that returned by {@link CController::actions}.
 3818 * 
 3819 * When a widget uses several actions, you can declare these actions using
 3820 * this method. The widget will then become an action provider, and the actions
 3821 * can be easily imported into a controller.
 3822 * 
 3823 * Note, when creating URLs referring to the actions listed in this method,
 3824 * make sure the action IDs are prefixed with {@link actionPrefix}.
 3825 * 
 3826 * @see actionPrefix
 3827 * @see CController::actions
 3828 * @since 1.0.1
 3829 */
 3830Yii.CWidget.prototype.actions = function () {
 3831		return [];
 3832	};
 3833/**
 3834 * Constructor.
 3835 * @param {Yii.CBaseController} owner owner/creator of this widget. It could be either a widget or a controller.
 3836 */
 3837Yii.CWidget.prototype.construct = function (owner) {
 3838		if (owner === undefined) {
 3839			owner = null;
 3840		}
 3841		this._owner=owner===null?Yii.app().getController():owner;
 3842	};
 3843/**
 3844 * Returns the owner/creator of this widget.
 3845 * @returns {Yii.CBaseController} owner/creator of this widget. It could be either a widget or a controller.
 3846 */
 3847Yii.CWidget.prototype.getOwner = function () {
 3848		return this._owner;
 3849	};
 3850/**
 3851 * Returns the ID of the widget or generates a new one if requested.
 3852 * @param {Boolean} autoGenerate whether to generate an ID if it is not set previously
 3853 * @returns {String} id of the widget.
 3854 */
 3855Yii.CWidget.prototype.getId = function (autoGenerate) {
 3856		var _counter;
 3857		if (autoGenerate === undefined) {
 3858			autoGenerate = true;
 3859		}
 3860		if(this._id!==null) {
 3861			return this._id;
 3862		}
 3863		else if(autoGenerate) {
 3864			return (this._id='yw'+Yii.CWidget.prototype._counter++);
 3865		}
 3866	};
 3867/**
 3868 * Sets the ID of the widget.
 3869 * @param {String} value id of the widget.
 3870 */
 3871Yii.CWidget.prototype.setId = function (value) {
 3872		this._id=value;
 3873	};
 3874/**
 3875 * Returns the controller that this widget belongs to.
 3876 * @returns {Yii.CController} the controller that this widget belongs to.
 3877 */
 3878Yii.CWidget.prototype.getController = function () {
 3879		if(this._owner instanceof Yii.CController) {
 3880			return this._owner;
 3881		}
 3882		else {
 3883			return Yii.app().getController();
 3884		}
 3885	};
 3886/**
 3887 * Initializes the widget.
 3888 * This method is called by {@link CBaseController::createWidget}
 3889 * and {@link CBaseController::beginWidget} after the widget's
 3890 * properties have been initialized.
 3891 */
 3892Yii.CWidget.prototype.init = function () {
 3893	};
 3894/**
 3895 * Executes the widget.
 3896 * This method is called by {@link CBaseController::endWidget}.
 3897 */
 3898Yii.CWidget.prototype.run = function () {
 3899	};
 3900/**
 3901 * Returns the directory containing the view files for this widget.
 3902 * The default implementation returns the 'views' subdirectory of the directory containing the widget class file.
 3903 * If $checkTheme is set true, the directory "ThemeID/views/ClassName" will be returned when it exists.
 3904 * @param {Boolean} checkTheme whether to check if the theme contains a view path for the widget.
 3905 * @returns {String} the directory containing the view files for this widget.
 3906 */
 3907Yii.CWidget.prototype.getViewPath = function (checkTheme) {
 3908		var className, _viewPaths, theme, path, viewFolder, pathParts;
 3909		if (checkTheme === undefined) {
 3910			checkTheme = false;
 3911		}
 3912		className=php.get_class(this);
 3913		if(Yii.CWidget.prototype._viewPaths[className] !== undefined) {
 3914			return Yii.CWidget.prototype._viewPaths[className];
 3915		}
 3916		else
 3917		{
 3918			if(checkTheme && (theme=Yii.app().getTheme())!==null) {
 3919				path=theme.getViewPath()+"/";
 3920				path+=className;
 3921				return (Yii.CWidget.prototype._viewPaths[className]=path);
 3922			}
 3923			
 3924			viewFolder = php.rtrim(Yii.app().getBasePath(),"/") + '/views/widgets/';
 3925			return (Yii.CWidget.prototype._viewPaths[className]=viewFolder + className);
 3926		}
 3927	};
 3928/**
 3929 * Looks for the view script file according to the view name.
 3930 * This method will look for the view under the widget's {@link getViewPath viewPath}.
 3931 * The view script file is named as "ViewName.php". A localized view file
 3932 * may be returned if internationalization is needed. See {@link CApplication::findLocalizedFile}
 3933 * for more details.
 3934 * Since version 1.0.2, the view name can also refer to a path alias
 3935 * if it contains dot characters.
 3936 * @param {String} viewName name of the view (without file extension)
 3937 * @returns {String} the view file path. False if the view file does not exist
 3938 * @see CApplication::findLocalizedFile
 3939 */
 3940Yii.CWidget.prototype.getViewFile = function (viewName) {
 3941		var renderer, extension, viewFile;
 3942		if((renderer=Yii.app().getViewRenderer())!==undefined) {
 3943			extension=renderer.fileExtension;
 3944		}
 3945		else {
 3946			extension='.js';
 3947		}
 3948		if(php.strpos(viewName,'.')) { // a path alias
 3949			viewFile=Yii.getPathOfAlias(viewName);
 3950		}
 3951		else {
 3952			viewFile=this.getViewPath(true)+'/'+viewName;
 3953			return Yii.app().findLocalizedFile(viewFile+extension);
 3954		
 3955		}
 3956		if(is_file(viewFile+extension)) {
 3957			return Yii.app().findLocalizedFile(viewFile+extension);
 3958		}
 3959		else if(extension!=='.js' && is_file(viewFile+'.js')) {
 3960			return Yii.app().findLocalizedFile(viewFile+'.js');
 3961		}
 3962		else {
 3963			return false;
 3964		}
 3965	};
 3966/**
 3967 * Renders a view.
 3968 * 
 3969 * The named view refers to a PHP script (resolved via {@link getViewFile})
 3970 * that is included by this method. If $data is an associative array,
 3971 * it will be extracted as PHP variables and made available to the script.
 3972 * 
 3973 * @param {String} view name of the view to be rendered. See {@link getViewFile} for details
 3974 * about how the view script is resolved.
 3975 * @param {Array} data data to be extracted into PHP variables and made available to the view script
 3976 * @param {Boolean} returnVar whether the rendering result should be returned instead of being displayed to end users
 3977 * @returns {String} the rendering result. Null if the rendering result is not required.
 3978 * @throws {Yii.CException} if the view does not exist
 3979 * @see getViewFile
 3980 */
 3981Yii.CWidget.prototype.render = function (view, data, returnVar) {
 3982		var viewFile;
 3983		if (data === undefined) {
 3984			data = null;
 3985		}
 3986		if (returnVar === undefined) {
 3987			returnVar = false;
 3988		}
 3989		if((viewFile=this.getViewFile(view))!==false) {
 3990			return this.renderFile(viewFile,data,returnVar);
 3991		}
 3992		else {
 3993			throw new Yii.CException(Yii.t('yii','{widget} cannot find the view "{view}".',
 3994				{'{widget}':php.get_class(this), '{view}':view}));
 3995		}
 3996	}/*global Yii, php, $, jQuery, alert, clearInterval, clearTimeout, document, event, frames, history, Image, location, name, navigator, Option, parent, screen, setInterval, setTimeout, window, XMLHttpRequest */
 3997/**
 3998 * CLogRoute is the base class for all log route classes.
 3999 * 
 4000 * A log route object retrieves log messages from a logger and sends it
 4001 * somewhere, such as files, emails.
 4002 * The messages being retrieved may be filtered first before being sent
 4003 * to the destination. The filters include log level filter and log category filter.
 4004 * 
 4005 * To specify level filter, set {@link levels} property,
 4006 * which takes a string of comma-separated desired level names (e.g. 'Error, Debug').
 4007 * To specify category filter, set {@link categories} property,
 4008 * which takes a string of comma-separated desired category names (e.g. 'System.Web, System.IO').
 4009 * 
 4010 * Level filter and category filter are combinational, i.e., only messages
 4011 * satisfying both filter conditions will they be returned.
 4012 * 
 4013 * @originalAuthor Qiang Xue <qiang.xue@gmail.com>
 4014 * @version $Id: CLogRoute.php 3001 2011-02-24 16:42:44Z alexander.makarow $
 4015 * @package system.logging
 4016 * @since 1.0
 4017 * @author Charles Pick
 4018 * @class
 4019 * @extends Yii.CComponent
 4020 */
 4021Yii.CLogRoute = function CLogRoute () {
 4022};
 4023Yii.CLogRoute.prototype = new Yii.CComponent();
 4024Yii.CLogRoute.prototype.constructor =  Yii.CLogRoute;
 4025/**
 4026 * @var {Boolean} whether to enable this log route. Defaults to true.
 4027 * @since 1.0.7
 4028 */
 4029Yii.CLogRoute.prototype.enabled = true;
 4030/**
 4031 * @var {String} list of levels separated by comma or space. Defaults to empty, meaning all levels.
 4032 */
 4033Yii.CLogRoute.prototype.levels = '';
 4034/**
 4035 * @var {String} list of categories separated by comma or space. Defaults to empty, meaning all categories.
 4036 */
 4037Yii.CLogRoute.prototype.categories = '';
 4038/**
 4039 * @var {Mixed} the additional filter (eg {@link CLogFilter}) that can be applied to the log messages.
 4040 * The value of this property will be passed to {@link Yii::createComponent} to create
 4041 * a log filter object. As a result, this can be either a string representing the
 4042 * filter class name or an array representing the filter configuration.
 4043 * In general, the log filter class should be {@link CLogFilter} or a child class of it.
 4044 * Defaults to null, meaning no filter will be used.
 4045 * @since 1.0.6
 4046 */
 4047Yii.CLogRoute.prototype.filter = null;
 4048/**
 4049 * @var {Array} the logs that are collected so far by this log route.
 4050 * @since 1.1.0
 4051 */
 4052Yii.CLogRoute.prototype.logs = null;
 4053/**
 4054 * Initializes the route.
 4055 * This method is invoked after the route is created by the route manager.
 4056 */
 4057Yii.CLogRoute.prototype.init = function () {
 4058	};
 4059/**
 4060 * Formats a log message given different fields.
 4061 * @param {String} message message content
 4062 * @param {Integer} level message level
 4063 * @param {String} category message category
 4064 * @param {Integer} time timestamp
 4065 * @returns {String} formatted message
 4066 */
 4067Yii.CLogRoute.prototype.formatLogMessage = function (message, level, category, time) {
 4068		return php.date('Y/m/d H:i:s',time)+" [" + level + "] [" + category + "] " + message + "\n";
 4069	};
 4070/**
 4071 * Retrieves filtered log messages from logger for further processing.
 4072 * @param {Yii.CLogger} logger logger instance
 4073 * @param {Boolean} processLogs whether to process the logs after they are collected from the logger
 4074 */
 4075Yii.CLogRoute.prototype.collectLogs = function (logger, processLogs) {
 4076		var logs;
 4077		
 4078		if (processLogs === undefined) {
 4079			processLogs = false;
 4080		}
 4081		
 4082		logs=logger.getLogs(this.levels,this.categories);
 4083		this.logs=php.empty(this.logs) ? logs : php.array_merge(this.logs,logs);
 4084		if(processLogs && !php.empty(this.logs)) {
 4085			if(this.filter!==null) {
 4086				Yii.createComponent(this.filter).filter(this.logs);
 4087			}
 4088			this.processLogs(this.logs);
 4089		}
 4090	};
 4091/**
 4092 * Processes log messages and sends them to specific destination.
 4093 * Derived child classes must implement this method.
 4094 * @param {Array} logs list of messages.  Each array elements represents one message
 4095 * with the following structure:
 4096 * array(
 4097 *   [0] => message (string)
 4098 *   [1] => level (string)
 4099 *   [2] => category (string)
 4100 *   [3] => timestamp (float, obtained by microtime(true));
 4101 */
 4102Yii.CLogRoute.prototype.processLogs = function (logs) {
 4103	};/*global Yii, php, $, jQuery, console, alert, clearInterval, clearTimeout, document, event, frames, history, Image, location, name, navigator, Option, parent, screen, setInterval, setTimeout, window, XMLHttpRequest */
 4104/**
 4105 * CWebLogRoute shows the log content in Web page.
 4106 * 
 4107 * The log content can appear either at the end of the current Web page
 4108 * or in FireBug console window (if {@link showInFireBug} is set true).
 4109 * 
 4110 * @originalAuthor Qiang Xue <qiang.xue@gmail.com>
 4111 * @version $Id: CWebLogRoute.php 3001 2011-02-24 16:42:44Z alexander.makarow $
 4112 * @package system.logging
 4113 * @since 1.0
 4114 * @author Charles Pick
 4115 * @class
 4116 * @extends Yii.CLogRoute
 4117 */
 4118Yii.CWebLogRoute = function CWebLogRoute () {
 4119};
 4120Yii.CWebLogRoute.prototype = new Yii.CLogRoute();
 4121Yii.CWebLogRoute.prototype.constructor =  Yii.CWebLogRoute;
 4122/**
 4123 * @var {Boolean} whether the log should be displayed in FireBug instead of browser window. Defaults to false.
 4124 */
 4125Yii.CWebLogRoute.prototype.showInFireBug = false;
 4126/**
 4127 * @var {Boolean} whether the log should be ignored in FireBug for ajax calls. Defaults to true.
 4128 * This option should be used carefully, because an ajax call returns all output as a result data.
 4129 * For example if the ajax call expects a json type result any output from the logger will cause ajax call to fail.
 4130 */
 4131Yii.CWebLogRoute.prototype.ignoreAjaxInFireBug = true;
 4132/**
 4133 * Displays the log messages.
 4134 * @param {Array} logs list of log messages
 4135 */
 4136Yii.CWebLogRoute.prototype.processLogs = function (logs) {
 4137		var logView = [], i, limit, log;
 4138		limit = logs.length;
 4139		for (i = 0; i < limit; i++) {
 4140			log = logs[i];
 4141			logView.push({
 4142				'time': php.date('H:i:s.',log[3]) + php.sprintf('%06d',Number((log[3]-Number(log[3]))*1000000)),
 4143				'level': log[1],
 4144				'category': log[2],
 4145				'message': log[0]
 4146			});
 4147		}
 4148		if (this.showInFireBug) {
 4149			if (console.group !== undefined) {
 4150				console.group("Application Log");
 4151			}
 4152			Yii.forEach(logView, function (index, log) {
 4153				var func;
 4154				if (log[1] === Yii.CLogger.prototype.LEVEL_WARNING) {
 4155					func = "warn";
 4156				}
 4157				else if (log[2] === Yii.CLogger.prototype.LEVEL_ERROR) {
 4158					func = "error";
 4159				}
 4160				else {
 4161					func = "log";
 4162				}
 4163				if (console[func] === undefined) {
 4164					func = "log";
 4165				}
 4166				console[func]("[" + log.time + "] [" + log.level + "] [" + log.category + "] " + log.message);
 4167			});
 4168			if (console.group !== undefined) {
 4169				console.groupEnd();
 4170			}
 4171		}
 4172		else {
 4173			this.render('log',logView);
 4174		}
 4175	};
 4176/**
 4177 * Renders the view.
 4178 * @param {String} view the view name (file name without extension). The file is assumed to be located under framework/data/views.
 4179 * @param {Array} data data to be passed to the view
 4180 */
 4181Yii.CWebLogRoute.prototype.render = function (view, data) {
 4182		var app, isAjax, viewFile;
 4183		
 4184		app=Yii.app();
 4185		isAjax=app.getRequest().getIsAjaxRequest();
 4186		if(this.showInFireBug) {
 4187			if(isAjax && this.ignoreAjaxInFireBug) {
 4188				return;
 4189			}
 4190			view+='-firebug';
 4191		}
 4192		else if(!(app instanceof Yii.CWebApplication) || isAjax) {
 4193			return;
 4194		}
 4195		viewFile='system.views.'+view;
 4196		jQuery("body").append(Yii.CController.prototype.renderPartial(viewFile, {data: data},true));
 4197	};/*global Yii, php, $, jQuery, alert, clearInterval, clearTimeout, document, event, frames, history, Image, location, name, navigator, Option, parent, screen, setInterval, setTimeout, window, XMLHttpRequest */
 4198/**
 4199 * CView is a base class for views
 4200 * 
 4201 * @package system.web
 4202 * @since 1.0
 4203 * @author Charles Pick
 4204 * @class
 4205 * @extends Yii.CComponent
 4206 */
 4207Yii.CView = function CView (config) {
 4208	if (config !== false) {
 4209		this.template = null;
 4210		this.construct(config);
 4211	}
 4212};
 4213Yii.CView.prototype = new Yii.CComponent();
 4214Yii.CView.prototype.constructor =  Yii.CView;
 4215/**
 4216 * Holds a list of registered views
 4217 */
 4218Yii.CView.prototype._views = {};
 4219
 4220/**
 4221 * Holds a list of cached templates
 4222 * @var Object
 4223 */
 4224Yii.CView.prototype._templates = {};
 4225/**
 4226 * The content of the template that should be used to render this view
 4227 * @var String
 4228 */
 4229Yii.CView.prototype.template = null;
 4230
 4231/**
 4232 * The URL of the template to use for this view.
 4233 * @var String
 4234 */
 4235Yii.CView.prototype.templateURL = null;
 4236
 4237/**
 4238 * The layout view to use when rendering, if none specified
 4239 * the default layout will be used.
 4240 * @var Yii.CView 
 4241 */
 4242Yii.CView.prototype.layout = null;
 4243
 4244/**
 4245 * jQuery events to delegate for this view.
 4246 * Array should be of the following format:
 4247 * <pre>
 4248 * [
 4249 * 	['#selector a.someLink', 'click', function (e) { alert("clicked!")}],
 4250 * 	['#selector form', 'submit', function (e) { alert('Submitted!'); e.preventDefault(); }]
 4251 * ] 
 4252 * </pre>
 4253 * These events will be bound to their selectors when the view is rendered
 4254 * @var Array
 4255 */
 4256Yii.CView.prototype.delegates = [];
 4257/**
 4258 * Registers a view that can be rendered later
 4259 * @param {String} alias The alias for this view so it can be retrieved later
 4260 * @param {Object} config An object that will be used as a configuration for a new CView
 4261 */
 4262Yii.CView.prototype.registerView = function (alias, config) {
 4263	var url;
 4264	if (alias.indexOf("/") === -1) {
 4265		url = Yii.getPathOfAlias(alias) + ".js";
 4266	}
 4267	else {
 4268		url = alias;
 4269	}
 4270	Yii.CView.prototype._views[url] = config;
 4271};
 4272
 4273/**
 4274 * Loads a particular view and executes the callback
 4275 * @param {String} alias The alias of the view to load
 4276 * @param {Function} callback The callback to execute, it will receive the loaded view as first parameter
 4277 */
 4278Yii.CView.prototype.load = function (alias, callback) {
 4279	var config, view, className, url;
 4280	if (alias.indexOf("/") === -1) {
 4281		url = Yii.getPathOfAlias(alias) + ".js";
 4282	}
 4283	else {
 4284		url = alias;
 4285	}
 4286	config = Yii.CView.prototype._views[url];
 4287	
 4288	if (config === undefined) {
 4289		// load the view
 4290		
 4291		Yii.include(url, true, function() {
 4292			config = Yii.CView.prototype._views[url];
 4293			
 4294			if (config === undefined) {
 4295				throw new Yii.CHttpException(404, "No such view: " + url);
 4296			}
 4297			if (config['class'] === undefined) {
 4298				className = "CView";
 4299			}
 4300			else {
 4301				className = config['class'];
 4302				delete config['class'];
 4303			}
 4304			return callback(new Yii[className](config));
 4305		});
 4306	}
 4307	else {
 4308		if (config['class'] === undefined) {
 4309			className = "CView";
 4310		}
 4311		else {
 4312			className = config['class'];
 4313			delete config['class'];
 4314		}
 4315		return callback(new Yii[className](config));
 4316	}
 4317}
 4318
 4319/**
 4320 * Constructs the view and applies the given configuration
 4321 */
 4322Yii.CView.prototype.construct = function (config) {
 4323	var self = this;
 4324	if (config === undefined) {
 4325		return;
 4326	}
 4327	Yii.forEach(config, function (key, value) {
 4328		self[key] = value;
 4329	});
 4330}
 4331/**
 4332 * Renders the view wrapped in the layout
 4333 * @param {Function} callback The function to execute after the view has been rendered
 4334 */
 4335Yii.CView.prototype.render = function (callback) {
 4336	var func, self = this;
 4337	if (this.layout === null) {
 4338		this.renderPartial(callback);
 4339	}
 4340	else {
 4341		this.load(this.layout, function(layout) {
 4342			func = function(html) {
 4343				layout.content = html;
 4344				layout.render(callback);
 4345			}
 4346			self.renderPartial(func);
 4347		});
 4348		
 4349	}
 4350};
 4351
 4352/**
 4353 * Renders the view
 4354 * @param {Function} callback The function to execute after the view has been rendered
 4355 */
 4356Yii.CView.prototype.renderPartial = function (callback) {
 4357	var elements = {}, dependencies = [], stack = [], self = this, output = "", func;
 4358	Yii.forEach(this, function(name, value) {
 4359		if (name.slice(0,1) !== "_") {
 4360			elements[name] = value;
 4361			if (value instanceof Yii.CView) {
 4362				dependencies.push(name);
 4363			}
 4364		}
 4365	});
 4366	Yii.forEach(this.delegates, function(i, item) {
 4367		jQuery("body").undelegate(item[0], item[1]).delegate(item[0], item[1], item[2]);
 4368	});
 4369	func = function() {
 4370		self.getTemplate(function(template) {
 4371			callback(Mustache.to_html(template, self), self);
 4372			
 4373		});
 4374	}
 4375	if (dependencies.length > 0) {
 4376		// can only call this callback when the others have completed.
 4377		stack.push(func);
 4378		Yii.forEach(dependencies, function(i, name) {
 4379			stack.push(function() {
 4380				self[name].renderPartial(function(output, parent) {
 4381					self[name] = output;
 4382					stack.pop()();
 4383				});
 4384			});
 4385			
 4386		});
 4387		return stack.pop()();
 4388	}
 4389	else {
 4390		func();
 4391	}
 4392};
 4393
 4394
 4395/**
 4396 * Gets the contents of the template
 4397 * @param {Function} callback The function to execute after retrieving the template contents
 4398 * @returns {String} the template contents
 4399 */
 4400Yii.CView.prototype.getTemplate = function (callback) {
 4401	var self = this, url;
 4402	
 4403	if (this.template === null) {
 4404		url = this.templateURL;
 4405		if (url.indexOf("/") === -1 && url.indexOf(".") !== -1) {
 4406			url = Yii.getPathOfAlias(url) + ".tpl";
 4407		}
 4408		if (this._templates[url] !== undefined) {
 4409			this.template = this._templates[url];
 4410			callback(this.template, this);
 4411		}
 4412		else {
 4413			jQuery.ajax(url, {
 4414				success: function(data) {
 4415					self._templates[url] = data;
 4416					self.template = data;
 4417					callback(self.template, self);
 4418				},
 4419				error: function (xhr) {
 4420					self._template = "ERROR: " + xhr.responseText;
 4421					callback(self.template, self);
 4422				}
 4423								
 4424			});
 4425		}
 4426	}
 4427	else {
 4428		callback(this.template, this);
 4429	}
 4430	return this.template;
 4431};
 4432
 4433/**
 4434 * Sets the contents of the template
 4435 * @param {String} value The template contents
 4436 */
 4437Yii.CView.prototype.setTemplate = function (value) {
 4438	this.template = value;
 4439}
 4440/*global Yii, php, $, jQuery, alert, clearInterval, clearTimeout, document, event, frames, history, Image, location, name, navigator, Option, parent, screen, setInterval, setTimeout, window, XMLHttpRequest */
 4441/**
 4442 * CApplication is the base class for all application classes.
 4443 * 
 4444 * An application serves as the global context that the user request
 4445 * is being processed. It manages a set of application components that
 4446 * provide specific functionalities to the whole application.
 4447 * 
 4448 * The core application components provided by CApplication are the following:
 4449 * <ul>
 4450 * <li>{@link getErrorHandler errorHandler}: handles JavaScript errors and
 4451 *   uncaught exceptions. This application component is dynamically loaded when needed.</li>
 4452 * <li>{@link getSecurityManager securityManager}: provides security-related
 4453 *   services, such as hashing, encryption. This application component is dynamically
 4454 *   loaded when needed.</li>
 4455 * <li>{@link getStatePersister statePersister}: provides global state
 4456 *   persistence method. This application component is dynamically loaded when needed.</li>
 4457 * <li>{@link getCache cache}: provides caching feature. This application component is
 4458 *   disabled by default.</li>
 4459 * <li>{@link getMessages messages}: provides the message source for translating
 4460 *   application messages. This application component is dynamically loaded when needed.</li>
 4461 * <li>{@link getCoreMessages coreMessages}: provides the message source for translating
 4462 *   Yii framework messages. This application component is dynamically loaded when needed.</li>
 4463 * </ul>
 4464 * 
 4465 * CApplication will undergo the following lifecycles when processing a user request:
 4466 * <ol>
 4467 * <li>load application configuration;</li>
 4468 * <li>set up class autoloader and error handling;</li>
 4469 * <li>load static application components;</li>
 4470 * <li>{@link onBeginRequest}: preprocess the user request;</li>
 4471 * <li>{@link processRequest}: process the user request;</li>
 4472 * <li>{@link onEndRequest}: postprocess the user request;</li>
 4473 * </ol>
 4474 * 
 4475 * Starting from lifecycle 3, if a JavaScript error or an uncaught exception occurs,
 4476 * the application will switch to its error handling logic and jump to step 6 afterwards.
 4477 * 
 4478 * @originalAuthor Qiang Xue <qiang.xue@gmail.com>
 4479 * @version $Id: CApplication.php 3001 2011-02-24 16:42:44Z alexander.makarow $
 4480 * @package system.base
 4481 * @since 1.0
 4482 * 
 4483 * @property string $basePath Returns the root path of the application.
 4484 * @property CCache $cache Returns the cache component.
 4485 * @property CPhpMessageSource $coreMessages Returns the core message translations.
 4486 * @property CDateFormatter $dateFormatter Returns the locale-dependent date formatter.
 4487 * @property CDbConnection $db Returns the database connection component.
 4488 * @property CErrorHandler $errorHandler Returns the error handler component.
 4489 * @property string $extensionPath Returns the root directory that holds all third-party extensions.
 4490 * @property string $id Returns the unique identifier for the application.
 4491 * @property string $language Returns the language that the user is using and the application should be targeted to.
 4492 * @property CLocale $locale Returns the locale instance.
 4493 * @property string $localeDataPath Returns the directory that contains the locale data.
 4494 * @property CMessageSource $messages Returns the application message translations component.
 4495 * @property CNumberFormatter $numberFormatter The locale-dependent number formatter.
 4496 * @property CHttpRequest $request Returns the request component.
 4497 * @property string $runtimePath Returns the directory that stores runtime files.
 4498 * @property CSecurityManager $securityManager Returns the security manager component.
 4499 * @property CStatePersister $statePersister Returns the state persister component.
 4500 * @property string $timeZone Returns the time zone used by this application.
 4501 * @property CUrlManager $urlManager Returns the URL manager component.
 4502 * @author Charles Pick
 4503 * @class
 4504 * @extends Yii.CModule
 4505 */
 4506Yii.CApplication = function CApplication (config) {
 4507	if (config !== false) {
 4508		this.construct(config);
 4509	}
 4510};
 4511Yii.CApplication.prototype = new Yii.CModule(false);
 4512Yii.CApplication.prototype.constructor =  Yii.CApplication;
 4513/**
 4514 * @var {String} the application name. Defaults to 'My Application'.
 4515 */
 4516Yii.CApplication.prototype.name = 'My Application';
 4517/**
 4518 * @var {String} the charset currently used for the application. Defaults to 'UTF-8'.
 4519 */
 4520Yii.CApplication.prototype.charset = 'UTF-8';
 4521/**
 4522 * @var {String} the language that the application is written in. This mainly refers to
 4523 * the language that the messages and view files are in. Defaults to 'en_us' (US English).
 4524 */
 4525Yii.CApplication.prototype.sourceLanguage = 'en_us';
 4526Yii.CApplication.prototype._id = null;
 4527Yii.CApplication.prototype._basePath = null;
 4528Yii.CApplication.prototype._runtimePath = null;
 4529Yii.CApplication.prototype._extensionPath = null;
 4530Yii.CApplication.prototype._globalState = null;
 4531Yii.CApplication.prototype._stateChanged = null;
 4532Yii.CApplication.prototype._ended = false;
 4533Yii.CApplication.prototype._language = null;
 4534Yii.CApplication.prototype._timezone = null;
 4535/**
 4536 * Processes the request.
 4537 * This is the place where the actual request processing work is done.
 4538 * Derived classes should override this method.
 4539 */
 4540Yii.CApplication.prototype.processRequest = function () {
 4541	};
 4542/**
 4543 * Constructor.
 4544 * @param {Mixed} config application configuration.
 4545 * If a string, it is treated as the path of the file that contains the configuration;
 4546 * If an array, it is the actual configuration information.
 4547 * Please make sure you specify the {@link getBasePath basePath} property in the configuration,
 4548 * which should point to the directory containing all application logic, template and data.
 4549 * If not, the directory will be defaulted to 'protected'.
 4550 */
 4551Yii.CApplication.prototype.construct = function (config) {
 4552		if (config === undefined) {
 4553			config = {};
 4554		}
 4555		Yii.setApplication(this);
 4556		
 4557		// set basePath at early as possible to avoid trouble
 4558		
 4559		if(config.basePath !== undefined) {
 4560			this.setBasePath(config.basePath);
 4561			delete config.basePath;
 4562		}
 4563		else {
 4564			this.setBasePath('protected');
 4565		}
 4566		Yii.setPathOfAlias('application',this.getBasePath());
 4567		Yii.setPathOfAlias('webroot',location.protocol + "//" + location.hostname + "/");
 4568		Yii.setPathOfAlias('ext',this.getBasePath()+'/'+'extensions');
 4569		this.preinit();
 4570		
 4571		this.initSystemHandlers();
 4572		this.registerCoreComponents();
 4573		this.configure(config);
 4574		this.attachBehaviors(this.behaviors);
 4575		this.preloadComponents();
 4576		this.init();
 4577	};
 4578/**
 4579 * Runs the application.
 4580 * This method loads static application components. Derived classes usually overrides this
 4581 * method to do more application-specific tasks.
 4582 * Remember to call the parent implementation so that static application components are loaded.
 4583 */
 4584Yii.CApplication.prototype.run = function () {
 4585		try {
 4586			if(this.hasEventHandler('onBeginRequest')) {
 4587				this.onBeginRequest(new Yii.CEvent(this));
 4588			}
 4589			Yii.beginProfile("Request");
 4590			this.processRequest();
 4591			Yii.endProfile("Request");
 4592			if(this.hasEventHandler('onEndRequest')) {
 4593				this.onEndRequest(new Yii.CEvent(this));
 4594			}
 4595		}
 4596		catch (e) {
 4597			if (e instanceof TypeError) {
 4598				this.displayError("TypeError",e);
 4599			}
 4600			else if (e instanceof Yii.CException) {
 4601				this.displayException(e);
 4602			}
 4603			else {
 4604				this.displayError("Error",e);
 4605			}
 4606		}
 4607	};
 4608/**
 4609 * Terminates the application.
 4610 * This method replaces JavaScript's exit() function by calling
 4611 * {@link onEndRequest} before exiting.
 4612 * @param {Integer} status exit status (value 0 means normal exit while other values mean abnormal exit).
 4613 * @param {Boolean} exit whether to exit the current request. This parameter has been available since version 1.1.5.
 4614 * It defaults to true, meaning the JavaScript's exit() function will be called at the end of this method.
 4615 */
 4616Yii.CApplication.prototype.end = function (status, exit) {
 4617		if (status === undefined) {
 4618			status = 0;
 4619		}
 4620		if (exit === undefined) {
 4621			exit = true;
 4622		}
 4623		if(this.hasEventHandler('onEndRequest')) {
 4624			this.onEndRequest(new Yii.CEvent(this));
 4625		}
 4626		if(exit) {
 4627			exit(status);
 4628		}
 4629	};
 4630/**
 4631 * Raised right BEFORE the application processes the request.
 4632 * @param {Yii.CEvent} event the event parameter
 4633 */
 4634Yii.CApplication.prototype.onBeginRequest = function (event) {
 4635		this.raiseEvent('onBeginRequest',event);
 4636	};
 4637/**
 4638 * Raised right AFTER the application processes the request.
 4639 * @param {Yii.CEvent} event the event parameter
 4640 */
 4641Yii.CApplication.prototype.onEndRequest = function (event) {
 4642		if(!this._ended) {
 4643			this._ended=true;
 4644			this.raiseEvent('onEndRequest',event);
 4645		}
 4646	};
 4647/**
 4648 * Returns the unique identifier for the application.
 4649 * @returns {String} the unique identifier for the application.
 4650 */
 4651Yii.CApplication.prototype.getId = function () {
 4652		if(this._id!==null) {
 4653			return this._id;
 4654		}
 4655		else {
 4656			return (this._id=php.sprintf('%x',php.crc32(this.getBasePath()+this.name)));
 4657		}
 4658	};
 4659/**
 4660 * Sets the unique identifier for the application.
 4661 * @param {String} id the unique identifier for the application.
 4662 */
 4663Yii.CApplication.prototype.setId = function (id) {
 4664		this._id=id;
 4665	};
 4666/**
 4667 * Returns the root path of the application.
 4668 * @returns {String} the root directory of the application. Defaults to 'protected'.
 4669 */
 4670Yii.CApplication.prototype.getBasePath = function () {
 4671		return this._basePath;
 4672	};
 4673/**
 4674 * Sets the root directory of the application.
 4675 * This method can only be invoked at the begin of the constructor.
 4676 * @param {String} path the root directory of the application.
 4677 */
 4678Yii.CApplication.prototype.setBasePath = function (path) {
 4679		this._basePath = path;
 4680	};
 4681/**
 4682 * Returns the directory that stores runtime files.
 4683 * @returns {String} the directory that stores runtime files. Defaults to 'protected/runtime'.
 4684 */
 4685Yii.CApplication.prototype.getRuntimePath = function () {
 4686		if(this._runtimePath!==null) {
 4687			return this._runtimePath;
 4688		}
 4689		else
 4690		{
 4691			this.setRuntimePath(this.getBasePath()+"/runtime");
 4692			return this._runtimePath;
 4693		}
 4694	};
 4695/**
 4696 * Sets the directory that stores runtime files.
 4697 * @param {String} path the directory that stores runtime files.
 4698 */
 4699Yii.CApplication.prototype.setRuntimePath = function (path) {
 4700		this._runtimePath= path;
 4701	};
 4702/**
 4703 * Returns the root directory that holds all third-party extensions.
 4704 * @returns {String} the directory that contains all extensions. Defaults to the 'extensions' directory under 'protected'.
 4705 */
 4706Yii.CApplication.prototype.getExtensionPath = function () {
 4707		return Yii.getPathOfAlias('ext');
 4708	};
 4709/**
 4710 * Sets the root directory that holds all third-party extensions.
 4711 * @param {String} path the directory that contains all third-party extensions.
 4712 */
 4713Yii.CApplication.prototype.setExtensionPath = function (path) {
 4714		Yii.setPathOfAlias('ext',path);
 4715	};
 4716/**
 4717 * Returns the language that the user is using and the application should be targeted to.
 4718 * @returns {String} the language that the user is using and the application should be targeted to.
 4719 * Defaults to the {@link sourceLanguage source language}.
 4720 */
 4721Yii.CApplication.prototype.getLanguage = function () {
 4722		return this._language===null ? this.sourceLanguage : this._language;
 4723	};
 4724/**
 4725 * Specifies which language the application is targeted to.
 4726 * 
 4727 * This is the language that the application displays to end users.
 4728 * If set null, it uses the {@link sourceLanguage source language}.
 4729 * 
 4730 * Unless your application needs to support multiple languages, you should always
 4731 * set this language to null to maximize the application's performance.
 4732 * @param {String} language the user language (e.g. 'en_US', 'zh_CN').
 4733 * If it is null, the {@link sourceLanguage} will be used.
 4734 */
 4735Yii.CApplication.prototype.setLanguage = function (language) {
 4736		this._language=language;
 4737	};
 4738/**
 4739 * Returns the time zone used by this application.
 4740 * @returns {String} the time zone used by this application.
 4741 * @see http://php.net/manual/en/function.date-default-timezone-get.php
 4742 * @since 1.0.9
 4743 */
 4744Yii.CApplication.prototype.getTimeZone = function () {
 4745		if (this._timezone === null) {
 4746			this._timezone = jzTimezoneDetector.determine_timezone().timezone.olson_tz;
 4747		}
 4748		return this._timezone;
 4749	};
 4750/**
 4751 * Sets the time zone used by this application.
 4752 * This is a simple wrapper of JavaScript function date_default_timezone_set().
 4753 * @param {String} value the time zone used by this application.
 4754 * @see http://php.net/manual/en/function.date-default-timezone-set.php
 4755 * @since 1.0.9
 4756 */
 4757Yii.CApplication.prototype.setTimeZone = function (value) {
 4758		this._timezone = value;
 4759	};
 4760/**
 4761 * Returns the localized version of a specified file.
 4762 * 
 4763 * The searching is based on the specified language code. In particular,
 4764 * a file with the same name will be looked for under the subdirectory
 4765 * named as the locale ID. For example, given the file "path/to/view.php"
 4766 * and locale ID "zh_cn", the localized file will be looked for as
 4767 * "path/to/zh_cn/view.php". If the file is not found, the original file
 4768 * will be returned.
 4769 * 
 4770 * For consistency, it is recommended that the locale ID is given
 4771 * in lower case and in the format of LanguageID_RegionID (e.g. "en_us").
 4772 * 
 4773 * @param {String} srcFile the original file
 4774 * @param {String} srcLanguage the language that the original file is in. If null, the application {@link sourceLanguage source language} is used.
 4775 * @param {String} language the desired language that the file should be localized to. If null, the {@link getLanguage application language} will be used.
 4776 * @returns {String} the matching localized file. The original file is returned if no localized version is found
 4777 * or if source language is the same as the desired language.
 4778 */
 4779Yii.CApplication.prototype.findLocalizedFile = function (srcFile, srcLanguage, language) {
 4780		var desiredFile;
 4781		if (srcLanguage === undefined) {
 4782			srcLanguage = null;
 4783		}
 4784		if (language === undefined) {
 4785			language = null;
 4786		}
 4787		if(srcLanguage===null) {
 4788			srcLanguage=this.sourceLanguage;
 4789		}
 4790		if(language===null) {
 4791			language=this.getLanguage();
 4792		}
 4793		if(language===srcLanguage) {
 4794			return srcFile;
 4795		}
 4796		
 4797		// TODO: fix this and determine how to deal with localized files
 4798		return srcFile;
 4799		//desiredFile=php.dirname(srcFile)+DIRECTORY_SEPARATOR+language+DIRECTORY_SEPARATOR+php.basename(srcFile);
 4800		//return is_file(desiredFile) ? desiredFile : srcFile;
 4801	};
 4802/**
 4803 * Returns the locale instance.
 4804 * @param {String} localeID the locale ID (e.g. en_US). If null, the {@link getLanguage application language ID} will be used.
 4805 * @returns {Yii.CLocale} the locale instance
 4806 */
 4807Yii.CApplication.prototype.getLocale = function (localeID) {
 4808		if (localeID === undefined) {
 4809			localeID = null;
 4810		}
 4811		return Yii.CLocale.getInstance(localeID===null?this.getLanguage():localeID);
 4812	};
 4813/**
 4814 * Returns the directory that contains the locale data.
 4815 * @returns {String} the directory that contains the locale data. It defaults to 'framework/i18n/data'.
 4816 * @since 1.1.0
 4817 */
 4818Yii.CApplication.prototype.getLocaleDataPath = function () {
 4819		var dataPath;
 4820		return Yii.CLocale.dataPath===null ? Yii.getPathOfAlias('system.i18n.data') : Yii.CLocale.dataPath;
 4821	};
 4822/**
 4823 * Sets the directory that contains the locale data.
 4824 * @param {String} value the directory that contains the locale data.
 4825 * @since 1.1.0
 4826 */
 4827Yii.CApplication.prototype.setLocaleDataPath = function (value) {
 4828		var dataPath;
 4829		Yii.CLocale.dataPath=value;
 4830	};
 4831/**
 4832 * @returns {Yii.CNumberFormatter} the locale-dependent number formatter.
 4833 * The current {@link getLocale application locale} will be used.
 4834 */
 4835Yii.CApplication.prototype.getNumberFormatter = function () {
 4836		return this.getLocale().getNumberFormatter();
 4837	};
 4838/**
 4839 * Returns the locale-dependent date formatter.
 4840 * @returns {Yii.CDateFormatter} the locale-dependent date formatter.
 4841 * The current {@link getLocale application locale} will be used.
 4842 */
 4843Yii.CApplication.prototype.getDateFormatter = function () {
 4844		return this.getLocale().getDateFormatter();
 4845	};
 4846/**
 4847 * Returns the database connection component.
 4848 * @returns {Yii.CDbConnection} the database connection
 4849 */
 4850Yii.CApplication.prototype.getDb = function () {
 4851		return this.getComponent('db');
 4852	};
 4853/**
 4854 * Returns the error handler component.
 4855 * @returns {Yii.CErrorHandler} the error handler application component.
 4856 */
 4857Yii.CApplication.prototype.getErrorHandler = function () {
 4858		return this.getComponent('errorHandler');
 4859	};
 4860/**
 4861 * Returns the security manager component.
 4862 * @returns {Yii.CSecurityManager} the security manager application component.
 4863 */
 4864Yii.CApplication.prototype.getSecurityManager = function () {
 4865		return this.getComponent('securityManager');
 4866	};
 4867/**
 4868 * Returns the state persister component.
 4869 * @returns {Yii.CStatePersister} the state persister application component.
 4870 */
 4871Yii.CApplication.prototype.getStatePersister = function () {
 4872		return this.getComponent('statePersister');
 4873	};
 4874/**
 4875 * Returns the cache component.
 4876 * @returns {Yii.CCache} the cache application component. Null if the component is not enabled.
 4877 */
 4878Yii.CApplication.prototype.getCache = function () {
 4879		return this.getComponent('cache');
 4880	};
 4881/**
 4882 * Returns the core message translations component.
 4883 * @returns {Yii.CPhpMessageSource} the core message translations
 4884 */
 4885Yii.CApplication.prototype.getCoreMessages = function () {
 4886		return this.getComponent('coreMessages');
 4887	};
 4888/**
 4889 * Returns the application message translations component.
 4890 * @returns {Yii.CMessageSource} the application message translations
 4891 */
 4892Yii.CApplication.prototype.getMessages = function () {
 4893		return this.getComponent('messages');
 4894	};
 4895/**
 4896 * Returns the request component.
 4897 * @returns {Yii.CHttpRequest} the request component
 4898 */
 4899Yii.CApplication.prototype.getRequest = function () {
 4900		return this.getComponent('request');
 4901	};
 4902/**
 4903 * Returns the URL manager component.
 4904 * @returns {Yii.CUrlManager} the URL manager component
 4905 */
 4906Yii.CApplication.prototype.getUrlManager = function () {
 4907		return this.getComponent('urlManager');
 4908	};
 4909/**
 4910 * Returns a global value.
 4911 * 
 4912 * A global value is one that is persistent across users sessions and requests.
 4913 * @param {String} key the name of the value to be returned
 4914 * @param {Mixed} defaultValue the default value. If the named global value is not found, this will be returned instead.
 4915 * @returns {Mixed} the named global value
 4916 * @see setGlobalState
 4917 */
 4918Yii.CApplication.prototype.getGlobalState = function (key, defaultValue) {
 4919		if (defaultValue === undefined) {
 4920			defaultValue = null;
 4921		}
 4922		if(this._globalState===null) {
 4923			
 4924			this.loadGlobalState();
 4925		}
 4926		if(this._globalState[key] !== undefined) {
 4927			return this._globalState[key];
 4928		}
 4929		else {
 4930			return defaultValue;
 4931		}
 4932	};
 4933/**
 4934 * Sets a global value.
 4935 * 
 4936 * A global value is one that is persistent across users sessions and requests.
 4937 * Make sure that the value is serializable and unserializable.
 4938 * @param {String} key the name of the value to be saved
 4939 * @param {Mixed} value the global value to be saved. It must be serializable.
 4940 * @param {Mixed} defaultValue the default value. If the named global value is the same as this value, it will be cleared from the current storage.
 4941 * @see getGlobalState
 4942 */
 4943Yii.CApplication.prototype.setGlobalState = function (key, value, defaultValue) {
 4944		var changed;
 4945		if (defaultValue === undefined) {
 4946			defaultValue = null;
 4947		}
 4948		if(this._globalState===null) {
 4949			this.loadGlobalState();
 4950		}
 4951		changed=this._stateChanged;
 4952		if(value===defaultValue) {
 4953			if(this._globalState[key] !== undefined) {
 4954				delete this._globalState[key];
 4955				this._stateChanged=true;
 4956			}
 4957		}
 4958		else if(this._globalState[key] === undefined || this._globalState[key]!==value) {
 4959			this._globalState[key]=value;
 4960			this._stateChanged=true;
 4961		}
 4962		if(this._stateChanged!==changed) {
 4963			this.saveGlobalState();
 4964		}
 4965	};
 4966/**
 4967 * Clears a global value.
 4968 * 
 4969 * The value cleared will no longer be available in this request and the following requests.
 4970 * @param {String} key the name of the value to be cleared
 4971 */
 4972Yii.CApplication.prototype.clearGlobalState = function (key) {
 4973		this.setGlobalState(key,true,true);
 4974	};
 4975/**
 4976 * Loads the global state data from persistent storage.
 4977 * @see getStatePersister
 4978 * @throws {Yii.CException} if the state persister is not available
 4979 */
 4980Yii.CApplication.prototype.loadGlobalState = function () {
 4981		var persister;
 4982		persister=this.getStatePersister();
 4983		if((this._globalState=persister.load())===null) {
 4984			this._globalState={};
 4985		}
 4986		this._stateChanged=false;
 4987	};
 4988/**
 4989 * Saves the global state data into persistent storage.
 4990 * @see getStatePersister
 4991 * @throws {Yii.CException} if the state persister is not available
 4992 */
 4993Yii.CApplication.prototype.saveGlobalState = function () {
 4994		if(this._stateChanged) {
 4995			this._stateChanged=false;
 4996			this.getStatePersister().save(this._globalState);
 4997		}
 4998	};
 4999/**
 5000 * Handles uncaught JavaScript exceptions.
 5001 * 
 5002 * This method is implemented as a JavaScript exception handler. It requires
 5003 * that constant YII_ENABLE_EXCEPTION_HANDLER be defined true.
 5004 * 
 5005 * This method will first raise an {@link onException} event.
 5006 * If the exception is not handled by any event handler, it will call
 5007 * {@link getErrorHandler errorHandler} to process the exception.
 5008 * 
 5009 * The application will be terminated by this method.
 5010 * 
 5011 * @param {Exception} exception exception that is not caught
 5012 */
 5013Yii.CApplication.prototype.handleException = function (exception) {
 5014		var category, message, event, handler, msg;
 5015		// disable error capturing to avoid recursive errors
 5016		
 5017		category='exception.'+php.get_class(exception);
 5018		if(exception instanceof Yii.CHttpException) {
 5019			category+='.'+exception.statusCode;
 5020		}
 5021		message=exception.message;
 5022		
 5023		Yii.log(message,Yii.CLogger.LEVEL_ERROR,category);
 5024		try
 5025		{
 5026			event=new Yii.CExceptionEvent(this,exception);
 5027			this.onException(event);
 5028			if(!event.handled) {
 5029				// try an error handler
 5030				if((handler=this.getErrorHandler())!==null) {
 5031					handler.handle(event);
 5032				}
 5033				else {
 5034					this.displayException(exception);
 5035				}
 5036			}
 5037		}
 5038		catch(e) {
 5039			this.displayException(e);
 5040		}
 5041		try
 5042		{
 5043			this.end(1);
 5044			return;
 5045		}
 5046		catch(e) {
 5047			// use the most primitive way to log error
 5048			msg = php.get_class(e)+': '+e.message+"\n";
 5049			msg += e.getTraceAsString()+"\n";
 5050			msg += "Previous exception:\n";
 5051			msg += php.get_class(exception)+': '+exception.message+"\n";
 5052			msg += exception.getTraceAsString()+"\n";
 5053			console.log(msg);
 5054			return;
 5055		}
 5056	};
 5057/**
 5058 * Handles JavaScript execution errors such as warnings, notices.
 5059 * 
 5060 * This method is implemented as a JavaScript error handler. It requires
 5061 * that constant YII_ENABLE_ERROR_HANDLER be defined true.
 5062 * 
 5063 * This method will first raise an {@link onError} event.
 5064 * If the error is not handled by any event handler, it will call
 5065 * {@link getErrorHandler errorHandler} to process the error.
 5066 * 
 5067 * The application will be terminated by this method.
 5068 * 
 5069 * @param {Integer} code the level of the error raised
 5070 * @param {String} message the error message
 5071 * @param {String} file the filename that the error was raised in
 5072 * @param {Integer} line the line number the error was raised at
 5073 */
 5074Yii.CApplication.prototype.handleError = function (code, message, file, line) {
 5075		var log = "", trace, t, i, event, handler, msg;
 5076		if(code) {
 5077			log="message (" + file + ":" + line + ")\nStack trace:\n";
 5078			trace=Yii.CException.prototype.stacktrace();
 5079			// skip the first 3 stacks as they do not tell the error position
 5080			if(php.count(trace)>3) {
 5081				trace=php.array_slice(trace,3);
 5082			}
 5083			for (i in trace) {
 5084				if (trace.hasOwnProperty(i)) {
 5085					t = trace[i];
 5086					if(t.file === undefined) {
 5087						t.file='unknown';
 5088					}
 5089					if(t.line === undefined) {
 5090						t.line=0;
 5091					}
 5092					if(t['function'] === undefined) {
 5093						t['function']='unknown';
 5094					}
 5095					log+="#i " + t.file + "(" + t.line + "): ";
 5096					if(t.object !== undefined && (!t.object instanceof Array && t.object !== null && typeof(t.object) === 'object')) {
 5097						log+=php.get_class(t.object)+'.';
 5098					}
 5099					log+= t['function'] + "()\n";
 5100				}
 5101			}
 5102			Yii.log(log, Yii.CLogger.prototype.LEVEL_ERROR, "js");
 5103			try {
 5104				event = new Yii.CErrorEvent(this, code, message, file, line);
 5105				this.onError(event);
 5106				if (!event.handled) {
 5107					// try an error handler
 5108					handler = this.getErrorHandler();
 5109					if (handler !== null) {
 5110						handler.handle(event);
 5111					}
 5112					else {
 5113						this.displayError(code, message, file, line);
 5114					}
 5115				}
 5116			}
 5117			catch (e) {
 5118				this.displayException(e);
 5119			}
 5120			
 5121			try {
 5122				this.end(1);
 5123			}
 5124			catch(e) {
 5125				// use the most primitive way to log error
 5126				msg = php.get_class(e)+': '+e.message+"\n";
 5127				msg += e.getTraceAsString()+"\n";
 5128				msg += "Previous error:\n";
 5129				msg += log + "\n";
 5130				console.log(msg);
 5131				return;
 5132			}
 5133		}			
 5134	};
 5135/**
 5136 * Raised when an uncaught JavaScript exception occurs.
 5137 * 
 5138 * An event handler can set the {@link CExceptionEvent::handled handled}
 5139 * property of the event parameter to be true to indicate no further error
 5140 * handling is needed. Otherwise, the {@link getErrorHandler errorHandler}
 5141 * application component will continue processing the error.
 5142 * 
 5143 * @param {Yii.CExceptionEvent} event event parameter
 5144 */
 5145Yii.CApplication.prototype.onException = function (event) {
 5146		this.raiseEvent('onException',event);
 5147	};
 5148/**
 5149 * Raised when a JavaScript execution error occurs.
 5150 * 
 5151 * An event handler can set the {@link CErrorEvent::handled handled}
 5152 * property of the event parameter to be true to indicate no further error
 5153 * handling is needed. Otherwise, the {@link getErrorHandler errorHandler}
 5154 * application component will continue processing the error.
 5155 * 
 5156 * @param {Yii.CErrorEvent} event event parameter
 5157 */
 5158Yii.CApplication.prototype.onError = function (event) {
 5159		this.raiseEvent('onError',event);
 5160	};
 5161/**
 5162 * Displays the captured JavaScript error.
 5163 * This method displays the error in HTML when there is
 5164 * no active error handler.
 5165 * @param {Integer} code error code
 5166 * @param {String} message error message
 5167 * @param {String} file error file
 5168 * @param {String} line error line
 5169 */
 5170Yii.CApplication.prototype.displayError = function (code, message, file, line) {
 5171		var trace, t, i;
 5172		if(YII_DEBUG) {
 5173			document.write("<h1>JavaScript Error [" + code + "]</h1>\n");
 5174			document.write("<p>" + message + "(" + file + ":" + line + ")</p>\n");
 5175			document.write('<table class="yiiLog" width="100%" cellpadding="2" style="border-spacing:1px;font:11px Verdana, Arial, Helvetica, sans-serif;background:#EEEEEE;color:#666666;">');
 5176			document.write('<tr style="background-color:#ccc;">');
 5177			document.write("<th style='width:120px'>Timestamp</th>");
 5178			document.write("<th>Level</th>");
 5179			document.write("<th>Category</th>");
 5180			document.write("<th>Message</th>");
 5181			document.write("</tr>");
 5182			Yii.forEach(Yii._logger.getLogs(), function (i, log) {
 5183				document.write("<tr><td>" + php.date('H:i:s.',log[3]) + php.sprintf('%06d',Number((log[3]-Number(log[3]))*1000000)) + "</td><td>" + log[1] + "</td><td>" + log[2] + "</td><td>" + log[0] + "</td></tr>");				
 5184			});
 5185			document.write("</table>");
 5186			document.write("<h2>Stack Trace</h2>");
 5187			document.write('<pre>');
 5188			trace=Yii.CException.prototype.stacktrace();
 5189			// skip the first 3 stacks as they do not tell the error position
 5190			if(php.count(trace)>3) {
 5191				trace=php.array_slice(trace,3);
 5192			}
 5193			for (i in trace) {
 5194				if (trace.hasOwnProperty(i)) {
 5195					document.write(trace[i] + "\n");
 5196				}
 5197			}
 5198			document.write("</pre>");
 5199		}
 5200		else {
 5201			document.write("<h1>JavaScript Error [" + code + "]</h1>\n");
 5202			document.write("<p>" + message + "</p>\n");
 5203		}
 5204	};
 5205/**
 5206 * Displays the uncaught JavaScript exception.
 5207 * This method displays the exception in HTML when there is
 5208 * no active error handler.
 5209 * @param {Exception} exception the uncaught exception
 5210 */
 5211Yii.CApplication.prototype.displayException = function (exception) {
 5212		if(YII_DEBUG) {
 5213			document.write('<h1>'+php.get_class(exception)+"</h1>\n");
 5214			document.write('<p>'+exception.getMessage()+'</p>');
 5215			document.write('<pre>'+exception.getTraceAsString()+'</pre>');
 5216		}
 5217		else
 5218		{
 5219			document.write('<h1>'+php.get_class(exception)+"</h1>\n");
 5220			document.write('<p>'+exception.getMessage()+'</p>');
 5221		}
 5222	};
 5223/**
 5224 * Initializes the class autoloader and error handlers.
 5225 */
 5226Yii.CApplication.prototype.initSystemHandlers = function () {
 5227	return;
 5228	window.onerror = function (err, loc) {
 5229		Yii.app().displayError("",err);
 5230		return false;
 5231	};
 5232};
 5233/**
 5234 * Registers the core application components.
 5235 * @see setComponents
 5236 */
 5237Yii.CApplication.prototype.registerCoreComponents = function () {
 5238		var components;
 5239		components={
 5240			'coreMessages':{
 5241				'class':'CJavaScriptMessageSource',
 5242				'language':'en_us',
 5243				'basePath':YII_PATH + '/messages'
 5244			},
 5245			'db':{
 5246				'class':'CDbConnection'
 5247			},
 5248			'messages':{
 5249				'class':'CJavaScriptMessageSource'
 5250			},
 5251			'errorHandler':{
 5252				'class':'CErrorHandler'
 5253			},
 5254			'securityManager':{
 5255				'class':'CSecurityManager'
 5256			},
 5257			'statePersister':{
 5258				'class':'CStatePersister'
 5259			},
 5260			'urlManager':{
 5261				'class':'CUrlManager'
 5262			},
 5263			'request':{
 5264				'class':'CHttpRequest'
 5265			},
 5266			'format':{
 5267				'class':'CFormatter'
 5268			}
 5269		};
 5270		this.setComponents(components);
 5271};/*global Yii, php, $, jQuery, alert, clearInterval, clearTimeout, document, event, frames, history, Image, location, name, navigator, Option, parent, screen, setInterval, setTimeout, window, XMLHttpRequest */
 5272/**
 5273 * CBehavior is a convenient base class for behavior classes.
 5274 * @originalAuthor Qiang Xue <qiang.xue@gmail.com>
 5275 * @version $Id: CBehavior.php 3001 2011-02-24 16:42:44Z alexander.makarow $
 5276 * @package system.base
 5277 * @since 1.0.2
 5278 * @author Charles Pick
 5279 * @class
 5280 * @extends Yii.CComponent
 5281 */
 5282Yii.CBehavior = function CBehavior() {
 5283};
 5284Yii.CBehavior.prototype = new Yii.CComponent();
 5285Yii.CBehavior.prototype.constructor =  Yii.CBehavior;
 5286Yii.CBehavior.prototype._enabled = null;
 5287Yii.CBehavior.prototype._owner = null;
 5288/**
 5289 * Declares events and the corresponding event handler methods.
 5290 * The events are defined by the {@link owner} component, while the handler
 5291 * methods by the behavior class. The handlers will be attached to the corresponding
 5292 * events when the behavior is attached to the {@link owner} component; and they
 5293 * will be detached from the events when the behavior is detached from the component.
 5294 * @returns {Object} events (keys) and the corresponding event handler methods (values).
 5295 */
 5296Yii.CBehavior.prototype.events = function () {
 5297		return {};
 5298	};
 5299/**
 5300 * Attaches the behavior object to the component.
 5301 * The default implementation will set the {@link owner} property
 5302 * and attach event handlers as declared in {@link events}.
 5303 * Make sure you call the parent implementation if you override this method.
 5304 * @param {Yii.CComponent} owner the component that this behavior is to be attached to.
 5305 */
 5306Yii.CBehavior.prototype.attach = function (owner) {
 5307		var eventHandler, event, handler;
 5308		this._owner=owner;
 5309		eventHandler = this.events();
 5310		for (event in eventHandler) {
 5311			if (eventHandler.hasOwnProperty(event)) {
 5312				handler = eventHandler[event];
 5313				owner.attachEventHandler(event,[this,handler]);
 5314			}
 5315		}
 5316	};
 5317/**
 5318 * Detaches the behavior object from the component.
 5319 * The default implementation will unset the {@link owner} property
 5320 * and detach event handlers declared in {@link events}.
 5321 * Make sure you call the parent implementation if you override this method.
 5322 * @param {Yii.CComponent} owner the component that this behavior is to be detached from.
 5323 */
 5324Yii.CBehavior.prototype.detach = function (owner) {
 5325		var eventHandler, event, handler;
 5326		eventHandler = this.events();
 5327		for (event in eventHandler) {
 5328			if (eventHandler.hasOwnProperty(event)) {
 5329				handler = eventHandler[event];
 5330				owner.detachEventHandler(event,[this,handler]);
 5331			}
 5332		}
 5333		this._owner=null;
 5334	};
 5335/**
 5336 * @returns {Yii.CComponent} the owner component that this behavior is attached to.
 5337 */
 5338Yii.CBehavior.prototype.getOwner = function () {
 5339		return this._owner;
 5340	};
 5341/**
 5342 * @returns {Boolean} whether this behavior is enabled
 5343 */
 5344Yii.CBehavior.prototype.getEnabled = function () {
 5345		return this._enabled;
 5346	};
 5347/**
 5348 * @param {Boolean} value whether this behavior is enabled
 5349 */
 5350Yii.CBehavior.prototype.setEnabled = function (value) {
 5351		var eventHandler, event, handler, eventHandlerList;
 5352		if(this._enabled!=value && this._owner) {
 5353			if(value) {
 5354				eventHandler = this.events();
 5355				for (event in eventHandler) {
 5356					if (eventHandler.hasOwnProperty(event)) {
 5357						handler = eventHandler[event];
 5358						this._owner.attachEventHandler(event,[this,handler]);
 5359					}
 5360				}
 5361			}
 5362			else {
 5363				eventHandlerList = this.events();
 5364				for (event in eventHandlerList) {
 5365					if (eventHandlerList.hasOwnProperty(event)) {
 5366						handler = eventHandlerList[event];
 5367						this._owner.detachEventHandler(event,[this,handler]);
 5368					}
 5369				}
 5370			}
 5371		}
 5372		this._enabled=value;
 5373	}/*global Yii, php, $, jQuery, alert, clearInterval, clearTimeout, document, event, frames, history, Image, location, name, navigator, Option, parent, screen, setInterval, setTimeout, window, XMLHttpRequest */
 5374/**
 5375 * CErrorEvent represents the parameter for the {@link CApplication::onError onError} event.
 5376 * 
 5377 * @originalAuthor Qiang Xue <qiang.xue@gmail.com>
 5378 * @version $Id: CErrorEvent.php 2799 2011-01-01 19:31:13Z qiang.xue $
 5379 * @package system.base
 5380 * @since 1.0
 5381 * @author Charles Pick
 5382 * @class
 5383 * @extends Yii.CEvent
 5384 */
 5385Yii.CErrorEvent = function CErrorEvent () {
 5386};
 5387Yii.CErrorEvent.prototype = new Yii.CEvent();
 5388Yii.CErrorEvent.prototype.constructor =  Yii.CErrorEvent;
 5389/**
 5390 * @var {String} error code
 5391 */
 5392Yii.CErrorEvent.prototype.code = null;
 5393/**
 5394 * @var {String} error message
 5395 */
 5396Yii.CErrorEvent.prototype.message = null;
 5397/**
 5398 * @var {String} error message
 5399 */
 5400Yii.CErrorEvent.prototype.file = null;
 5401/**
 5402 * @var {String} error file
 5403 */
 5404Yii.CErrorEvent.prototype.line = null;
 5405/**
 5406 * Constructor.
 5407 * @param {Mixed} sender sender of the event
 5408 * @param {String} code error code
 5409 * @param {String} message error message
 5410 * @param {String} file error file
 5411 * @param {Integer} line error line
 5412 */
 5413Yii.CErrorEvent.prototype.construct = function (sender, code, message, file, line) {
 5414		this.code=code;
 5415		this.message=message;
 5416		this.file=file;
 5417		this.line=line;
 5418		parent.__construct(sender);
 5419	}/*global Yii, php, $, jQuery, alert, clearInterval, clearTimeout, document, event, frames, history, Image, location, name, navigator, Option, parent, screen, setInterval, setTimeout, window, XMLHttpRequest */
 5420/**
 5421 * CExceptionEvent represents the parameter for the {@link CApplication::onException onException} event.
 5422 * 
 5423 * @originalAuthor Qiang Xue <qiang.xue@gmail.com>
 5424 * @version $Id: CExceptionEvent.php 2799 2011-01-01 19:31:13Z qiang.xue $
 5425 * @package system.base
 5426 * @since 1.0
 5427 * @author Charles Pick
 5428 * @class
 5429 * @extends Yii.CEvent
 5430 */
 5431Yii.CExceptionEvent = function CExceptionEvent (sender, exception) {
 5432	this.construct(sender, exception);
 5433};
 5434Yii.CExceptionEvent.prototype = new Yii.CEvent();
 5435Yii.CExceptionEvent.prototype.constructor =  Yii.CExceptionEvent;
 5436/**
 5437 * @var {Yii.CException} the exception that this event is about.
 5438 */
 5439Yii.CExceptionEvent.prototype.exception = null;
 5440/**
 5441 * Constructor.
 5442 * @param {Mixed} sender sender of the event
 5443 * @param {Yii.CException} exception the exception
 5444 */
 5445Yii.CExceptionEvent.prototype.construct = function (sender, exception) {
 5446	this.exception=exception;
 5447	Yii.CEvent.prototype.construct.call(this, sender);
 5448};/*global Yii, php, $, jQuery, alert, clearInterval, clearTimeout, document, event, frames, history, Image, location, name, navigator, Option, parent, screen, setInterval, setTimeout, window, XMLHttpRequest */
 5449/**
 5450 * CHttpException represents an exception caused by invalid operations of end-users.
 5451 * 
 5452 * The HTTP error code can be obtained via {@link statusCode}.
 5453 * Error handlers may use this status code to decide how to format the error page.
 5454 * 
 5455 * @originalAuthor Qiang Xue <qiang.xue@gmail.com>
 5456 * @version $Id: CHttpException.php 2799 2011-01-01 19:31:13Z qiang.xue $
 5457 * @package system.base
 5458 * @since 1.0
 5459 * @author Charles Pick
 5460 * @class
 5461 * @extends Yii.CException
 5462 */
 5463Yii.CHttpException = function CHttpException (status, message, code) {
 5464	
 5465	this.construct(status, message, code);
 5466};
 5467Yii.CHttpException.prototype = new Yii.CException(false);
 5468Yii.CHttpException.prototype.constructor =  Yii.CHttpException;
 5469/**
 5470 * @var {Integer} HTTP status code, such as 403, 404, 500, etc.
 5471 */
 5472Yii.CHttpException.prototype.statusCode = null;
 5473/**
 5474 * Constructor.
 5475 * @param {Integer} status HTTP status code, such as 404, 500, etc.
 5476 * @param {String} message error message
 5477 * @param {Integer} code error code
 5478 */
 5479Yii.CHttpException.prototype.construct = function (status, message, code) {
 5480	if (message === undefined) {
 5481		message = null;
 5482	}
 5483	if (code === undefined) {
 5484		code = 0;
 5485	}
 5486	this.statusCode=status;
 5487	
 5488	Yii.CException.call(this, message, code);
 5489};/*global Yii, php, $, jQuery, alert, clearInterval, clearTimeout, document, event, frames, history, Image, location, name, navigator, Option, parent, screen, setInterval, setTimeout, window, XMLHttpRequest */
 5490/**
 5491 * CModel is the base class providing the common features needed by data model objects.
 5492 * 
 5493 * CModel defines the basic framework for data models that need to be validated.
 5494 * 
 5495 * @originalAuthor Qiang Xue <qiang.xue@gmail.com>
 5496 * @version $Id: CModel.php 3087 2011-03-15 02:08:53Z qiang.xue $
 5497 * @package system.base
 5498 * @since 1.0
 5499 * @author Charles Pick
 5500 * @class
 5501 * @extends Yii.CComponent
 5502 */
 5503Yii.CModel = function CModel () {
 5504};
 5505Yii.CModel.prototype = new Yii.CComponent();
 5506Yii.CModel.prototype.constructor =  Yii.CModel;
 5507Yii.CModel.prototype._errors = {};
 5508Yii.CModel.prototype._validators = null;
 5509Yii.CModel.prototype._scenario = '';
 5510/**
 5511 * Returns the list of attribute names of the model.
 5512 * @returns {Array} list of attribute names.
 5513 * @since 1.0.1
 5514 */
 5515Yii.CModel.prototype.attributeNames = function () {
 5516	
 5517	};
 5518/**
 5519 * Returns the validation rules for attributes.
 5520 *
 5521 * This method should be overridden to declare validation rules.
 5522 * Each rule is an object with the following structure:
 5523 * <pre>
 5524 * {
 5525 * 	attributes: 'attribute list',
 5526 * 	validator: 'validator name',
 5527 *  on: 'scenario name', ...validation parameters...
 5528 * }
 5529 * </pre>
 5530 * where
 5531 * <ul>
 5532 * <li>attributes: specifies the attributes (separated by commas) to be validated;</li>
 5533 * <li>validator: specifies the validator to be used. It can be the name of a model class
 5534 *   method, the name of a built-in validator, or a validator class.
 5535 *   A validation method must have the following signature:
 5536 * <pre>
 5537 * // params refers to validation parameters given in the rule
 5538 * function validatorName(attribute, params)
 5539 * </pre>
 5540 *   A built-in validator refers to one of the validators declared in {@link Yii.CValidator.builtInValidators}.
 5541 *   And a validator class is a class extending {@link Yii.CValidator}.</li>
 5542 * <li>on: this specifies the scenarios when the validation rule should be performed.
 5543 *   Separate different scenarios with commas. If this option is not set, the rule
 5544 *   will be applied in any scenario. Please see {@link Yii.CModel.scenario} for more details about this option.</li>
 5545 * <li>additional parameters are used to initialize the corresponding validator properties.
 5546 *   Please refer to individal validator class API for possible properties.</li>
 5547 * </ul>
 5548 *
 5549 * The following are some examples:
 5550 * <pre>
 5551 * [
 5552 *     {
 5553 *     	attributes: 'username',
 5554 *     	validator: 'required'
 5555 *     },
 5556 *     {
 5557 *     	attributes: 'username',
 5558 *      validator: 'length',
 5559 *      min: 3,
 5560 *      max: 12
 5561 *     },
 5562 *     {
 5563 *     	attributes: 'password',
 5564 *      validator: 'compare',
 5565 *      compareAttribute: 'password2',
 5566 *      on: 'register'
 5567 *     },
 5568 *     {
 5569 *     	attributes: 'password',
 5570 *     	validator: 'authenticate',
 5571 *     	on: 'login'
 5572 *     }
 5573 * ];
 5574 * </pre>
 5575 *
 5576 * @returns {Array} validation rules to be applied when {@link validate()} is called.
 5577 * @see scenario
 5578 */
 5579Yii.CModel.prototype.rules = function () {
 5580		return [];
 5581	};
 5582/**
 5583 * Returns a list of behaviors that this model should behave as.
 5584 * The return value should be an array of behavior configurations indexed by
 5585 * behavior names. Each behavior configuration can be either a string specifying
 5586 * the behavior class or an array of the following structure:
 5587 * <pre>
 5588 * 'behaviorName':{
 5589 *     'class':'path.to.BehaviorClass',
 5590 *     'property1':'value1',
 5591 *     'property2':'value2',
 5592 * }
 5593 * </pre>
 5594 * 
 5595 * Note, the behavior classes must implement {@link IBehavior} or extend from
 5596 * {@link CBehavior}. Behaviors declared in this method will be attached
 5597 * to the model when it is instantiated.
 5598 * 
 5599 * For more details about behaviors, see {@link CComponent}.
 5600 * @returns {Object} the behavior configurations (behavior name=>behavior configuration)
 5601 * @since 1.0.2
 5602 */
 5603Yii.CModel.prototype.behaviors = function () {
 5604		return {};
 5605	};
 5606/**
 5607 * Returns the attribute labels.
 5608 * Attribute labels are mainly used in error messages of validation.
 5609 * By default an attribute label is generated using {@link generateAttributeLabel}.
 5610 * This method allows you to explicitly specify attribute labels.
 5611 * 
 5612 * Note, in order to inherit labels defined in the parent class, a child class needs to
 5613 * merge the parent labels with child labels using functions like array_merge().
 5614 * 
 5615 * @returns {Object} attribute labels (name=>label)
 5616 * @see generateAttributeLabel
 5617 */
 5618Yii.CModel.prototype.attributeLabels = function () {
 5619		return {};
 5620	};
 5621/**
 5622 * Performs the validation.
 5623 * 
 5624 * This method executes the validation rules as declared in {@link rules}.
 5625 * Only the rules applicable to the current {@link scenario} will be executed.
 5626 * A rule is considered applicable to a scenario if its 'on' option is not set
 5627 * or contains the scenario.
 5628 * 
 5629 * Errors found during the validation can be retrieved via {@link getErrors}.
 5630 * 
 5631 * @param {Array} attributes list of attributes that should be validated. Defaults to null,
 5632 * meaning any attribute listed in the applicable validation rules should be
 5633 * validated. If this parameter is given as a list of attributes, only
 5634 * the listed attributes will be validated.
 5635 * @param {Boolean} clearErrors whether to call {@link clearErrors} before performing validation
 5636 * @returns {Boolean} whether the validation is successful without any error.
 5637 * @see beforeValidate
 5638 * @see afterValidate
 5639 */
 5640Yii.CModel.prototype.validate = function (attributes, clearErrors) {
 5641		var i, limit, validatorList, validator;
 5642		if (attributes === undefined) {
 5643			attributes = null;
 5644		}
 5645		if (clearErrors === undefined) {
 5646			clearErrors = true;
 5647		}
 5648		if (clearErrors) {
 5649			this.clearErrors();
 5650		}
 5651		if(this.beforeValidate()) {
 5652			validatorList = this.getValidators();
 5653			
 5654			limit = validatorList.length;
 5655			for (i = 0; i < limit; i++) {
 5656				validator = validatorList[i];
 5657				validator.validate(this,attributes);
 5658			}
 5659			
 5660			this.afterValidate();
 5661			return !this.hasErrors();
 5662		}
 5663		else {
 5664			return false;
 5665		}
 5666	};
 5667/**
 5668 * This method is invoked after a model instance is created by new operator.
 5669 * The default implementation raises the {@link onAfterConstruct} event.
 5670 * You may override this method to do postprocessing after model creation.
 5671 * Make sure you call the parent implementation so that the event is raised properly.
 5672 */
 5673Yii.CModel.prototype.afterConstruct = function () {
 5674		if(this.hasEventHandler('onAfterConstruct')) {
 5675			this.onAfterConstruct(new Yii.CEvent(this));
 5676		}
 5677	};
 5678/**
 5679 * This method is invoked before validation starts.
 5680 * The default implementation calls {@link onBeforeValidate} to raise an event.
 5681 * You may override this method to do preliminary checks before validation.
 5682 * Make sure the parent implementation is invoked so that the event can be raised.
 5683 * @returns {Boolean} whether validation should be executed. Defaults to true.
 5684 * If false is returned, the validation will stop and the model is considered invalid.
 5685 */
 5686Yii.CModel.prototype.beforeValidate = function () {
 5687		var event;
 5688		
 5689		event=new Yii.CModelEvent(this);
 5690		
 5691		this.onBeforeValidate(event);
 5692		return event.isValid;
 5693	};
 5694/**
 5695 * This method is invoked after validation ends.
 5696 * The default implementation calls {@link onAfterValidate} to raise an event.
 5697 * You may override this method to do postprocessing after validation.
 5698 * Make sure the parent implementation is invoked so that the event can be raised.
 5699 */
 5700Yii.CModel.prototype.afterValidate = function () {
 5701		this.onAfterValidate(new Yii.CEvent(this));
 5702	};
 5703/**
 5704 * This event is raised after the model instance is created by new operator.
 5705 * @param {Yii.CEvent} event the event parameter
 5706 * @since 1.0.2
 5707 */
 5708Yii.CModel.prototype.onAfterConstruct = function (event) {
 5709		this.raiseEvent('onAfterConstruct',event);
 5710	};
 5711/**
 5712 * This event is raised before the validation is performed.
 5713 * @param {Yii.CModelEvent} event the event parameter
 5714 * @since 1.0.2
 5715 */
 5716Yii.CModel.prototype.onBeforeValidate = function (event) {
 5717		this.raiseEvent('onBeforeValidate',event);
 5718	};
 5719/**
 5720 * This event is raised after the validation is performed.
 5721 * @param {Yii.CEvent} event the event parameter
 5722 * @since 1.0.2
 5723 */
 5724Yii.CModel.prototype.onAfterValidate = function (event) {
 5725		this.raiseEvent('onAfterValidate',event);
 5726	};
 5727/**
 5728 * Returns all the validators declared in the model.
 5729 * This method differs from {@link getValidators} in that the latter
 5730 * would only return the validators applicable to the current {@link scenario}.
 5731 * Also, since this method return a {@link CList} object, you may
 5732 * manipulate it by inserting or removing validators (useful in behaviors).
 5733 * For example, <code>$model->validatorList->add($newValidator)</code>.
 5734 * The change made to the {@link CList} object will persist and reflect
 5735 * in the result of the next call of {@link getValidators}.
 5736 * @returns {Yii.CList} all the validators declared in the model.
 5737 * @since 1.1.2
 5738 */
 5739Yii.CModel.prototype.getValidatorList = function () {
 5740		if(this._validators===null) {
 5741			this._validators=this.createValidators();
 5742		}
 5743		return this._validators;
 5744	};
 5745/**
 5746 * Returns the validators applicable to the current {@link scenario}.
 5747 * @param {String} attribute the name of the attribute whose validators should be returned.
 5748 * If this is null, the validators for ALL attributes in the model will be returned.
 5749 * @returns {Array} the validators applicable to the current {@link scenario}.
 5750 * @since 1.0.1
 5751 */
 5752Yii.CModel.prototype.getValidators = function (attribute) {
 5753		var validators, scenario, i, limit, validator;
 5754		if (attribute === undefined) {
 5755			attribute = null;
 5756		}
 5757		if(this._validators===null) {
 5758			this._validators=this.createValidators();
 5759		}
 5760		validators=[];
 5761		scenario=this.getScenario();
 5762		limit = this._validators.length;
 5763		for (i = 0; i < limit; i++) {
 5764			validator = this._validators[i];
 5765			if(validator.applyTo(scenario))	{
 5766				if(attribute===null || php.in_array(attribute,validator.attributes,true)) {
 5767					validators.push(validator);
 5768				}
 5769			}
 5770		}
 5771		
 5772		return validators;
 5773	};
 5774/**
 5775 * Creates validator objects based on the specification in {@link rules}.
 5776 * This method is mainly used internally.
 5777 * @returns {Yii.CList} validators built based on {@link rules()}.
 5778 */
 5779Yii.CModel.prototype.createValidators = function () {
 5780		var validators, i, ruleList, rule, validator, validatorName = null, attributes = null;
 5781		validators=[];
 5782		ruleList = this.rules();
 5783		for (i in ruleList)	{
 5784			if (ruleList.hasOwnProperty(i)) {
 5785				rule = ruleList[i];
 5786				attributes = rule.attributes;
 5787				delete rule.attributes;
 5788				validatorName = rule.validator;
 5789				delete rule.validator;
 5790				
 5791				if(attributes !== undefined && validatorName !== undefined) {  // attributes, validator name
 5792					
 5793					validator = new Yii.CValidator();
 5794					validators.push(validator.createValidator(validatorName,this,attributes,rule));
 5795				}
 5796				else {
 5797					throw new Yii.CException(Yii.t('yii','{class} has an invalid validation rule. The rule must specify attributes to be validated and the validator name.',
 5798						{'{class}':php.get_class(this)}));
 5799				}	
 5800			}
 5801		}
 5802		return validators;
 5803	};
 5804/**
 5805 * Returns a value indicating whether the attribute is required.
 5806 * This is determined by checking if the attribute is associated with a
 5807 * {@link CRequiredValidator} validation rule in the current {@link scenario}.
 5808 * @param {String} attribute attribute name
 5809 * @returns {Boolean} whether the attribute is required
 5810 * @since 1.0.2
 5811 */
 5812Yii.CModel.prototype.isAttributeRequired = function (attribute) {
 5813		var i, validatorList, validator;
 5814		validatorList = this.getValidators(attribute);
 5815		for (i in validatorList) {
 5816			if (validatorList.hasOwnProperty(i)) {
 5817				validator = validatorList[i];
 5818				if(validator instanceof Yii.CRequiredValidator) {
 5819					return true;
 5820				}
 5821			}
 5822		}
 5823		return false;
 5824	};
 5825/**
 5826 * Returns a value indicating whether the attribute is safe for massive assignments.
 5827 * @param {String} attribute attribute name
 5828 * @returns {Boolean} whether the attribute is safe for massive assignments
 5829 * @since 1.1
 5830 */
 5831Yii.CModel.prototype.isAttributeSafe = function (attribute) {
 5832		var attributes;
 5833		attributes=this.getSafeAttributeNames();
 5834		
 5835		return php.in_array(attribute,attributes);
 5836	};
 5837/**
 5838 * Returns the text label for the specified attribute.
 5839 * @param {String} attribute the attribute name
 5840 * @returns {String} the attribute label
 5841 * @see generateAttributeLabel
 5842 * @see attributeLabels
 5843 */
 5844Yii.CModel.prototype.getAttributeLabel = function (attribute) {
 5845		var labels;
 5846		labels=this.attributeLabels();
 5847		if(labels[attribute] !== undefined) {
 5848			return labels[attribute];
 5849		}
 5850		else {
 5851			return this.generateAttributeLabel(attribute);
 5852		}
 5853	};
 5854/**
 5855 * Returns a value indicating whether there is any validation error.
 5856 * @param {String} attribute attribute name. Use null to check all attributes.
 5857 * @returns {Boolean} whether there is any error.
 5858 */
 5859Yii.CModel.prototype.hasErrors = function (attribute) {
 5860		var i;
 5861		if (attribute === undefined) {
 5862			attribute = null;
 5863		}
 5864		if(attribute===null) {
 5865			for (i in this._errors) {
 5866				if (this._errors.hasOwnProperty(i)) {
 5867					return true;
 5868				}
 5869			}
 5870			return false;
 5871		}
 5872		else {
 5873			return this._errors[attribute] !== undefined;
 5874		}
 5875	};
 5876/**
 5877 * Returns the errors for all attribute or a single attribute.
 5878 * @param {String} attribute attribute name. Use null to retrieve errors for all attributes.
 5879 * @returns {Array} errors for all attributes or the specified attribute. Empty array is returned if no error.
 5880 */
 5881Yii.CModel.prototype.getErrors = function (attribute) {
 5882		if (attribute === undefined) {
 5883			attribute = null;
 5884		}
 5885		if(attribute===null) {
 5886			return this._errors;
 5887		}
 5888		else {
 5889			return this._errors[attribute] !== undefined ? this._errors[attribute] : [];
 5890		}
 5891	};
 5892/**
 5893 * Returns the first error of the specified attribute.
 5894 * @param {String} attribute attribute name.
 5895 * @returns {String} the error message. Null is returned if no error.
 5896 * @since 1.0.2
 5897 */
 5898Yii.CModel.prototype.getError = function (attribute) {
 5899		return this._errors[attribute] !== undefined ? php.reset(this._errors[attribute]) : null;
 5900	};
 5901/**
 5902 * Adds a new error to the specified attribute.
 5903 * @param {String} attribute attribute name
 5904 * @param {String} error new error message
 5905 */
 5906Yii.CModel.prototype.addError = function (attribute, error) {
 5907		if (this._errors[attribute] === undefined) {
 5908			this._errors[attribute] = [];
 5909		}
 5910		this._errors[attribute].push(error);
 5911	};
 5912/**
 5913 * Adds a list of errors.
 5914 * @param {Array} errors a list of errors. The array keys must be attribute names.
 5915 * The array values should be error messages. If an attribute has multiple errors,
 5916 * these errors must be given in terms of an array.
 5917 * You may use the result of {@link getErrors} as the value for this parameter.
 5918 * @since 1.0.5
 5919 */
 5920Yii.CModel.prototype.addErrors = function (errors) {
 5921		var error, i, attribute, e;
 5922		for (attribute in errors) {
 5923			if (errors.hasOwnProperty(attribute)) {
 5924				error = errors[attribute];
 5925				if(Object.prototype.toString.call(error) === '[object Array]') {
 5926					for (i in error) {
 5927						if (error.hasOwnProperty(i)) {
 5928							e = error[i];
 5929							if (this._errors[attribute] === undefined) {
 5930								this._errors[attribute] = [];
 5931							}
 5932							this._errors[attribute].push(e);
 5933						}
 5934					}
 5935				}
 5936				else {
 5937					if (this._errors[attribute] === undefined) {
 5938						this._errors[attribute] = [];
 5939					}
 5940					this._errors[attribute].push(error);
 5941				}
 5942			}
 5943		}
 5944	};
 5945/**
 5946 * Removes errors for all attributes or a single attribute.
 5947 * @param {String} attribute attribute name. Use null to remove errors for all attribute.
 5948 */
 5949Yii.CModel.prototype.clearErrors = function (attribute) {
 5950		if (attribute === undefined) {
 5951			attribute = null;
 5952		}
 5953		if(attribute===null) {
 5954			this._errors={};
 5955		}
 5956		else {
 5957			delete this._errors[attribute];
 5958		}
 5959	};
 5960/**
 5961 * Generates a user friendly attribute label.
 5962 * This is done by replacing underscores or dashes with blanks and
 5963 * changing the first letter of each word to upper case.
 5964 * For example, 'department_name' or 'DepartmentName' becomes 'Department Name'.
 5965 * @param {String} name the column name
 5966 * @returns {String} the attribute label
 5967 */
 5968Yii.CModel.prototype.generateAttributeLabel = function (name) {
 5969		return php.trim(name.replace(/([A-Z])/g, ' $1').replace(/_|-|\./g, ' ')).replace(/^./, function (str) {
 5970				return str.toUpperCase();
 5971			}
 5972		);
 5973	};
 5974/**
 5975 * Returns all attribute values.
 5976 * @param {Array} names list of attributes whose value needs to be returned.
 5977 * Defaults to null, meaning all attributes as listed in {@link attributeNames} will be returned.
 5978 * If it is an array, only the attributes in the array will be returned.
 5979 * @returns {Array} attribute values (name=>value).
 5980 */
 5981Yii.CModel.prototype.getAttributes = function (names) {
 5982		var values, i, nameList, name, values2, n;
 5983		if (names === undefined) {
 5984			names = null;
 5985		}
 5986		values={};
 5987		nameList = this.attributeNames();
 5988		for (i in nameList) {
 5989			if (nameList.hasOwnProperty(i)) {
 5990				name = nameList[i];
 5991				values[name]=this.name;
 5992			}
 5993		}
 5994		if(Object.prototype.toString.call(names) === '[object Array]') {
 5995			values2=[];
 5996			for (n in names) {
 5997				if (names.hasOwnProperty(n)) {
 5998					name = names[n];
 5999					values2[name] = (values[name] !== undefined ? values[name] : null);
 6000				}
 6001			}
 6002			return values2;
 6003		}
 6004		else {
 6005			return values;
 6006		}
 6007	};
 6008/**
 6009 * Sets the attribute values in a massive way.
 6010 * @param {Array} values attribute values (name=>value) to be set.
 6011 * @param {Boolean} safeOnly whether the assignments should only be done to the safe attributes.
 6012 * A safe attribute is one that is associated with a validation rule in the current {@link scenario}.
 6013 * @see getSafeAttributeNames
 6014 * @see attributeNames
 6015 */
 6016Yii.CModel.prototype.setAttributes = function (values, safeOnly) {
 6017		var attributes, name, value;
 6018		if (safeOnly === undefined) {
 6019			safeOnly = true;
 6020		}
 6021		if(!values instanceof Object) {
 6022			return;
 6023		}
 6024		attributes=php.array_flip(safeOnly ? this.getSafeAttributeNames() : this.attributeNames());
 6025		for (name in values) {
 6026			if (values.hasOwnProperty(name)) {
 6027				value = values[name];
 6028				if(attributes[name] !== undefined) {
 6029					this.name=value;
 6030				}
 6031				else if(safeOnly) {
 6032					this.onUnsafeAttribute(name,value);
 6033				}
 6034			}
 6035		}
 6036	};
 6037/**
 6038 * Unsets the attributes.
 6039 * @param {Array} names list of attributes to be set null. If this parameter is not given,
 6040 * all attributes as specified by {@link attributeNames} will have their values unset.
 6041 * @since 1.1.3
 6042 */
 6043Yii.CModel.prototype.unsetAttributes = function (names) {
 6044		var i, name;
 6045		if (names === undefined) {
 6046			names = null;
 6047		}
 6048		if(names===null) {
 6049			names=this.attributeNames();
 6050		}
 6051		for (i in names) {
 6052			if (names.hasOwnProperty(i)) {
 6053				name = names[i];
 6054				this.name=null;
 6055			}
 6056		}
 6057	};
 6058/**
 6059 * This method is invoked when an unsafe attribute is being massively assigned.
 6060 * The default implementation will log a warning message if YII_DEBUG is on.
 6061 * It does nothing otherwise.
 6062 * @param {String} name the unsafe attribute name
 6063 * @param {Mixed} value the attribute value
 6064 * @since 1.1.1
 6065 */
 6066Yii.CModel.prototype.onUnsafeAttribute = function (name, value) {
 6067		if(YII_DEBUG) {
 6068			Yii.log(Yii.t('yii','Failed to set unsafe attribute "{attribute}".',{'{attribute}':name}),Yii.CLogger.LEVEL_WARNING);
 6069		}
 6070	};
 6071/**
 6072 * Returns the scenario that this model is used in.
 6073 * 
 6074 * Scenario affects how validation is performed and which attributes can
 6075 * be massively assigned.
 6076 * 
 6077 * A validation rule will be performed when calling {@link validate()}
 6078 * if its 'on' option is not set or contains the current scenario value.
 6079 * 
 6080 * And an attribute can be massively assigned if it is associated with
 6081 * a validation rule for the current scenario. Note that an exception is
 6082 * the {@link CUnsafeValidator unsafe} validator which marks the associated
 6083 * attributes as unsafe and not allowed to be massively assigned.
 6084 * 
 6085 * @returns {String} the scenario that this model is in.
 6086 * @since 1.0.4
 6087 */
 6088Yii.CModel.prototype.getScenario = function () {
 6089		return this._scenario;
 6090	};
 6091/**
 6092 * Sets the scenario for the model.
 6093 * @param {String} value the scenario that this model is in.
 6094 * @see getScenario
 6095 * @since 1.0.4
 6096 */
 6097Yii.CModel.prototype.setScenario = function (value) {
 6098		this._scenario=value;
 6099	};
 6100/**
 6101 * Returns the attribute names that are safe to be massively assigned.
 6102 * A safe attribute is one that is associated with a validation rule in the current {@link scenario}.
 6103 * @returns {Array} safe attribute names
 6104 * @since 1.0.2
 6105 */
 6106Yii.CModel.prototype.getSafeAttributeNames = function () {
 6107		var attributes, unsafe, i, validatorList, validator, n, name, j, k;
 6108		attributes=[];
 6109		unsafe=[];
 6110		validatorList = this.getValidators();
 6111		for (i in validatorList) {
 6112			if (validatorList.hasOwnProperty(i)) {
 6113				validator = validatorList[i];
 6114				if(!validator.safe)	{
 6115					for (n in validator.attributes) {
 6116						if (validator.attributes.hasOwnProperty(n)) {
 6117							name = validator.attributes[n];
 6118							unsafe.push(name);
 6119						}
 6120					}
 6121				}
 6122				else
 6123				{
 6124					for (j in validator.attributes) {
 6125						if (validator.attributes.hasOwnProperty(j)) {
 6126							name = validator.attributes[j];
 6127							attributes[name]=true;
 6128						}
 6129					}
 6130				}
 6131			}
 6132		}
 6133		for (k in unsafe) {
 6134			if (unsafe.hasOwnProperty(k)) {
 6135				name = unsafe[k];
 6136				delete attributes[name];
 6137			}
 6138		}
 6139		return php.array_keys(attributes);
 6140	};
 6141/*global Yii, php, $, jQuery, alert, clearInterval, clearTimeout, document, event, frames, history, Image, location, name, navigator, Option, parent, screen, setInterval, setTimeout, window, XMLHttpRequest */
 6142/**
 6143 * CModelBehavior is a base class for behaviors that are attached to a model component.
 6144 * The model should extend from {@link CModel} or its child classes.
 6145 * @originalAuthor Qiang Xue <qiang.xue@gmail.com>
 6146 * @version $Id: CModelBehavior.php 2799 2011-01-01 19:31:13Z qiang.xue $
 6147 * @package system.base
 6148 * @since 1.0.2
 6149 * @author Charles Pick
 6150 * @class
 6151 * @extends Yii.CBehavior
 6152 */
 6153Yii.CModelBehavior = function CModelBehavior() {
 6154};
 6155Yii.CModelBehavior.prototype = new Yii.CBehavior();
 6156Yii.CModelBehavior.prototype.constructor =  Yii.CModelBehavior;
 6157/**
 6158 * Declares events and the corresponding event handler methods.
 6159 * The default implementation returns 'onBeforeValidate' and 'onAfterValidate' events and handlers.
 6160 * If you override this method, make sure you merge the parent result to the return value.
 6161 * @returns {Object} events (keys) and the corresponding event handler methods (values).
 6162 * @see CBehavior::events
 6163 */
 6164Yii.CModelBehavior.prototype.events = function () {
 6165		return {
 6166			'onAfterConstruct':'afterConstruct',
 6167			'onBeforeValidate':'beforeValidate',
 6168			'onAfterValidate':'afterValidate'
 6169		};
 6170	};
 6171/**
 6172 * Responds to {@link CModel::onAfterConstruct} event.
 6173 * Overrides this method if you want to handle the corresponding event of the {@link CBehavior::owner owner}.
 6174 * @param {Yii.CEvent} event event parameter
 6175 */
 6176Yii.CModelBehavior.prototype.afterConstruct = function (event) {
 6177	};
 6178/**
 6179 * Responds to {@link CModel::onBeforeValidate} event.
 6180 * Overrides this method if you want to handle the corresponding event of the {@link owner}.
 6181 * You may set {@link CModelEvent::isValid} to be false to quit the validation process.
 6182 * @param {Yii.CModelEvent} event event parameter
 6183 */
 6184Yii.CModelBehavior.prototype.beforeValidate = function (event) {
 6185	};
 6186/**
 6187 * Responds to {@link CModel::onAfterValidate} event.
 6188 * Overrides this method if you want to handle the corresponding event of the {@link owner}.
 6189 * @param {Yii.CEvent} event event parameter
 6190 */
 6191Yii.CModelBehavior.prototype.afterValidate = function (event) {
 6192};/*global Yii, php, $, jQuery, alert, clearInterval, clearTimeout, document, event, frames, history, Image, location, name, navigator, Option, parent, screen, setInterval, setTimeout, window, XMLHttpRequest */
 6193/**
 6194 * CModelEvent class.
 6195 * 
 6196 * CModelEvent represents the event parameters needed by events raised by a model.
 6197 * 
 6198 * @originalAuthor Qiang Xue <qiang.xue@gmail.com>
 6199 * @version $Id: CModelEvent.php 2799 2011-01-01 19:31:13Z qiang.xue $
 6200 * @package system.base
 6201 * @since 1.0
 6202 * @author Charles Pick
 6203 * @class
 6204 * @extends Yii.CEvent
 6205 */
 6206Yii.CModelEvent = function CModelEvent () {
 6207};
 6208Yii.CModelEvent.prototype = new Yii.CEvent();
 6209Yii.CModelEvent.prototype.constructor =  Yii.CModelEvent;
 6210/**
 6211 * @var {Boolean} whether the model is in valid status and should continue its normal method execution cycles. Defaults to true.
 6212 * For example, when this event is raised in a {@link CFormModel} object that is executing {@link CModel::beforeValidate},
 6213 * if this property is set false by the event handler, the {@link CModel::validate} method will quit after handling this event.
 6214 * If true, the normal execution cycles will continue, including performing the real validations and calling
 6215 * {@link CModel::afterValidate}.
 6216 */
 6217Yii.CModelEvent.prototype.isValid = true;
 6218/**
 6219 * @var {Yii.CDbCrireria} the query criteria that is passed as a parameter to a find method of {@link CActiveRecord}.
 6220 * Note that this property is only used by {@link CActiveRecord::onBeforeFind} event.
 6221 * This property could be null.
 6222 * @since 1.1.5
 6223 */
 6224Yii.CModelEvent.prototype.criteria = null;/*global Yii, php, sjcl, $, jQuery, alert, clearInterval, clearTimeout, document, event, frames, history, Image, location, name, navigator, Option, parent, screen, setInterval, setTimeout, window, XMLHttpRequest */
 6225/**
 6226 * CSecurityManager provides private keys, hashing and encryption functions.
 6227 * 
 6228 * CSecurityManager is used by Yii components and applications for security-related purpose.
 6229 * For example, it is used in cookie validation feature to prevent cookie data
 6230 * from being tampered.
 6231 * 
 6232 * CSecurityManager is mainly used to protect data from being tampered and viewed.
 6233 * It can generate HMAC and encrypt the data. The private key used to generate HMAC
 6234 * is set by {@link setValidationKey ValidationKey}. The key used to encrypt data is
 6235 * specified by {@link setEncryptionKey EncryptionKey}. If the above keys are not
 6236 * explicitly set, random keys will be generated and used.
 6237 * 
 6238 * To protected data with HMAC, call {@link hashData()}; and to check if the data
 6239 * is tampered, call {@link validateData()}, which will return the real data if
 6240 * it is not tampered. The algorithm used to generated HMAC is specified by
 6241 * {@link validation}.
 6242 * 
 6243 * To encrypt and decrypt data, call {@link encrypt()} and {@link decrypt()}
 6244 * respectively, which uses 3DES encryption algorithm.  Note, the PHP Mcrypt
 6245 * extension must be installed and loaded.
 6246 * 
 6247 * CSecurityManager is a core application component that can be accessed via
 6248 * {@link CApplication::getSecurityManager()}.
 6249 * 
 6250 * @originalAuthor Qiang Xue <qiang.xue@gmail.com>
 6251 * @version $Id: CSecurityManager.php 3001 2011-02-24 16:42:44Z alexander.makarow $
 6252 * @package system.base
 6253 * @since 1.0
 6254 * @author Charles Pick
 6255 * @class
 6256 * @extends Yii.CApplicationComponent
 6257 */
 6258Yii.CSecurityManager = function CSecurityManager() {
 6259};
 6260Yii.CSecurityManager.prototype = new Yii.CApplicationComponent();
 6261Yii.CSecurityManager.prototype.constructor =  Yii.CSecurityManager;
 6262/**
 6263 * @const
 6264 */
 6265Yii.CSecurityManager.STATE_VALIDATION_KEY = 'Yii.CSecurityManager.validationkey';
 6266/**
 6267 * @const
 6268 */
 6269Yii.CSecurityManager.STATE_ENCRYPTION_KEY = 'Yii.CSecurityManager.encryptionkey';
 6270/**
 6271 * @var {String} the name of the hashing algorithm to be used by {@link computeHMAC}.
 6272 * 
 6273 * Defaults to 'sha1', meaning using SHA1 hash algorithm.
 6274 * @since 1.1.3
 6275 */
 6276Yii.CSecurityManager.prototype.hashAlgorithm = 'sha1';
 6277
 6278Yii.CSecurityManager.prototype._validationKey = null;
 6279Yii.CSecurityManager.prototype._encryptionKey = null;
 6280/**
 6281 * @returns {String} a randomly generated private key
 6282 */
 6283Yii.CSecurityManager.prototype.generateRandomKey = function () {
 6284		return php.sprintf('%08x%08x%08x%08x',php.mt_rand(),php.mt_rand(),php.mt_rand(),php.mt_rand());
 6285	};
 6286/**
 6287 * @returns {String} the private key used to generate HMAC.
 6288 * If the key is not explicitly set, a random one is generated and returned.
 6289 */
 6290Yii.CSecurityManager.prototype.getValidationKey = function () {
 6291		var key;
 6292		if(this._validationKey!==null) {
 6293			return this._validationKey;
 6294		}
 6295		else {
 6296			if((key=Yii.app().getGlobalState(this.STATE_VALIDATION_KEY))!==null) {
 6297				this.setValidationKey(key);
 6298			}
 6299			else {
 6300				key=this.generateRandomKey();
 6301				this.setValidationKey(key);
 6302				Yii.app().setGlobalState(this.STATE_VALIDATION_KEY,key);
 6303			}
 6304			return this._validationKey;
 6305		}
 6306	};
 6307/**
 6308 * @param {String} value the key used to generate HMAC
 6309 * @throws {Yii.CException} if the key is empty
 6310 */
 6311Yii.CSecurityManager.prototype.setValidationKey = function (value) {
 6312		if(!php.empty(value)) {
 6313			this._validationKey=value;
 6314		}
 6315		else {
 6316			throw new Yii.CException(Yii.t('yii','CSecurityManager.validationKey cannot be empty.'));
 6317		}
 6318	};
 6319/**
 6320 * @returns {String} the private key used to encrypt/decrypt data.
 6321 * If the key is not explicitly set, a random one is generated and returned.
 6322 */
 6323Yii.CSecurityManager.prototype.getEncryptionKey = function () {
 6324		var key;
 6325		if(this._encryptionKey!==null) {
 6326			return this._encryptionKey;
 6327		}
 6328		else {
 6329			if((key=Yii.app().getGlobalState(this.STATE_ENCRYPTION_KEY))!==null) {
 6330				this.setEncryptionKey(key);
 6331			}
 6332			else {
 6333				key=this.generateRandomKey();
 6334				this.setEncryptionKey(key);
 6335				Yii.app().setGlobalState(this.STATE_ENCRYPTION_KEY,key);
 6336			}
 6337			return this._encryptionKey;
 6338		}
 6339	};
 6340/**
 6341 * @param {String} value the key used to encrypt/decrypt data.
 6342 * @throws {Yii.CException} if the key is empty
 6343 */
 6344Yii.CSecurityManager.prototype.setEncryptionKey = function (value) {
 6345		if(!php.empty(value)) {
 6346			this._encryptionKey=value;
 6347		}
 6348		else {
 6349			throw new Yii.CException(Yii.t('yii','CSecurityManager.encryptionKey cannot be empty.'));
 6350		}
 6351	};
 6352/**
 6353 * This method has been deprecated since version 1.1.3.
 6354 * Please use {@link hashAlgorithm} instead.
 6355 */
 6356Yii.CSecurityManager.prototype.getValidation = function () {
 6357		return this.hashAlgorithm;
 6358	};
 6359/**
 6360 * This method has been deprecated since version 1.1.3.
 6361 * Please use {@link hashAlgorithm} instead.
 6362 * @param {String} value -
 6363 */
 6364Yii.CSecurityManager.prototype.setValidation = function (value) {
 6365		this.hashAlgorithm=value;
 6366	};
 6367/**
 6368 * Encrypts data.
 6369 * @param {String} data data to be encrypted.
 6370 * @param {String} key the decryption key. This defaults to null, meaning using {@link getEncryptionKey EncryptionKey}.
 6371 * @returns {String} the encrypted data
 6372 * @throws {Yii.CException} if PHP Mcrypt extension is not loaded
 6373 */
 6374Yii.CSecurityManager.prototype.encrypt = function (data, key) {
 6375		var module, iv, encrypted;
 6376		if (key === undefined) {
 6377			key = null;
 6378		}
 6379		module=this.openCryptModule();
 6380		key=key===null ? php.md5(this.getEncryptionKey()) : key;
 6381		encrypted = module.encrypt(key, data);
 6382		return encrypted;
 6383	};
 6384/**
 6385 * Decrypts data
 6386 * @param {String} data data to be decrypted.
 6387 * @param {String} key the decryption key. This defaults to null, meaning using {@link getEncryptionKey EncryptionKey}.
 6388 * @returns {String} the decrypted data
 6389 * @throws {Yii.CException} if PHP Mcrypt extension is not loaded
 6390 */
 6391Yii.CSecurityManager.prototype.decrypt = function (data, key) {
 6392		var module, ivSize, iv, decrypted;
 6393		if (key === undefined) {
 6394			key = null;
 6395		}
 6396		module=this.openCryptModule();
 6397		key=key===null ? php.md5(this.getEncryptionKey()) : key;
 6398		decrypted = module.decrypt(key, data);
 6399		return decrypted;
 6400	};
 6401/**
 6402 * Opens the mcrypt module with the configuration specified in {@link cryptAlgorithm}.
 6403 * @returns {Resource} the mycrypt module handle.
 6404 * @since 1.1.3
 6405 */
 6406Yii.CSecurityManager.prototype.openCryptModule = function () {
 6407		var module;
 6408		if(sjcl !== undefined) {
 6409			return sjcl;
 6410		}
 6411		else {
 6412			throw new Yii.CException(Yii.t('yii','CSecurityManager requires the Stanford Javascript Crypto Library to be loaded in order to use data encryption feature.'));
 6413		}
 6414	};
 6415/**
 6416 * Prefixes data with an HMAC.
 6417 * @param {String} data data to be hashed.
 6418 * @param {String} key the private key to be used for generating HMAC. Defaults to null, meaning using {@link validationKey}.
 6419 * @returns {String} data prefixed with HMAC
 6420 */
 6421Yii.CSecurityManager.prototype.hashData = function (data, key) {
 6422		if (key === undefined) {
 6423			key = null;
 6424		}
 6425		return this.computeHMAC(data,key)+data;
 6426	};
 6427/**
 6428 * Validates if data is tampered.
 6429 * @param {String} data data to be validated. The data must be previously
 6430 * generated using {@link hashData()}.
 6431 * @param {String} key the private key to be used for generating HMAC. Defaults to null, meaning using {@link validationKey}.
 6432 * @returns {String} the real data with HMAC stripped off. False if the data
 6433 * is tampered.
 6434 */
 6435Yii.CSecurityManager.prototype.validateData = function (data, key) {
 6436		var len, hmac, data2;
 6437		if (key === undefined) {
 6438			key = null;
 6439		}
 6440		len=php.strlen(this.computeHMAC('test'));
 6441		
 6442		if(php.strlen(data)>=len) {
 6443			hmac=data.slice(0, len);
 6444			data2=data.slice(len);
 6445			return hmac===this.computeHMAC(data2,key)?data2:false;
 6446		}
 6447		else {
 6448			return false;
 6449		}
 6450	};
 6451/**
 6452 * Computes the HMAC for the data with {@link getValidationKey ValidationKey}.
 6453 * @param {String} data data to be generated HMAC
 6454 * @param {String} key the private key to be used for generating HMAC. Defaults to null, meaning using {@link validationKey}.
 6455 * @returns {String} the HMAC for the data
 6456 */
 6457Yii.CSecurityManager.prototype.computeHMAC = function (data, key) {
 6458		var pack, func, hmac;
 6459		if (key === undefined) {
 6460			key = null;
 6461		}
 6462		if(key===null) {
 6463			key=this.getValidationKey();
 6464		}
 6465		hmac = new sjcl.misc.hmac(key);
 6466		return php.md5(hmac.encrypt(data).join(""));		
 6467		
 6468};
 6469
 6470/*global Yii, php, $, jQuery, alert, clearInterval, clearTimeout, document, event, frames, history, Image, location, name, navigator, Option, parent, screen, setInterval, setTimeout, window, XMLHttpRequest */
 6471/**
 6472 * CStatePersister implements a file-based persistent data storage.
 6473 * 
 6474 * It can be used to keep data available through multiple requests and sessions.
 6475 * 
 6476 * By default, CStatePersister stores data in a file named 'state.bin' that is located
 6477 * under the application {@link CApplication::getRuntimePath runtime path}.
 6478 * You may change the location by setting the {@link stateFile} property.
 6479 * 
 6480 * To retrieve the data from CStatePersister, call {@link load()}. To save the data,
 6481 * call {@link save()}.
 6482 * 
 6483 * Comparison among state persister, session and cache is as follows:
 6484 * <ul>
 6485 * <li>session: data persisting within a single user session.</li>
 6486 * <li>state persister: data persisting through all requests/sessions (e.g. hit counter).</li>
 6487 * <li>cache: volatile and fast storage. It may be used as storage medium for session or state persister.</li>
 6488 * </ul>
 6489 * 
 6490 * Since server resource is often limited, be cautious if you plan to use CStatePersister
 6491 * to store large amount of data. You should also consider using database-based persister
 6492 * to improve the throughput.
 6493 * 
 6494 * CStatePersister is a core application component used to store global application state.
 6495 * It may be accessed via {@link CApplication::getStatePersister()}.
 6496 * page state persistent method based on cache.
 6497 * 
 6498 * @originalAuthor Qiang Xue <qiang.xue@gmail.com>
 6499 * @version $Id: CStatePersister.php 3165 2011-04-06 08:27:40Z mdomba $
 6500 * @package system.base
 6501 * @since 1.0
 6502 * @author Charles Pick
 6503 * @class
 6504 * @extends Yii.CApplicationComponent
 6505 */
 6506Yii.CStatePersister = function CStatePersister() {
 6507};
 6508Yii.CStatePersister.prototype = new Yii.CApplicationComponent();
 6509Yii.CStatePersister.prototype.constructor =  Yii.CStatePersister;
 6510
 6511/**
 6512 * Initializes the component.
 6513 * This method overrides the parent implementation by making sure the
 6514 * browser supports localStorage
 6515 */
 6516Yii.CStatePersister.prototype.init = function () {
 6517		Yii.CApplicationComponent.prototype.init.call(this);
 6518		
 6519		try {
 6520			return "localStorage" in window && window.localStorage !== null;
 6521		}
 6522		catch (e) {
 6523			throw new Yii.CException(Yii.t('yii','Unable to access local storage, please ensure that you\'re using a modern browser!'));
 6524		}
 6525	};
 6526/**
 6527 * Loads state data from persistent storage.
 6528 * @returns {Mixed} state data. Null if no state data available.
 6529 */
 6530Yii.CStatePersister.prototype.load = function () {
 6531		var state = {}, i, value;
 6532		if(window.localStorage.length !== 0) {
 6533			
 6534			for (i in window.localStorage) {
 6535				if (window.localStorage.hasOwnProperty(i)) {
 6536					try {
 6537						state[i] = Yii.CJSON.decode(window.localStorage[i]);
 6538					}
 6539					catch (e) {
 6540						state[i] = window.localStorage[i];
 6541					}
 6542				}
 6543			}
 6544			return state;
 6545		}
 6546		else {
 6547			return null;
 6548		}
 6549	};
 6550/**
 6551 * Saves application state in persistent storage.
 6552 * @param {Mixed} state state data (must be serializable).
 6553 */
 6554Yii.CStatePersister.prototype.save = function (state) {
 6555	var i;
 6556	window.localStorage.clear();
 6557	for(i in state) {
 6558		if (state.hasOwnProperty(i)) {
 6559			window.localStorage[i] = Yii.CJSON.encode(state[i]);
 6560		}
 6561	}
 6562};/*global Yii, php, $, jQuery, alert, clearInterval, clearTimeout, document, event, frames, history, Image, location, name, navigator, Option, parent, screen, setInterval, setTimeout, window, XMLHttpRequest */
 6563/**
 6564 * CCache is the base class for cache classes with different cache storage implementation.
 6565 * 
 6566 * A data item can be stored in cache by calling {@link set} and be retrieved back
 6567 * later by {@link get}. In both operations, a key identifying the data item is required.
 6568 * An expiration time and/or a dependency can also be specified when calling {@link set}.
 6569 * If the data item expires or the dependency changes, calling {@link get} will not
 6570 * return back the data item.
 6571 * 
 6572 * Note, by definition, cache does not ensure the existence of a value
 6573 * even if it does not expire. Cache is not meant to be a persistent storage.
 6574 * 
 6575 * CCache implements the interface {@link ICache} with the following methods:
 6576 * <ul>
 6577 * <li>{@link get} : retrieve the value with a key (if any) from cache</li>
 6578 * <li>{@link set} : store the value with a key into cache</li>
 6579 * <li>{@link add} : store the value only if cache does not have this key</li>
 6580 * <li>{@link delete} : delete the value with the specified key from cache</li>
 6581 * <li>{@link flush} : delete all values from cache</li>
 6582 * </ul>
 6583 * 
 6584 * Child classes must implement the following methods:
 6585 * <ul>
 6586 * <li>{@link getValue}</li>
 6587 * <li>{@link setValue}</li>
 6588 * <li>{@link addValue}</li>
 6589 * <li>{@link deleteValue}</li>
 6590 * <li>{@link flush} (optional)</li>
 6591 * </ul>
 6592 * 
 6593 * CCache also implements ArrayAccess so that it can be used like an array.
 6594 * 
 6595 * @originalAuthor Qiang Xue <qiang.xue@gmail.com>
 6596 * @version $Id: CCache.php 3001 2011-02-24 16:42:44Z alexander.makarow $
 6597 * @package system.caching
 6598 * @since 1.0
 6599 * @author Charles Pick
 6600 * @class
 6601 * @extends Yii.CApplicationComponent
 6602 */
 6603Yii.CCache = function CCache () {
 6604};
 6605Yii.CCache.prototype = new Yii.CApplicationComponent();
 6606Yii.CCache.prototype.constructor =  Yii.CCache;
 6607/**
 6608 * @var {String} a string prefixed to every cache key so that it is unique. Defaults to {@link CApplication::getId() application ID}.
 6609 */
 6610Yii.CCache.prototype.keyPrefix = null;
 6611/**
 6612 * Initializes the application component.
 6613 * This method overrides the parent implementation by setting default cache key prefix.
 6614 */
 6615Yii.CCache.prototype.init = function () {
 6616		Yii.CApplicationComponent.prototype.init.call(this);
 6617		if(this.keyPrefix===null) {
 6618			this.keyPrefix=Yii.app().getId();
 6619		}
 6620	};
 6621/**
 6622 * @param {String} key a key identifying a value to be cached
 6623 * @returns {Sring} a key generated from the provided key which ensures the uniqueness across applications
 6624 */
 6625Yii.CCache.prototype.generateUniqueKey = function (key) {
 6626		return php.md5(this.keyPrefix+key);
 6627	};
 6628/**
 6629 * Retrieves a value from cache with a specified key.
 6630 * @param {String} id a key identifying the cached value
 6631 * @returns {Mixed} the value stored in cache, false if the value is not in the cache, expired or the dependency has changed.
 6632 */
 6633Yii.CCache.prototype.get = function (id) {
 6634		var value, data;
 6635		if((value=this.getValue(this.generateUniqueKey(id)))!==false) {
 6636			data = value;
 6637			
 6638			if (!data) {
 6639				return false;
 6640			}
 6641			if(Object.prototype.toString.call(data) !== '[object Array]') {
 6642				if (data.length > 0) {
 6643					try {
 6644						data = Yii.CJSON.decode(data);
 6645					}
 6646					catch (e) {
 6647						return false;
 6648					}
 6649				}
 6650				else {
 6651					return false;
 6652				}
 6653			}
 6654			if (false && data[1] !== undefined && data[1] !== {}) {
 6655				data[1] = Yii.createComponent(data[1]);
 6656			}
 6657			if(data[1] === null || !(data[1] instanceof Yii.CCacheDependency) || !data[1].getHasChanged()) {
 6658				Yii.trace('Serving "'+id+'" from cache','system.caching.'+this.getClassName());
 6659				return data[0];
 6660			}
 6661		}
 6662		return false;
 6663	};
 6664/**
 6665 * Retrieves multiple values from cache with the specified keys.
 6666 * Some caches (such as memcache, apc) allow retrieving multiple cached values at one time,
 6667 * which may improve the performance since it reduces the communication cost.
 6668 * In case a cache doesn't support this feature natively, it will be simulated by this method.
 6669 * @param {Array} ids list of keys identifying the cached values
 6670 * @returns {Array} list of cached values corresponding to the specified keys. The array
 6671 * is returned in terms of (key,value) pairs.
 6672 * If a value is not cached or expired, the corresponding array value will be false.
 6673 * @since 1.0.8
 6674 */
 6675Yii.CCache.prototype.mget = function (ids) {
 6676		var uniqueIDs, results, i, id, values, uniqueID, data;
 6677		uniqueIDs={};
 6678		results={};
 6679		for (i in ids) {
 6680			if (ids.hasOwnProperty(i)) {
 6681				id = ids[i];
 6682				uniqueIDs[id]=this.generateUniqueKey(id);
 6683				results[id]=false;
 6684			}
 6685		}
 6686		values=this.getValues(uniqueIDs);
 6687		for (id in uniqueIDs) {
 6688			if (uniqueIDs.hasOwnProperty(id)) {
 6689				uniqueID = uniqueIDs[id];
 6690				if(values[uniqueID] === undefined) {
 6691					continue;
 6692				}
 6693				data=Yii.CJSON.decode(values[uniqueID]);
 6694				data = value;
 6695				if(Object.prototype.toString.call(data) !== '[object Array]') {
 6696					if (data.length > 0) {
 6697						try {
 6698							data = Yii.CJSON.decode(data);
 6699						}
 6700						catch (e) {
 6701							return false;
 6702						}
 6703					}
 6704					else {
 6705						return false;
 6706					}
 6707				}
 6708				if (data[1] !== undefined && data[1] !== {}) {
 6709					data[1] = Yii.createComponent(data[1]);
 6710				}
 6711				if(!(data[1] instanceof Yii.CCacheDependency) || !data[1].getHasChanged()) {
 6712					Yii.trace('Serving "'+id+'" from cache','system.caching.'+this.getClassName());
 6713					results[id] = data[0];
 6714				}
 6715			}
 6716		}
 6717		return results;
 6718	};
 6719/**
 6720 * Stores a value identified by a key into cache.
 6721 * If the cache already contains such a key, the existing value and
 6722 * expiration time will be replaced with the new ones.
 6723 * 
 6724 * @param {String} id the key identifying the value to be cached
 6725 * @param {Mixed} value the value to be cached
 6726 * @param {Integer} expire the number of seconds in which the cached value will expire. 0 means never expire.
 6727 * @param {ICacheDependency} dependency dependency of the cached item. If the dependency changes, the item is labeled invalid.
 6728 * @returns {Boolean} true if the value is successfully stored into cache, false otherwise
 6729 */
 6730Yii.CCache.prototype.set = function (id, value, expire, dependency) {
 6731		var data;
 6732		if (expire === undefined) {
 6733			expire = 0;
 6734		}
 6735		if (dependency === undefined) {
 6736			dependency = null;
 6737		}
 6738		Yii.trace('Saving "'+id+'" to cache','system.caching.'+this.getClassName());
 6739		if(dependency!==null) {
 6740			dependency.evaluateDependency();
 6741		}
 6742		data=[value,dependency];
 6743		return this.setValue(this.generateUniqueKey(id),Yii.CJSON.encode(data),expire);
 6744	};
 6745/**
 6746 * Stores a value identified by a key into cache if the cache does not contain this key.
 6747 * Nothing will be done if the cache already contains the key.
 6748 * @param {String} id the key identifying the value to be cached
 6749 * @param {Mixed} value the value to be cached
 6750 * @param {Integer} expire the number of seconds in which the cached value will expire. 0 means never expire.
 6751 * @param {ICacheDependency} dependency dependency of the cached item. If the dependency changes, the item is labeled invalid.
 6752 * @returns {Boolean} true if the value is successfully stored into cache, false otherwise
 6753 */
 6754Yii.CCache.prototype.add = function (id, value, expire, dependency) {
 6755		var data;
 6756		if (expire === undefined) {
 6757			expire = 0;
 6758		}
 6759		if (dependency === undefined) {
 6760			dependency = null;
 6761		}
 6762		Yii.trace('Adding "'+id+'" to cache','system.caching.'+this.getClassName());
 6763		if(dependency!==null) {
 6764			dependency.evaluateDependency();
 6765		}
 6766		data=[value,dependency];
 6767		return this.addValue(this.generateUniqueKey(id),Yii.CJSON.encode(data),expire);
 6768	};
 6769/**
 6770 * Deletes a value with the specified key from cache
 6771 * @param {String} id the key of the value to be deleted
 6772 * @returns {Boolean} if no error happens during deletion
 6773 */
 6774Yii.CCache.prototype.remove = function (id) {
 6775		Yii.trace('Deleting "'+id+'" from cache','system.caching.'+this.getClassName());
 6776		return this.deleteValue(this.generateUniqueKey(id));
 6777	};
 6778/**
 6779 * Deletes all values from cache.
 6780 * Be careful of performing this operation if the cache is shared by multiple applications.
 6781 * @returns {Boolean} whether the flush operation was successful.
 6782 */
 6783Yii.CCache.prototype.flush = function () {
 6784		Yii.trace('Flushing cache','system.caching.'+this.getClassName());
 6785		return this.flushValues();
 6786	};
 6787/**
 6788 * Retrieves a value from cache with a specified key.
 6789 * This method should be implemented by child classes to retrieve the data
 6790 * from specific cache storage. The uniqueness and dependency are handled
 6791 * in {@link get()} already. So only the implementation of data retrieval
 6792 * is needed.
 6793 * @param {String} key a unique key identifying the cached value
 6794 * @returns {String} the value stored in cache, false if the value is not in the cache or expired.
 6795 * @throws {Yii.CException} if this method is not overridden by child classes
 6796 */
 6797Yii.CCache.prototype.getValue = function (key) {
 6798		throw new Yii.CException(Yii.t('yii','{className} does not support get() functionality.',
 6799			{'{className}':this.getClassName()}));
 6800	};
 6801/**
 6802 * Retrieves multiple values from cache with the specified keys.
 6803 * The default implementation simply calls {@link getValue} multiple
 6804 * times to retrieve the cached values one by one.
 6805 * If the underlying cache storage supports multiget, this method should
 6806 * be overridden to exploit that feature.
 6807 * @param {Array} keys a list of keys identifying the cached values
 6808 * @returns {Object} a list of cached values indexed by the keys
 6809 * @since 1.0.8
 6810 */
 6811Yii.CCache.prototype.getValues = function (keys) {
 6812		var results, i, key;
 6813		results={};
 6814		for (i in keys) {
 6815			if (keys.hasOwnProperty(i)) {
 6816				key = keys[i];
 6817				results[key]=this.getValue(key);
 6818			}
 6819		}
 6820		return results;
 6821	};
 6822/**
 6823 * Stores a value identified by a key in cache.
 6824 * This method should be implemented by child classes to store the data
 6825 * in specific cache storage. The uniqueness and dependency are handled
 6826 * in {@link set()} already. So only the implementation of data storage
 6827 * is needed.
 6828 * 
 6829 * @param {String} key the key identifying the value to be cached
 6830 * @param {String} value the value to be cached
 6831 * @param {Integer} expire the number of seconds in which the cached value will expire. 0 means never expire.
 6832 * @returns {Boolean} true if the value is successfully stored into cache, false otherwise
 6833 * @throws {Yii.CException} if this method is not overridden by child classes
 6834 */
 6835Yii.CCache.prototype.setValue = function (key, value, expire) {
 6836		throw new Yii.CException(Yii.t('yii','{className} does not support set() functionality.',
 6837			{'{className}':this.getClassName()}));
 6838	};
 6839/**
 6840 * Stores a value identified by a key into cache if the cache does not contain this key.
 6841 * This method should be implemented by child classes to store the data
 6842 * in specific cache storage. The uniqueness and dependency are handled
 6843 * in {@link add()} already. So only the implementation of data storage
 6844 * is needed.
 6845 * 
 6846 * @param {String} key the key identifying the value to be cached
 6847 * @param {String} value the value to be cached
 6848 * @param {Integer} expire the number of seconds in which the cached value will expire. 0 means never expire.
 6849 * @returns {Boolean} true if the value is successfully stored into cache, false otherwise
 6850 * @throws {Yii.CException} if this method is not overridden by child classes
 6851 */
 6852Yii.CCache.prototype.addValue = function (key, value, expire) {
 6853		throw new Yii.CException(Yii.t('yii','{className} does not support add() functionality.',
 6854			{'{className}':this.getClassName()}));
 6855	};
 6856/**
 6857 * Deletes a value with the specified key from cache
 6858 * This method should be implemented by child classes to delete the data from actual cache storage.
 6859 * @param {String} key the key of the value to be deleted
 6860 * @returns {Boolean} if no error happens during deletion
 6861 * @throws {Yii.CException} if this method is not overridden by child classes
 6862 */
 6863Yii.CCache.prototype.deleteValue = function (key) {
 6864		throw new Yii.CException(Yii.t('yii','{className} does not support delete() functionality.',
 6865			{'{className}':this.getClassName()}));
 6866	};
 6867/**
 6868 * Deletes all values from cache.
 6869 * Child classes may implement this method to realize the flush operation.
 6870 * @returns {Boolean} whether the flush operation was successful.
 6871 * @throws {Yii.CException} if this method is not overridden by child classes
 6872 * @since 1.1.5
 6873 */
 6874Yii.CCache.prototype.flushValues = function () {
 6875		throw new Yii.CException(Yii.t('yii','{className} does not support flushValues() functionality.',
 6876			{'{className}':this.getClassName()}));
 6877	};
 6878/**
 6879 * Returns whether there is a cache entry with a specified key.
 6880 * This method is required by the interface ArrayAccess.
 6881 * @param {String} id a key identifying the cached value
 6882 * @returns {Boolean}
 6883 */
 6884Yii.CCache.prototype.offsetExists = function (id) {
 6885		return this.get(id)!==false;
 6886	};
 6887/**
 6888 * Retrieves the value from cache with a specified key.
 6889 * This method is required by the interface ArrayAccess.
 6890 * @param {String} id a key identifying the cached value
 6891 * @returns {Mixed} the value stored in cache, false if the value is not in the cache or expired.
 6892 */
 6893Yii.CCache.prototype.offsetGet = function (id) {
 6894		return this.get(id);
 6895	};
 6896/**
 6897 * Stores the value identified by a key into cache.
 6898 * If the cache already contains such a key, the existing value will be
 6899 * replaced with the new ones. To add expiration and dependencies, use the set() method.
 6900 * This method is required by the interface ArrayAccess.
 6901 * @param {String} id the key identifying the value to be cached
 6902 * @param {Mixed} value the value to be cached
 6903 */
 6904Yii.CCache.prototype.offsetSet = function (id, value) {
 6905		this.set(id, value);
 6906	};
 6907/**
 6908 * Deletes the value with the specified key from cache
 6909 * This method is required by the interface ArrayAccess.
 6910 * @param {String} id the key of the value to be deleted
 6911 * @returns {Boolean} if no error happens during deletion
 6912 */
 6913Yii.CCache.prototype.offsetUnset = function (id) {
 6914		this.remove(id);
 6915	};/*global Yii, php, $, jQuery, alert, clearInterval, clearTimeout, document, event, frames, history, Image, location, name, navigator, Option, parent, screen, setInterval, setTimeout, window, XMLHttpRequest */
 6916/**
 6917 * CLocalCache implements a cache application component based on localStorage
 6918
 6919 * @package system.caching
 6920 * @since 1.0
 6921 * @author Charles Pick
 6922 * @class
 6923 * @extends Yii.CCache
 6924 */
 6925Yii.CLocalCache = function CLocalCache () {
 6926};
 6927Yii.CLocalCache.prototype = new Yii.CCache();
 6928Yii.CLocalCache.prototype.constructor =  Yii.CLocalCache;
 6929
 6930
 6931/**
 6932 * Retrieves a value from cache with a specified key.
 6933 * This is the implementation of the method declared in the parent class.
 6934 * @param {String} key a unique key identifying the cached value
 6935 * @returns {String} the value stored in cache, false if the value is not in the cache or expired.
 6936 */
 6937Yii.CLocalCache.prototype.getValue = function (key) {
 6938		var raw, item, expiry, now;
 6939		raw = localStorage.getItem(key);
 6940		if (raw === null) {
 6941			return false;
 6942		}
 6943		try {
 6944			item = Yii.CJSON.decode(raw);
 6945			now = php.time();
 6946			expiry = item.shift();
 6947			if (expiry !== 0 && expiry < now) {
 6948				localStorage.removeItem(key);
 6949				return false;
 6950			}
 6951			return item.shift();
 6952		}
 6953		catch (e) {
 6954			return raw;
 6955		}
 6956	};
 6957
 6958/**
 6959 * Stores a value identified by a key in cache.
 6960 * This is the implementation of the method declared in the parent class.
 6961 * 
 6962 * @param {String} key the key identifying the value to be cached
 6963 * @param {String} value the value to be cached
 6964 * @param {Integer} expire the number of seconds in which the cached value will expire. 0 means never expire.
 6965 * @returns {Boolean} true if the value is successfully stored into cache, false otherwise
 6966 */
 6967Yii.CLocalCache.prototype.setValue = function (key, value, expire) {
 6968		if(expire>0) {
 6969			expire+=php.time();
 6970		}
 6971		else {
 6972			expire=0;
 6973		}
 6974		
 6975		return localStorage.setItem(key, Yii.CJSON.encode([expire,value]));
 6976		
 6977	};
 6978/**
 6979 * Stores a value identified by a key into cache if the cache does not contain this key.
 6980 * This is the implementation of the method declared in the parent class.
 6981 * 
 6982 * @param {String} key the key identifying the value to be cached
 6983 * @param {String} value the value to be cached
 6984 * @param {Integer} expire the number of seconds in which the cached value will expire. 0 means never expire.
 6985 * @returns {Boolean} true if the value is successfully stored into cache, false otherwise
 6986 */
 6987Yii.CLocalCache.prototype.addValue = function (key, value, expire) {
 6988		if(expire>0) {
 6989			expire+=php.time();
 6990		}
 6991		else {
 6992			expire=0;
 6993		}
 6994		// TODO: expiry!
 6995		return localStorage.setItem(key, value);
 6996	};
 6997/**
 6998 * Deletes a value with the specified key from cache
 6999 * This is the implementation of the method declared in the parent class.
 7000 * @param {String} key the key of the value to be deleted
 7001 * @returns {Boolean} if no error happens during deletion
 7002 */
 7003Yii.CLocalCache.prototype.remove = function (key) {
 7004		return localStorage.removeItem(key);
 7005	};
 7006/**
 7007 * Deletes all values from cache.
 7008 * This is the implementation of the method declared in the parent class.
 7009 * @returns {Boolean} whether the flush operation was successful.
 7010 * @since 1.1.5
 7011 */
 7012Yii.CLocalCache.prototype.flushValues = function () {
 7013		return localStorage.clear();
 7014	};/*global Yii, php, $, jQuery, alert, clearInterval, clearTimeout, document, event, frames, history, Image, location, name, navigator, Option, parent, screen, setInterval, setTimeout, window, XMLHttpRequest */
 7015/**
 7016 * CSessionCache implements a cache application component based on sessionStorage
 7017
 7018 * @package system.caching
 7019 * @since 1.0
 7020 * @author Charles Pick
 7021 * @class
 7022 * @extends Yii.CCache
 7023 */
 7024Yii.CSessionCache = function CSessionCache () {
 7025};
 7026Yii.CSessionCache.prototype = new Yii.CCache();
 7027Yii.CSessionCache.prototype.constructor =  Yii.CSessionCache;
 7028
 7029
 7030/**
 7031 * Retrieves a value from cache with a specified key.
 7032 * This is the implementation of the method declared in the parent class.
 7033 * @param {String} key a unique key identifying the cached value
 7034 * @returns {String} the value stored in cache, false if the value is not in the cache or expired.
 7035 */
 7036Yii.CSessionCache.prototype.getValue = function (key) {
 7037		var raw, item, expiry, now;
 7038		raw = sessionStorage.getItem(key);
 7039		if (raw === null) {
 7040			return false;
 7041		}
 7042		try {
 7043			item = Yii.CJSON.decode(raw);
 7044			now = php.time();
 7045			expiry = item.shift();
 7046			if (expiry !== 0 && expiry < now) {
 7047				sessionStorage.removeItem(key);
 7048				return false;
 7049			}
 7050			return item.shift();
 7051		}
 7052		catch (e) {
 7053			return raw;
 7054		}
 7055	};
 7056
 7057/**
 7058 * Stores a value identified by a key in cache.
 7059 * This is the implementation of the method declared in the parent class.
 7060 * 
 7061 * @param {String} key the key identifying the value to be cached
 7062 * @param {String} value the value to be cached
 7063 * @param {Integer} expire the number of seconds in which the cached value will expire. 0 means never expire.
 7064 * @returns {Boolean} true if the value is successfully stored into cache, false otherwise
 7065 */
 7066Yii.CSessionCache.prototype.setValue = function (key, value, expire) {
 7067		if(expire>0) {
 7068			expire+=php.time();
 7069		}
 7070		else {
 7071			expire=0;
 7072		}
 7073		
 7074		return sessionStorage.setItem(key, Yii.CJSON.encode([expire,value]));
 7075		
 7076	};
 7077/**
 7078 * Stores a value identified by a key into cache if the cache does not contain this key.
 7079 * This is the implementation of the method declared in the parent class.
 7080 * 
 7081 * @param {String} key the key identifying the value to be cached
 7082 * @param {String} value the value to be cached
 7083 * @param {Integer} expire the number of seconds in which the cached value will expire. 0 means never expire.
 7084 * @returns {Boolean} true if the value is successfully stored into cache, false otherwise
 7085 */
 7086Yii.CSessionCache.prototype.addValue = function (key, value, expire) {
 7087		if(expire>0) {
 7088			expire+=php.time();
 7089		}
 7090		else {
 7091			expire=0;
 7092		}
 7093		// TODO: expiry!
 7094		return sessionStorage.setItem(key, value);
 7095	};
 7096/**
 7097 * Deletes a value with the specified key from cache
 7098 * This is the implementation of the method declared in the parent class.
 7099 * @param {String} key the key of the value to be deleted
 7100 * @returns {Boolean} if no error happens during deletion
 7101 */
 7102Yii.CSessionCache.prototype.remove = function (key) {
 7103		return sessionStorage.removeItem(key);
 7104	};
 7105/**
 7106 * Deletes all values from cache.
 7107 * This is the implementation of the method declared in the parent class.
 7108 * @returns {Boolean} whether the flush operation was successful.
 7109 * @since 1.1.5
 7110 */
 7111Yii.CSessionCache.prototype.flushValues = function () {
 7112		return sessionStorage.clear();
 7113	};/*global Yii, php, $, jQuery, alert, clearInterval, clearTimeout, document, event, frames, history, Image, location, name, navigator, Option, parent, screen, setInterval, setTimeout, window, XMLHttpRequest */
 7114/**
 7115 * CAttributeCollection implements a collection for storing attribute names and values.
 7116 * 
 7117 * Besides all functionalities provided by {@link CMap}, CAttributeCollection
 7118 * allows you to get and set attribute values like getting and setting
 7119 * properties. For example, the following usages are all valid for a
 7120 * CAttributeCollection object:
 7121 * <pre>
 7122 * collection.text='text'; // same as:  $collection->add('text','text');
 7123 * document.write(collection.text);   // same as:  echo $collection->itemAt('text');
 7124 * </pre>
 7125 * 
 7126 * The case sensitivity of attribute names can be toggled by setting the
 7127 * {@link caseSensitive} property of the collection.
 7128 * 
 7129 * @originalAuthor Qiang Xue <qiang.xue@gmail.com>
 7130 * @version $Id: CAttributeCollection.php 3001 2011-02-24 16:42:44Z alexander.makarow $
 7131 * @package system.collections
 7132 * @since 1.0
 7133 * @author Charles Pick
 7134 * @class
 7135 * @extends Yii.CMap
 7136 */
 7137Yii.CAttributeCollection = function CAttributeCollection(data, readOnly) {
 7138	this.construct(data, readOnly);
 7139	
 7140};
 7141Yii.CAttributeCollection.prototype = new Yii.CMap();
 7142Yii.CAttributeCollection.prototype.constructor =  Yii.CAttributeCollection;
 7143/**
 7144 * @var {Boolean} whether the keys are case-sensitive. Defaults to false.
 7145 */
 7146Yii.CAttributeCollection.prototype.caseSensitive = false;
 7147/**
 7148 * Returns a property value or an event handler list by property or event name.
 7149 * This method overrides the parent implementation by returning
 7150 * a key value if the key exists in the collection.
 7151 * @param {String} name the property name or the event name
 7152 * @returns {Mixed} the property value or the event handler list
 7153 * @throws {Yii.CException} if the property/event is not defined.
 7154 */
 7155Yii.CAttributeCollection.prototype.get = function (name) {
 7156		if(this.contains(name)) {
 7157			return this.itemAt(name);
 7158		}
 7159		else {
 7160			return Yii.CMap.prototype.get.call(this, name);
 7161		}
 7162	};
 7163/**
 7164 * Sets value of a component property.
 7165 * This method overrides the parent implementation by adding a new key value
 7166 * to the collection.
 7167 * @param {String} name the property name or event name
 7168 * @param {Mixed} value the property value or event handler
 7169 * @throws {Yii.CException} If the property is not defined or read-only.
 7170 */
 7171Yii.CAttributeCollection.prototype.set = function (name, value) {
 7172		this.add(name,value);
 7173	};
 7174/**
 7175 * Checks if a property value is null.
 7176 * This method overrides the parent implementation by checking
 7177 * if the key exists in the collection and contains a non-null value.
 7178 * @param {String} name the property name or the event name
 7179 * @returns {Boolean} whether the property value is null
 7180 * @since 1.0.1
 7181 */
 7182Yii.CAttributeCollection.prototype.isset = function (name) {
 7183		if(this.contains(name)) {
 7184			return this.itemAt(name)!==null;
 7185		}
 7186		else {
 7187			return Yii.CMap.prototype.isset.call(this, name);
 7188		}
 7189	};
 7190/**
 7191 * Sets a component property to be null.
 7192 * This method overrides the parent implementation by clearing
 7193 * the specified key value.
 7194 * @param {String} name the property name or the event name
 7195 * @since 1.0.1
 7196 */
 7197Yii.CAttributeCollection.prototype.unset = function (name) {
 7198		this.remove(name);
 7199	};
 7200/**
 7201 * Returns the item with the specified key.
 7202 * This overrides the parent implementation by converting the key to lower case first if {@link caseSensitive} is false.
 7203 * @param {Mixed} key the key
 7204 * @returns {Mixed} the element at the offset, null if no element is found at the offset
 7205 */
 7206Yii.CAttributeCollection.prototype.itemAt = function (key) {
 7207		if(this.caseSensitive) {
 7208			return Yii.CMap.prototype.itemAt.call(this,key);
 7209		}
 7210		else {
 7211			return Yii.CMap.prototype.itemAt.call(this,key.toLowerCase());
 7212		}
 7213	};
 7214/**
 7215 * Adds an item into the map.
 7216 * This overrides the parent implementation by converting the key to lower case first if {@link caseSensitive} is false.
 7217 * @param {Mixed} key key
 7218 * @param {Mixed} value value
 7219 */
 7220Yii.CAttributeCollection.prototype.add = function (key, value) {
 7221		if(this.caseSensitive) {
 7222			Yii.CMap.prototype.add.call(this, key,value);
 7223		}
 7224		else {
 7225			Yii.CMap.prototype.add.call(this, key.toLowerCase(),value);
 7226		}
 7227	};
 7228/**
 7229 * Removes an item from the map by its key.
 7230 * This overrides the parent implementation by converting the key to lower case first if {@link caseSensitive} is false.
 7231 * @param {Mixed} key the key of the item to be removed
 7232 * @returns {Mixed} the removed value, null if no such key exists.
 7233 */
 7234Yii.CAttributeCollection.prototype.remove = function (key) {
 7235		if(this.caseSensitive) {
 7236			return Yii.CMap.prototype.remove.call(this, key);
 7237		}
 7238		else {
 7239			return Yii.CMap.prototype.remove.call(this, key.toLowerCase());
 7240		}
 7241	};
 7242/**
 7243 * Returns whether the specified is in the map.
 7244 * This overrides the parent implementation by converting the key to lower case first if {@link caseSensitive} is false.
 7245 * @param {Mixed} key the key
 7246 * @returns {Boolean} whether the map contains an item with the specified key
 7247 */
 7248Yii.CAttributeCollection.prototype.contains = function (key) {
 7249		if(this.caseSensitive) {
 7250			return Yii.CMap.prototype.contains.call(this, key);
 7251		}
 7252		else {
 7253			return Yii.CMap.prototype.contains.call(this, key.toLowerCase());
 7254		}
 7255	};
 7256/**
 7257 * Determines whether a property is defined.
 7258 * This method overrides parent implementation by returning true
 7259 * if the collection contains the named key.
 7260 * @param {String} name the property name
 7261 * @returns {Boolean} whether the property is defined
 7262 */
 7263Yii.CAttributeCollection.prototype.hasProperty = function (name) {
 7264		return this.contains(name) || Yii.CMap.prototype.hasProperty.call(this, name);
 7265	};
 7266/**
 7267 * Determines whether a property can be read.
 7268 * This method overrides parent implementation by returning true
 7269 * if the collection contains the named key.
 7270 * @param {String} name the property name
 7271 * @returns {Boolean} whether the property can be read
 7272 */
 7273Yii.CAttributeCollection.prototype.canGetProperty = function (name) {
 7274		return this.contains(name) || Yii.CMap.prototype.canGetProperty.call(this, name);
 7275	};
 7276/**
 7277 * Determines whether a property can be set.
 7278 * This method overrides parent implementation by always returning true
 7279 * because you can always add a new value to the collection.
 7280 * @param {String} name the property name
 7281 * @returns {Boolean} true
 7282 */
 7283Yii.CAttributeCollection.prototype.canSetProperty = function (name) {
 7284		return true;
 7285	}/*global Yii, php, $, jQuery, alert, clearInterval, clearTimeout, document, event, frames, history, Image, location, name, navigator, Option, parent, screen, setInterval, setTimeout, window, XMLHttpRequest */
 7286/**
 7287 * CConfiguration represents an array-based configuration.
 7288 * 
 7289 * It can be used to initialize an object's properties.
 7290 * 
 7291 * The configuration data may be obtained from a PHP script. For example,
 7292 * <pre>
 7293 * return {
 7294 *     'name':'My Application',
 7295 *     'defaultController':'index',
 7296 * };
 7297 * </pre>
 7298 * Use the following code to load the above configuration data:
 7299 * <pre>
 7300 * config=new Yii.CConfiguration('path/to/config.php');
 7301 * </pre>
 7302 * 
 7303 * To apply the configuration to an object, call {@link applyTo()}.
 7304 * Each (key,value) pair in the configuration data is applied
 7305 * to the object like: $object->$key=$value.
 7306 * 
 7307 * Since CConfiguration extends from {@link CMap}, it can be
 7308 * used like an associative array. See {@link CMap} for more details.
 7309 * 
 7310 * @originalAuthor Qiang Xue <qiang.xue@gmail.com>
 7311 * @version $Id: CConfiguration.php 3001 2011-02-24 16:42:44Z alexander.makarow $
 7312 * @package system.collections
 7313 * @since 1.0
 7314 * @author Charles Pick
 7315 * @class
 7316 * @extends Yii.CMap
 7317 */
 7318Yii.CConfiguration = function CConfiguration (data, readOnly) {
 7319	this.construct(data, readOnly);
 7320	
 7321};
 7322Yii.CConfiguration.prototype = new Yii.CMap();
 7323Yii.CConfiguration.prototype.constructor =  Yii.CConfiguration;
 7324
 7325/**
 7326 * Saves the configuration into a JSON string.
 7327 * The string is a valid JSON expression representing the configuration data as an object.
 7328 * @returns {String} the JSON representation of the configuration
 7329 */
 7330Yii.CConfiguration.prototype.saveAsString = function () {
 7331		return Yii.CJSON.encode(this.toObject());
 7332	};
 7333/**
 7334 * Applies the configuration to an object.
 7335 * Each (key,value) pair in the configuration data is applied
 7336 * to the object like: $object->$key=$value.
 7337 * @param {Object} object object to be applied with this configuration
 7338 */
 7339Yii.CConfiguration.prototype.applyTo = function (object) {
 7340		var keyValue, key, value;
 7341		keyValue = this.toObject();
 7342		for (key in keyValue) {
 7343			if (keyValue.hasOwnProperty(key)) {
 7344				value = keyValue[key];
 7345				object[key] = value;
 7346			}
 7347		}
 7348	};/*global Yii, php, $, jQuery, alert, clearInterval, clearTimeout, document, event, frames, history, Image, location, name, navigator, Option, parent, screen, setInterval, setTimeout, window, XMLHttpRequest */
 7349/**
 7350 * CQueue implements a queue.
 7351 * 
 7352 * The typical queue operations are implemented, which include
 7353 * {@link enqueue()}, {@link dequeue()} and {@link peek()}. In addition,
 7354 * {@link contains()} can be used to check if an item is contained
 7355 * in the queue. To obtain the number of the items in the queue,
 7356 * check the {@link getCount Count} property.
 7357 * 
 7358 * Items in the queue may be traversed using foreach as follows,
 7359 * <pre>
 7360 * for (i in queue) +++
 7361 * </pre>
 7362 * 
 7363 * @originalAuthor Qiang Xue <qiang.xue@gmail.com>
 7364 * @version $Id: CQueue.php 3001 2011-02-24 16:42:44Z alexander.makarow $
 7365 * @package system.collections
 7366 * @since 1.0
 7367 * @author Charles Pick
 7368 * @class
 7369 * @extends Yii.CComponent
 7370 */
 7371Yii.CQueue = function CQueue(data) {
 7372	this.readOnly = false;
 7373	this.construct(data);
 7374	
 7375};
 7376Yii.CQueue.prototype = new Yii.CList();
 7377Yii.CQueue.prototype.constructor =  Yii.CQueue;
 7378
 7379/**
 7380 * Constructor.
 7381 * Initializes the queue with an array or an iterable object.
 7382 * @param {Array} data the intial data. Default is null, meaning no initialization.
 7383 * @throws {Yii.CException} If data is not null and neither an array nor an iterator.
 7384 */
 7385Yii.CQueue.prototype.construct = function (data) {
 7386		if (data === undefined) {
 7387			data = null;
 7388		}
 7389		if(data!==null) {
 7390			this.copyFrom(data);
 7391		}
 7392	};
 7393
 7394
 7395
 7396/**
 7397 * @param {Mixed} item the item
 7398 * @returns {Boolean} whether the queue contains the item
 7399 */
 7400Yii.CQueue.prototype.contains = function (item) {
 7401		var i, limit = this.length;
 7402		for (i = 0; i < limit; i++) {
 7403			if (item === this[i]) {
 7404				return true;
 7405			}
 7406		}
 7407		return false;
 7408	};
 7409/**
 7410 * Returns the item at the top of the queue.
 7411 * @returns {Mixed} item at the top of the queue
 7412 * @throws {Yii.CException} if the queue is empty
 7413 */
 7414Yii.CQueue.prototype.peek = function () {
 7415		if(this.length===0) {
 7416			throw new Yii.CException(Yii.t('yii','The queue is empty.'));
 7417		}
 7418		else {
 7419			return this[0];
 7420		}
 7421	};
 7422/**
 7423 * Removes and returns the object at the beginning of the queue.
 7424 * @returns {Mixed} the item at the beginning of the queue
 7425 * @throws {Yii.CException} if the queue is empty
 7426 */
 7427Yii.CQueue.prototype.dequeue = function () {
 7428		if(this.length===0) {
 7429			throw new Yii.CException(Yii.t('yii','The queue is empty.'));
 7430		}
 7431		else {
 7432			return this.shift();
 7433		}
 7434	};
 7435/**
 7436 * Adds an object to the end of the queue.
 7437 * @param {Mixed} item the item to be appended into the queue
 7438 */
 7439Yii.CQueue.prototype.enqueue = function (item) {
 7440		this.push(item);
 7441	};
 7442
 7443/*global Yii, php, $, jQuery, alert, clearInterval, clearTimeout, document, event, frames, history, Image, location, name, navigator, Option, parent, screen, setInterval, setTimeout, window, XMLHttpRequest */
 7444/**
 7445 * CStack implements a stack.
 7446 * 
 7447 * The typical stack operations are implemented, which include
 7448 * {@link push()}, {@link pop()} and {@link peek()}. In addition,
 7449 * {@link contains()} can be used to check if an item is contained
 7450 * in the stack. To obtain the number of the items in the stack,
 7451 * check the {@link getCount Count} property.
 7452 * 
 7453 * Items in the stack may be traversed using foreach as follows,
 7454 * <pre>
 7455 * for (i in stack) +++
 7456 * </pre>
 7457 * 
 7458 * @originalAuthor Qiang Xue <qiang.xue@gmail.com>
 7459 * @version $Id: CStack.php 3001 2011-02-24 16:42:44Z alexander.makarow $
 7460 * @package system.collections
 7461 * @since 1.0
 7462 * @author Charles Pick
 7463 * @class
 7464 * @extends Yii.CComponent
 7465 */
 7466Yii.CStack = function CStack (data) {
 7467	this.construct(data);
 7468};
 7469Yii.CStack.prototype = new Array();
 7470Yii.CStack.prototype.constructor =  Yii.CStack;
 7471Yii.augment(Yii.CStack, Yii.CComponent);
 7472/**
 7473 * Constructor.
 7474 * Initializes the stack with an array or an iterable object.
 7475 * @param {Array} data the initial data. Default is null, meaning no initialization.
 7476 * @throws {Yii.CException} If data is not null and neither an array nor an iterator.
 7477 */
 7478Yii.CStack.prototype.construct = function (data) {
 7479		if (data === undefined) {
 7480			data = null;
 7481		}
 7482		if(data!==null) {
 7483			this.copyFrom(data);
 7484		}
 7485	};
 7486/**
 7487 * @returns {Array} the list of items in stack
 7488 */
 7489Yii.CStack.prototype.toArray = function () {
 7490		var ret = [], i, limit;
 7491		limit = this.length;
 7492		for (i = 0; i < limit; i++) {
 7493			ret.push(this[i]);
 7494		}
 7495		return ret;
 7496	};
 7497/**
 7498 * Copies iterable data into the stack.
 7499 * Note, existing data in the list will be cleared first.
 7500 * @param {Mixed} data the data to be copied from, must be an array or object implementing Traversable
 7501 * @throws {Yii.CException} If data is neither an array nor a Traversable.
 7502 */
 7503Yii.CStack.prototype.copyFrom = function (data) {
 7504		var i, item;
 7505		if(Object.prototype.toString.call(data) === '[object Array]' || (data instanceof Array))
 7506		{
 7507			this.clear();
 7508			for (i in data)
 7509			{
 7510				if (data.hasOwnProperty(i)) {
 7511					item = data[i];
 7512					this.push(item);
 7513				}
 7514			}
 7515		}
 7516		else if(data!==null) {
 7517			throw new Yii.CException(Yii.t('yii','Stack data must be an array or an object implementing Traversable.'));
 7518		}
 7519	};
 7520/**
 7521 * Removes all items in the stack.
 7522 */
 7523Yii.CStack.prototype.clear = function () {
 7524		var i, limit;
 7525		limit = this.length;
 7526		for(i = 0; i < limit; i++) {
 7527			delete this[i];
 7528		}
 7529	};
 7530/**
 7531 * @param {Mixed} item the item
 7532 * @returns {Boolean} whether the stack contains the item
 7533 */
 7534Yii.CStack.prototype.contains = function (item) {
 7535		var i, limit = this.length;
 7536		for (i = 0; i < limit; i++) {
 7537			if (item === this[i]) {
 7538				return true;
 7539			}
 7540		}
 7541		return false;
 7542	};
 7543/**
 7544 * Returns the item at the top of the stack.
 7545 * Unlike {@link pop()}, this method does not remove the item from the stack.
 7546 * @returns {Mixed} item at the top of the stack
 7547 * @throws {Yii.CException} if the stack is empty
 7548 */
 7549Yii.CStack.prototype.peek = function () {
 7550		if(this.length) {
 7551			return this[this.length - 1];
 7552		}
 7553		else {
 7554			throw new Yii.CException(Yii.t('yii','The stack is empty.'));
 7555		}
 7556	};
 7557/**
 7558 * Pops up the item at the top of the stack.
 7559 * @returns {Mixed} the item at the top of the stack
 7560 * @throws {Yii.CException} if the stack is empty
 7561 */
 7562Yii.CStack.prototype.pop = function () {
 7563		if(this.length) {
 7564			return Array.prototype.pop.call(this);
 7565		}
 7566		else {
 7567			throw new Yii.CException(Yii.t('yii','The stack is empty.'));
 7568		}
 7569	};
 7570
 7571/**
 7572 * Returns the number of items in the stack.
 7573 * @returns {Integer} the number of items in the stack
 7574 */
 7575Yii.CStack.prototype.getCount = function () {
 7576		return this.length;
 7577	};
 7578/**
 7579 * Returns the number of items in the stack.
 7580 * This method is required by Countable interface.
 7581 * @returns {Integer} number of items in the stack.
 7582 */
 7583Yii.CStack.prototype.count = function () {
 7584		return this.length;
 7585	};
 7586/**
 7587 * Provides convenient access to Yii.forEach()
 7588 * @param {Function} callback The callback function, this will receive 2 parameters, key and value
 7589 * @returns {Yii.CStack} the stack
 7590 */
 7591Yii.CStack.prototype.forEach = function(callback) {
 7592	return Yii.forEach(this,callback);
 7593};/*global Yii, php, $, jQuery, alert, clearInterval, clearTimeout, document, event, frames, history, Image, location, name, navigator, Option, parent, screen, setInterval, setTimeout, window, XMLHttpRequest */
 7594/**
 7595 * CTypedList represents a list whose items are of the certain type.
 7596 * 
 7597 * CTypedList extends {@link CList} by making sure that the elements to be
 7598 * added to the list is of certain class type.
 7599 * 
 7600 * @originalAuthor Qiang Xue <qiang.xue@gmail.com>
 7601 * @version $Id: CTypedList.php 3001 2011-02-24 16:42:44Z alexander.makarow $
 7602 * @package system.collections
 7603 * @since 1.0
 7604 * @author Charles Pick
 7605 * @class
 7606 * @extends Yii.CList
 7607 */
 7608Yii.CTypedList = function CTypedList (type) {
 7609	this.construct(type);
 7610};
 7611Yii.CTypedList.prototype = new Yii.CList();
 7612Yii.CTypedList.prototype.constructor =  Yii.CTypedList;
 7613Yii.CTypedList.prototype._type = null;
 7614/**
 7615 * Constructor.
 7616 * @param {String} type class type
 7617 */
 7618Yii.CTypedList.prototype.construct = function (type) {
 7619		this._type=type;
 7620	};
 7621/**
 7622 * Inserts an item at the specified position.
 7623 * This method overrides the parent implementation by
 7624 * checking the item to be inserted is of certain type.
 7625 * @param {Integer} index the specified position.
 7626 * @param {Mixed} item new item
 7627 * @throws {Yii.CException} If the index specified exceeds the bound,
 7628 * the list is read-only or the element is not of the expected type.
 7629 */
 7630Yii.CTypedList.prototype.insertAt = function (index, item) {
 7631		if(item instanceof this._type) {
 7632			Yii.CList.prototype.insertAt.call(this,index,item);
 7633		}
 7634		else {
 7635			throw new Yii.CException(Yii.t('yii','CTypedList<{type}> can only hold objects of {type} class.',
 7636				{'{type}':this._type}));
 7637		}
 7638};
 7639
 7640/**
 7641 * Pushes an item on to the end of the list
 7642 * @param {Mixed} the item to add
 7643 * @returns {Integer} the number of items in the list
 7644 */
 7645Yii.CTypedList.prototype.push = function (item) {
 7646	if(item instanceof this._type) {
 7647		return Yii.CList.prototype.push.call(this,item);
 7648	}
 7649	else {
 7650		throw new Yii.CException(Yii.t('yii','CTypedList<{type}> can only hold objects of {type} class.',
 7651			{'{type}':this._type}));
 7652	}
 7653};
 7654/*global Yii, php, $, jQuery, alert, clearInterval, clearTimeout, document, event, frames, history, Image, location, name, navigator, Option, parent, screen, setInterval, setTimeout, window, XMLHttpRequest */
 7655/**
 7656 * CTypedMap represents a map whose items are of the certain type.
 7657 * 
 7658 * CTypedMap extends {@link CMap} by making sure that the elements to be
 7659 * added to the list is of certain class type.
 7660 * 
 7661 * @originalAuthor Qiang Xue <qiang.xue@gmail.com>
 7662 * @version $Id: CTypedMap.php 3001 2011-02-24 16:42:44Z alexander.makarow $
 7663 * @package system.collections
 7664 * @since 1.0
 7665 * @author Charles Pick
 7666 * @class
 7667 * @extends Yii.CMap
 7668 */
 7669Yii.CTypedMap = function CTypedMap (type) {
 7670	this.construct(type);
 7671};
 7672Yii.CTypedMap.prototype = new Yii.CMap();
 7673Yii.CTypedMap.prototype.constructor =  Yii.CTypedMap;
 7674Yii.CTypedMap.prototype._type = null;
 7675/**
 7676 * Constructor.
 7677 * @param {String} type class type
 7678 */
 7679Yii.CTypedMap.prototype.construct = function (type) {
 7680		this._type=type;
 7681	};
 7682/**
 7683 * Adds an item into the map.
 7684 * This method overrides the parent implementation by
 7685 * checking the item to be inserted is of certain type.
 7686 * @param {Integer} index the specified position.
 7687 * @param {Mixed} item new item
 7688 * @throws {Yii.CException} If the index specified exceeds the bound,
 7689 * the map is read-only or the element is not of the expected type.
 7690 */
 7691Yii.CTypedMap.prototype.add = function (index, item) {
 7692		if(item instanceof this._type) {
 7693			Yii.CMap.prototype.add.call(this, index,item);
 7694		}
 7695		else {
 7696			throw new Yii.CException(Yii.t('yii','CTypedMap<{type}> can only hold objects of {type} class.',
 7697				{'{type}':this._type}));
 7698		}
 7699};var YII_PATH = "/js/test/";
 7700var appConfig = {
 7701	'basePath': "/js/app",
 7702	'name': "EbayStore",
 7703	'preload': ["log"],
 7704	'params': {
 7705		'version': 0.1
 7706	},
 7707	'components': {
 7708		'db': {
 7709			'connectionString': 'sqlite:host=localhost;dbname=ebaystore',
 7710			'enableParamLogging': true,
 7711			'enableProfiling': true,
 7712			'initSQLs': [
 7713				
 7714			]
 7715		},
 7716		'viewRenderer' : {
 7717			'class': 'CMustacheViewRenderer'
 7718		},
 7719		'request': {
 7720			'enableCsrfValidation': true,
 7721			'enableCookieValidation': true
 7722		},
 7723		'log': {
 7724			'class': 'CLogRouter',
 7725			'routes': [
 7726				{
 7727					'class': 'CProfileLogRoute',
 7728					'showInFireBug': false
 7729				},
 7730				{
 7731					'class': 'CWebLogRoute',
 7732					'showInFireBug': false
 7733				}
 7734			]
 7735		},
 7736		'cache': {
 7737			'class': 'CSessionCache'
 7738		},
 7739		'urlManager': {
 7740			'urlFormat': 'path',
 7741			'showScriptName': false,
 7742			'urlSuffix': '.html',
 7743			'useStrictParsing': false,
 7744			'rules': [
 7745				{
 7746					'pattern': '/',
 7747					'route': '/site/index',
 7748					'urlSuffix': ''
 7749				},
 7750				{
 7751					'pattern': 'contactus',
 7752					'route': '/site/contact'
 7753				},
 7754				{
 7755					'pattern': '<controller:\\w+>s',
 7756					'route': '<controller>/index'	
 7757				},
 7758				{
 7759					'pattern': '<controller:\\w+>s/<id:\\d+>',
 7760					'route': '<controller>/view'	
 7761				},
 7762				{
 7763					'pattern': '<controller:\\w+>s/<action:\\w+>/<id:\\d+>',
 7764					'route': '<controller>/<action>'	
 7765				},
 7766				{
 7767					'pattern': '<controller:\\w+>s/<action:\\w+>',
 7768					'route': '<controller>/<action>'	
 7769				}
 7770			]
 7771		}		
 7772	}
 7773};
 7774/*global Yii, php, $, jQuery, alert, clearInterval, clearTimeout, document, event, frames, history, Image, location, name, navigator, Option, parent, screen, setInterval, setTimeout, window, XMLHttpRequest */
 7775/**
 7776 * A base class for data sources.
 7777 * @package system.ds
 7778 * @since 1.0
 7779 * @author Charles Pick
 7780 * @class
 7781 * @extends Yii.CComponent
 7782 */
 7783Yii.CActiveDataSource = function CActiveDataSource () {
 7784	
 7785};
 7786Yii.CActiveDataSource.prototype = new Yii.CComponent();
 7787Yii.CActiveDataSource.prototype.constructor =  Yii.CActiveDataSource;
 7788
 7789/**
 7790 * Gets data from the data source and executes the callback when data arrives.
 7791 * Child classes must override this method!
 7792 * @param {Function} callback The callback function to execute, this will recieve the
 7793 * data as its first parameter and the data source as its second parameter.
 7794 * 
 7795 */
 7796Yii.CActiveDataSource.prototype.getData = function (callback) {
 7797	
 7798};
 7799
 7800/*global Yii, php, $, jQuery, alert, clearInterval, clearTimeout, document, event, frames, history, Image, location, name, navigator, Option, parent, screen, setInterval, setTimeout, window, XMLHttpRequest */
 7801/**
 7802 * CAsyncRecord is the base class for classes representing relational data loaded from a remote data source.
 7803 * 
 7804 * It implements the active record design pattern, a popular Object-Relational Mapping (ORM) technique.
 7805 * 
 7806 * @package system.ds
 7807 * @since 1.0
 7808 * 
 7809 * @property array $attributes
 7810 * @author Charles Pick
 7811 * @class
 7812 * @extends Yii.CModel
 7813 */
 7814Yii.CAsyncRecord = function CAsyncRecord (scenario, callback) {
 7815	if (scenario !== false) {
 7816		return this.construct(scenario, callback);
 7817	}
 7818};
 7819Yii.CAsyncRecord.prototype = new Yii.CModel(false);
 7820Yii.CAsyncRecord.prototype.constructor =  Yii.CAsyncRecord;
 7821/**
 7822 * @const
 7823 */
 7824Yii.CAsyncRecord.prototype.BELONGS_TO = 'CBelongsToRelation';
 7825/**
 7826 * @const
 7827 */
 7828Yii.CAsyncRecord.prototype.HAS_ONE = 'CHasOneRelation';
 7829/**
 7830 * @const
 7831 */
 7832Yii.CAsyncRecord.prototype.HAS_MANY = 'CHasManyRelation';
 7833/**
 7834 * @const
 7835 */
 7836Yii.CAsyncRecord.prototype.MANY_MANY = 'CManyManyRelation';
 7837/**
 7838 * @const
 7839 */
 7840Yii.CAsyncRecord.prototype.STAT = 'CStatRelation';
 7841/**
 7842 * @var {Yii.CActiveDataSource} the default data source for all active records 
 7843 * @see getDbConnection
 7844 */
 7845Yii.CAsyncRecord.prototype._ds = null;
 7846/**
 7847 * Whether or not to wrap the posted data in an object or not.
 7848 * If this is set to true, data will be wrapped in an object with the same name as 
 7849 * this model. If set to a string, the string value will be used to wrap. If false
 7850 * no wrapping will be applied.
 7851 * Defaults to false.
 7852 * @var Mixed
 7853 */
 7854Yii.CAsyncRecord.prototype.wrapData = false;
 7855Yii.CAsyncRecord.prototype._models = {};
 7856Yii.CAsyncRecord.prototype._new = false;
 7857Yii.CAsyncRecord.prototype._attributes = {};
 7858Yii.CAsyncRecord.prototype._related = {};
 7859Yii.CAsyncRecord.prototype._c = null;
 7860Yii.CAsyncRecord.prototype._pk = null;
 7861Yii.CAsyncRecord.prototype._alias = 't';
 7862/**
 7863 * Constructor.
 7864 * @param {String} scenario scenario name. See {@link CModel::scenario} for more details about this parameter.
 7865 */
 7866Yii.CAsyncRecord.prototype.construct = function (scenario) {
 7867		if (scenario === undefined) {
 7868			scenario = 'insert';
 7869		}
 7870		if(scenario===null) { // internally used by populateRecord() and model()
 7871			return;
 7872		}
 7873		this._attributes = {};
 7874		this._ds = this.dataStoreDefaults();
 7875		this.setScenario(scenario);
 7876		this.setIsNewRecord(true);
 7877		this._attributes=this.attributeDefaults();
 7878		this.init();
 7879		this.attachBehaviors(this.behaviors());
 7880		this.afterConstruct();
 7881	};
 7882
 7883/**
 7884 * Initializes this model.
 7885 * This method is invoked when an AR instance is newly created and has
 7886 * its {@link scenario} set.
 7887 * You may override this method to provide code that is needed to initialize the model (e.g. setting
 7888 * initial property values.)
 7889 * @since 1.0.8
 7890 */
 7891Yii.CAsyncRecord.prototype.init = function () {
 7892	};
 7893/**
 7894 * Returns a list of attribute names and their default values.
 7895 * Child classes should override this!
 7896 * @returns {Object} attributeName: value
 7897 */
 7898Yii.CAsyncRecord.prototype.attributeDefaults = function () {
 7899	return {};
 7900};
 7901/**
 7902 * Sets the parameters about query caching.
 7903 * This is a shortcut method to {@link CDbConnection::cache()}.
 7904 * It changes the query caching parameter of the {@link dbConnection} instance.
 7905 * @param {Integer} duration the number of seconds that query results may remain valid in cache.
 7906 * If this is 0, the caching will be disabled.
 7907 * @param {Yii.CCacheDependency} dependency the dependency that will be used when saving the query results into cache.
 7908 * @param {Integer} queryCount number of SQL queries that need to be cached after calling this method. Defaults to 1,
 7909 * meaning that the next SQL query will be cached.
 7910 * @returns {Yii.CAsyncRecord} the active record instance itself.
 7911 * @since 1.1.7
 7912 */
 7913Yii.CAsyncRecord.prototype.cache = function (duration, dependency, queryCount) {
 7914		if (dependency === undefined) {
 7915			dependency = null;
 7916		}
 7917		if (queryCount === undefined) {
 7918			queryCount = 1;
 7919		}
 7920		this.getDataSource().cache(duration, dependency, queryCount);
 7921		return this;
 7922	};
 7923
 7924/**
 7925 * Getter magic method.
 7926 * This method is overridden so that RR attributes can be accessed like properties.
 7927 * @param {String} name property name
 7928 * @returns {Mixed} property value
 7929 * @see getAttribute
 7930 */
 7931Yii.CAsyncRecord.prototype.get = function (name) {
 7932		var getter, i, object, nameParts = [], limit;
 7933		if (name.indexOf(".") !== -1) {
 7934			nameParts = name.split(".");
 7935			name = nameParts.shift();
 7936		}
 7937		if (this[name] !== undefined) {
 7938			object = this[name];
 7939		}
 7940		else if (this._attributes[name] !== undefined) {
 7941			object = this._attributes[name];
 7942		}
 7943		else if (this._related[name] !== undefined) {
 7944			object = this._related[name];
 7945		}
 7946		if (object !== undefined) {
 7947			if (nameParts.length > 0) {
 7948				if (object instanceof Yii.CComponent) {
 7949					return object.get(nameParts.join("."));
 7950				}
 7951				limit = nameParts.length;
 7952				for (i = 0; i < limit; i++) {
 7953					name = nameParts.shift();
 7954					object = object[name];
 7955					if (nameParts.length === 0) {
 7956						return object;
 7957					}
 7958					
 7959					if (object instanceof Yii.CComponent) {
 7960						return object.get(nameParts.join("."));
 7961					}
 7962				}
 7963			}
 7964			return object;
 7965		}
 7966		else {
 7967			if (nameParts.length > 0) {
 7968				return Yii.CModel.prototype.get.call(this, php.array_merge([name],nameParts).join("."));
 7969			}
 7970			return Yii.CModel.prototype.get.call(this,name);
 7971		}
 7972	};
 7973/**
 7974 * Setter magic method.
 7975 * This method is overridden so that RR attributes can be accessed like properties.
 7976 * @param {String} name property name
 7977 * @param {Mixed} value property value
 7978 */
 7979Yii.CAsyncRecord.prototype.set = function (name, value) {
 7980		var nameParts = [];
 7981		if (name.indexOf(".") !== -1) {
 7982			nameParts = name.split(".");
 7983			name = nameParts.pop();
 7984			nameParts = nameParts.join(".");
 7985			return (this.get(nameParts)[name] = value);
 7986		}
 7987		else if(this.setAttribute(name,value)===false) {
 7988			if(this.relations[name] !== undefined) {
 7989				this._related[name]=value;
 7990			}
 7991			else {
 7992				Yii.CModel.prototype.set.call(this, name,value);
 7993			}
 7994		}
 7995	};
 7996/**
 7997 * Gets the data source for this model.
 7998 * @returns {Yii.CActiveDataSource} The data source that this model interacts with
 7999 */
 8000Yii.CAsyncRecord.prototype.getDataSource = function () {
 8001	if (this._ds !== null) {
 8002		if (this._ds instanceof Yii.CActiveDataSource) {
 8003			return this._ds;
 8004		}
 8005		this._ds = Yii.createComponent(this._ds);
 8006	}
 8007	return this._ds;
 8008};
 8009
 8010/**
 8011 * Sets the data source for this model
 8012 * @param {Yii.CActiveDataSource} value The data source to use with this model
 8013 */
 8014Yii.CAsyncRecord.prototype.setDataSource = function (value) {
 8015	var className;
 8016	if (!(value instanceof Yii.CActiveDataSource)) {
 8017		if (value['class'] !== undefined) {
 8018			className = value['class'];
 8019			delete value['class'];
 8020		}
 8021		else {
 8022			className = 'CActiveDataSource';
 8023		}
 8024		
 8025		value = Yii.createComponent(className, value);
 8026	}
 8027	this._ds = value;
 8028}
 8029
 8030/**
 8031 * Checks whether this AR has the named attribute
 8032 * @param {String} name attribute name
 8033 * @returns {Boolean} whether this AR has the named attribute (table column).
 8034 */
 8035Yii.CAsyncRecord.prototype.hasAttribute = function (name) {
 8036		return this.get(name) !== undefined;
 8037	};
 8038/**
 8039 * Returns the named attribute value.
 8040 * If this is a new record and the attribute is not set before,
 8041 * the default column value will be returned.
 8042 * If this record is the result of a query and the attribute is not loaded,
 8043 * null will be returned.
 8044 * You may also use $this->AttributeName to obtain the attribute value.
 8045 * @param {String} name the attribute name
 8046 * @returns {Mixed} the attribute value. Null if the attribute is not set or does not exist.
 8047 * @see hasAttribute
 8048 */
 8049Yii.CAsyncRecord.prototype.getAttribute = function (name) {
 8050		if(this[name] !== undefined) {
 8051			return this[name];
 8052		}
 8053		else if(this._attributes[name] !== undefined) {
 8054			return this._attributes[name];
 8055		}
 8056	};
 8057/**
 8058 * Returns all column attribute values.
 8059 * Note, related objects are not returned.
 8060 * @param {Mixed} names names of attributes whose value needs to be returned.
 8061 * If this is true (default), then all attribute values will be returned, including
 8062 * those that are not loaded from DB (null will be returned for those attributes).
 8063 * If this is null, all attributes except those that are not loaded from DB will be returned.
 8064 * @returns {Array} attribute values indexed by attribute names.
 8065 */
 8066Yii.CAsyncRecord.prototype.getAttributes = function (names) {
 8067		var attributes, nameColumn, name, attrs, i, column;
 8068		if (names === undefined) {
 8069			names = true;
 8070		}
 8071		attributes=this._attributes;
 8072		
 8073		if(Object.prototype.toString.call(names) === '[object Array]') {
 8074			attrs=[];
 8075			for (i in names) {
 8076				if (names.hasOwnProperty(i)) {
 8077					name = names[i];
 8078					if(this[name] !== undefined) {
 8079						attrs[name]=this.name;
 8080					}
 8081					else {
 8082						attrs[name]=attributes[name] !== undefined?attributes[name]:null;
 8083					}
 8084				}
 8085			}
 8086			return attrs;
 8087		}
 8088		else {
 8089			return attributes;
 8090		}
 8091	};
 8092/**
 8093 * Sets the named attribute value.
 8094 * You may also use $this->AttributeName to set the attribute value.
 8095 * @param {String} name the attribute name
 8096 * @param {Mixed} value the attribute value.
 8097 * @returns {Boolean} whether the attribute exists and the assignment is conducted successfully
 8098 * @see hasAttribute
 8099 */
 8100Yii.CAsyncRecord.prototype.setAttribute = function (name, value) {
 8101		if(this[name] !== undefined) {
 8102			this[name]=value;
 8103		}
 8104		else if(this._attributes[name] !== undefined) {
 8105			this._attributes[name]=value;
 8106		}
 8107		else {
 8108			return false;
 8109		}
 8110		return true;
 8111	};
 8112
 8113/**
 8114 * Returns if the current record is new.
 8115 * @returns {Boolean} whether the record is new and should be inserted when calling {@link save}.
 8116 * This property is automatically set in constructor and {@link populateRecord}.
 8117 * Defaults to false, but it will be set to true if the instance is created using
 8118 * the new operator.
 8119 */
 8120Yii.CAsyncRecord.prototype.getIsNewRecord = function () {
 8121		return this._new;
 8122	};
 8123/**
 8124 * Sets if the record is new.
 8125 * @param {Boolean} value whether the record is new and should be inserted when calling {@link save}.
 8126 * @see getIsNewRecord
 8127 */
 8128Yii.CAsyncRecord.prototype.setIsNewRecord = function (value) {
 8129		this._new=value;
 8130	};
 8131/**
 8132 * This event is raised before the record is saved.
 8133 * By setting {@link CModelEvent::isValid} to be false, the normal {@link save()} process will be stopped.
 8134 * @param {Yii.CModelEvent} event the event parameter
 8135 * @since 1.0.2
 8136 */
 8137Yii.CAsyncRecord.prototype.onBeforeSave = function (event) {
 8138		this.raiseEvent('onBeforeSave',event);
 8139	};
 8140/**
 8141 * This event is raised after the record is saved.
 8142 * @param {Yii.CEvent} event the event parameter
 8143 * @since 1.0.2
 8144 */
 8145Yii.CAsyncRecord.prototype.onAfterSave = function (event) {
 8146		this.raiseEvent('onAfterSave',event);
 8147	};
 8148/**
 8149 * This event is raised before the record is deleted.
 8150 * By setting {@link CModelEvent::isValid} to be false, the normal {@link delete()} process will be stopped.
 8151 * @param {Yii.CModelEvent} event the event parameter
 8152 * @since 1.0.2
 8153 */
 8154Yii.CAsyncRecord.prototype.onBeforeDelete = function (event) {
 8155		this.raiseEvent('onBeforeDelete',event);
 8156	};
 8157/**
 8158 * This event is raised after the record is deleted.
 8159 * @param {Yii.CEvent} event the event parameter
 8160 * @since 1.0.2
 8161 */
 8162Yii.CAsyncRecord.prototype.onAfterDelete = function (event) {
 8163		this.raiseEvent('onAfterDelete',event);
 8164	};
 8165/**
 8166 * This event is raised before an AR finder performs a find call.
 8167 * In this event, the {@link CModelEvent::criteria} property contains the query criteria
 8168 * passed as parameters to those find methods. If you want to access
 8169 * the query criteria specified in scopes, please use {@link getDbCriteria()}.
 8170 * You can modify either criteria to customize them based on needs.
 8171 * @param {Yii.CModelEvent} event the event parameter
 8172 * @see beforeFind
 8173 * @since 1.0.9
 8174 */
 8175Yii.CAsyncRecord.prototype.onBeforeFind = function (event) {
 8176		this.raiseEvent('onBeforeFind',event);
 8177	};
 8178/**
 8179 * This event is raised after the record is instantiated by a find method.
 8180 * @param {Yii.CEvent} event the event parameter
 8181 * @since 1.0.2
 8182 */
 8183Yii.CAsyncRecord.prototype.onAfterFind = function (event) {
 8184		this.raiseEvent('onAfterFind',event);
 8185	};
 8186/**
 8187 * This method is invoked before saving a record (after validation, if any).
 8188 * The default implementation raises the {@link onBeforeSave} event.
 8189 * You may override this method to do any preparation work for record saving.
 8190 * Use {@link isNewRecord} to determine whether the saving is
 8191 * for inserting or updating record.
 8192 * Make sure you call the parent implementation so that the event is raised properly.
 8193 * @returns {Boolean} whether the saving should be executed. Defaults to true.
 8194 */
 8195Yii.CAsyncRecord.prototype.beforeSave = function () {
 8196		var event;
 8197		if(this.hasEventHandler('onBeforeSave')) {
 8198			event=new Yii.CModelEvent(this);
 8199			this.onBeforeSave(event);
 8200			return event.isValid;
 8201		}
 8202		else {
 8203			return true;
 8204		}
 8205	};
 8206/**
 8207 * This method is invoked after saving a record successfully.
 8208 * The default implementation raises the {@link onAfterSave} event.
 8209 * You may override this method to do postprocessing after record saving.
 8210 * Make sure you call the parent implementation so that the event is raised properly.
 8211 */
 8212Yii.CAsyncRecord.prototype.afterSave = function () {
 8213		if(this.hasEventHandler('onAfterSave')) {
 8214			this.onAfterSave(new Yii.CEvent(this));
 8215		}
 8216	};
 8217/**
 8218 * This method is invoked before deleting a record.
 8219 * The default implementation raises the {@link onBeforeDelete} event.
 8220 * You may override this method to do any preparation work for record deletion.
 8221 * Make sure you call the parent implementation so that the event is raised properly.
 8222 * @returns {Boolean} whether the record should be deleted. Defaults to true.
 8223 */
 8224Yii.CAsyncRecord.prototype.beforeDelete = function () {
 8225		var event;
 8226		if(this.hasEventHandler('onBeforeDelete')) {
 8227			event=new Yii.CModelEvent(this);
 8228			this.onBeforeDelete(event);
 8229			return event.isValid;
 8230		}
 8231		else {
 8232			return true;
 8233		}
 8234	};
 8235/**
 8236 * This method is invoked after deleting a record.
 8237 * The default implementation raises the {@link onAfterDelete} event.
 8238 * You may override this method to do postprocessing after the record is deleted.
 8239 * Make sure you call the parent implementation so that the event is raised properly.
 8240 */
 8241Yii.CAsyncRecord.prototype.afterDelete = function () {
 8242		if(this.hasEventHandler('onAfterDelete')) {
 8243			this.onAfterDelete(new Yii.CEvent(this));
 8244		}
 8245	};
 8246/**
 8247 * This method is invoked before an AR finder executes a find call.
 8248 * The find calls include {@link find}, {@link findAll}, {@link findByPk},
 8249 * {@link findAllByPk}, {@link findByAttributes} and {@link findAllByAttributes}.
 8250 * The default implementation raises the {@link onBeforeFind} event.
 8251 * If you override this method, make sure you call the parent implementation
 8252 * so that the event is raised properly.
 8253 * 
 8254 * Starting from version 1.1.5, this method may be called with a hidden {@link CDbCriteria}
 8255 * parameter which represents the current query criteria as passed to a find method of AR.
 8256 * 
 8257 * @since 1.0.9
 8258 */
 8259Yii.CAsyncRecord.prototype.beforeFind = function () {
 8260		var event;
 8261		if(this.hasEventHandler('onBeforeFind')) {
 8262			event=new Yii.CModelEvent(this);
 8263			// for backward compatibility
 8264			event.criteria=arguments.length>0 ? arguments[0] : null;
 8265			this.onBeforeFind(event);
 8266		}
 8267	};
 8268/**
 8269 * This method is invoked after each record is instantiated by a find method.
 8270 * The default implementation raises the {@link onAfterFind} event.
 8271 * You may override this method to do postprocessing after each newly found record is instantiated.
 8272 * Make sure you call the parent implementation so that the event is raised properly.
 8273 */
 8274Yii.CAsyncRecord.prototype.afterFind = function () {
 8275		if(this.hasEventHandler('onAfterFind')) {
 8276			this.onAfterFind(new Yii.CEvent(this));
 8277		}
 8278	};
 8279/**
 8280 * Calls {@link beforeFind}.
 8281 * This method is internally used.
 8282 * @since 1.0.11
 8283 */
 8284Yii.CAsyncRecord.prototype.beforeFindInternal = function () {
 8285		this.beforeFind();
 8286	};
 8287/**
 8288 * Calls {@link afterFind}.
 8289 * This method is internally used.
 8290 * @since 1.0.3
 8291 */
 8292Yii.CAsyncRecord.prototype.afterFindInternal = function () {
 8293		this.afterFind();
 8294	};
 8295	
 8296	
 8297/**
 8298 * Adds an item to the data source based on this remote record attributes.
 8299 * Note, validation is not performed in this method. You may call {@link validate} to perform the validation.
 8300 * After the record is inserted to data source successfully, its {@link isNewRecord} property will be set false,
 8301 * and its {@link scenario} property will be set to be 'update'.
 8302 * @param {Array} attributes list of attributes that need to be saved. Defaults to null,
 8303 * meaning all attributes that are loaded from DS will be saved.
 8304 * @param {Function} callback The callback that will be executed after the insert succeeds
 8305 * @returns {Mixed} The data source request
 8306 * @throws {Yii.CException} if the record is not new
 8307 */
 8308Yii.CAsyncRecord.prototype.create = function (attributes, callback) {
 8309		var builder, table, command, primaryKey, i, pk, self = this, func, postData;
 8310		if (attributes === undefined) {
 8311			attributes = null;
 8312		}
 8313		if(!this.getIsNewRecord()) {
 8314			throw new Yii.CDbException(Yii.t('yii','The remote record cannot be created because it is not new.'));
 8315		}
 8316		if(this.beforeSave()) {
 8317			Yii.trace(this.getClassName()+'.create()','system.ds.CAsyncRecord');
 8318			func = function (data, dataSource) {
 8319				var model;
 8320				model = self.populateRecord(data);
 8321				model.afterSave();
 8322				model.setIsNewRecord(false);
 8323				model.setScenario('update');
 8324				callback(model, dataSource);
 8325			};
 8326			if (this.wrapData === true) {
 8327				postData = {};
 8328				postData[this.getClassName()] = this.getAttributes(attributes);
 8329			}
 8330			else if (this.wrapData) {
 8331				postData = {};
 8332				postData[this.wrapData] = this.getAttributes(attributes);
 8333			}
 8334			else {
 8335				postData = this.getAttributes(attributes);
 8336			}
 8337			return this.getDataSource().create(postData, func);
 8338		}
 8339		return false;
 8340	};
 8341/**
 8342 * Updates the row represented by this remote record.
 8343 * All loaded attributes will be saved to the database.
 8344 * Note, validation is not performed in this method. You may call {@link validate} to perform the validation.
 8345 * @param {Array} attributes list of attributes that need to be saved. Defaults to null,
 8346 * meaning all attributes that are loaded from DB will be saved.
 8347 * @param {Function} callback The callback that will be executed after the update succeeds
 8348 * @returns {Mixed} The data source request
 8349 * @throws {Yii.CException} if the record is new
 8350 */
 8351Yii.CAsyncRecord.prototype.update = function (attributes, callback) {
 8352		var self = this, func, postData;
 8353		if (attributes === undefined) {
 8354			attributes = null;
 8355		}
 8356		if(this.getIsNewRecord()) {
 8357			throw new Yii.CDbException(Yii.t('yii','The remote record cannot be updated because it is new.'));
 8358		}
 8359		
 8360		if(this.beforeSave()) {
 8361			Yii.trace(this.getClassName()+'.update()','system.ds.CAsyncRecord');
 8362			func = function (data, dataSource) {
 8363				var model;
 8364				model = self.populateRecord(data);
 8365				model.afterSave();
 8366				model.setIsNewRecord(false);
 8367				model.setScenario('update');
 8368				callback(model, dataSource);
 8369			};
 8370			if (this.wrapData === true) {
 8371				postData = {};
 8372				postData[this.getClassName()] = this.getAttributes(attributes);
 8373			}
 8374			else if (this.wrapData) {
 8375				postData = {};
 8376				postData[this.wrapData] = this.getAttributes(attributes);
 8377			}
 8378			else {
 8379				postData = this.getAttributes(attributes);
 8380			}
 8381			
 8382			return this.getDataSource().update(postData, func);
 8383		}
 8384		else {
 8385			return false;
 8386		}
 8387	};
 8388/**
 8389 * Saves a selected list of attributes.
 8390 * Unlike {@link save}, this method only saves the specified attributes
 8391 * of an existing row dataset and does NOT call either {@link beforeSave} or {@link afterSave}.
 8392 * Also note that this method does neither attribute filtering nor validation.
 8393 * So do not use this method with untrusted data (such as user posted data).
 8394 * @param {Array} attributes attributes to be updated. Each element represents an attribute name
 8395 * or an attribute value indexed by its name. If the latter, the record's
 8396 * attribute will be changed accordingly before saving.
 8397 * @param {Function} callback The callback that will be executed after the insert succeeds
 8398 * @returns {Mixed} The data source request
 8399 * @throws {Yii.CException} if the record is new or any database error
 8400 */
 8401Yii.CAsyncRecord.prototype.saveAttributes = function (attributes, callback) {
 8402		var values, name, value;
 8403		if(!this.getIsNewRecord()) {
 8404			Yii.trace(this.getClassName()+'.saveAttributes()','system.ds.CAsyncRecord');
 8405			values={};
 8406			for (name in attributes) {
 8407				if (attributes.hasOwnProperty(name)) {
 8408					value = attributes[name];
 8409					if((typeof(name) === 'number' && (name % 1 ? false : true))) {
 8410						values[value]=this[value];
 8411					}
 8412					else {
 8413						values[name]=this[name]=value;
 8414					}
 8415				}
 8416			}
 8417			Yii.trace(this.getClassName()+'.update()','system.ds.CAsyncRecord');
 8418			return this.getDataSource().update(values, callback);
 8419		}
 8420		else {
 8421			throw new Yii.CDbException(Yii.t('yii','The active record cannot be updated because it is new.'));
 8422		}
 8423	};
 8424/**
 8425 * Saves the current record.
 8426 * 
 8427 * The record is created if its {@link isNewRecord}
 8428 * property is true (usually the case when the record is created using the 'new'
 8429 * operator). Otherwise, it will be used to update the corresponding item in the data source
 8430 * (usually the case if the record is obtained using one of those 'find' methods.)
 8431 * 
 8432 * Validation will be performed before saving the record. If the validation fails,
 8433 * the record will not be saved. You can call {@link getErrors()} to retrieve the
 8434 * validation errors.
 8435 * 
 8436 * If the record is saved via insertion, its {@link isNewRecord} property will be
 8437 * set false, and its {@link scenario} property will be set to be 'update'.
 8438 * And if its primary key is auto-incremental and is not set before insertion,
 8439 * the primary key will be populated with the automatically generated key value.
 8440 * @param {Function} callback The callback function that will be executed after the save
 8441 * @param {Boolean} runValidation whether to perform validation before saving the record.
 8442 * If the validation fails, the record will not be saved to database.
 8443 * @param {Array} attributes list of attributes that need to be saved. Defaults to null,
 8444 * meaning all attributes that are loaded from DB will be saved.
 8445 * @returns {Mixed} the response from the data source
 8446 */
 8447Yii.CAsyncRecord.prototype.save = function (callback, runValidation, attributes) {
 8448		if (runValidation === undefined) {
 8449			runValidation = true;
 8450		}
 8451		if (attributes === undefined) {
 8452			attributes = null;
 8453		}
 8454		if(!runValidation || this.validate(attributes)) {
 8455			
 8456			return this.getIsNewRecord() ? this.create(attributes, callback) : this.update(attributes, callback);
 8457		}
 8458		else {
 8459			return false;
 8460		}
 8461	};
 8462	
 8463/**
 8464 * Creates a remote record with the given attributes.
 8465 * This method is internally used by the find methods.
 8466 * @param {Array} attributes attribute values (column name=>column value)
 8467 * @param {Boolean} callAfterFind whether to call {@link afterFind} after the record is populated.
 8468 * This parameter is added in version 1.0.3.
 8469 * @returns {Yii.CAsyncRecord} the newly created active record. The class of the object is the same as the model class.
 8470 * Null is returned if the input data is false.
 8471 */
 8472Yii.CAsyncRecord.prototype.populateRecord = function (attributes, callAfterFind) {
 8473		var record, md, name, value;
 8474		if (callAfterFind === undefined) {
 8475			callAfterFind = true;
 8476		}
 8477		if(attributes!==false) {
 8478			record=this.instantiate(attributes);
 8479			record.setIsNewRecord(false);
 8480			record.setScenario('update');
 8481			record.init();
 8482			
 8483			for (name in attributes) {
 8484				if (attributes.hasOwnProperty(name)) {
 8485					value = attributes[name];
 8486					if(record[name] !== undefined) {
 8487						record[name]=value;
 8488					}
 8489					else if(record._attributes[name] !== undefined) {
 8490						record._attributes[name]=value;
 8491					}
 8492				}
 8493			}
 8494			record._pk=record.getPrimaryKey();
 8495			record.attachBehaviors(record.behaviors());
 8496			if(callAfterFind) {
 8497				record.afterFind();
 8498			}
 8499			return record;
 8500		}
 8501		else {
 8502			return null;
 8503		}
 8504	};
 8505/**
 8506 * Creates a list of active records based on the input data.
 8507 * This method is internally used by the find methods.
 8508 * @param {Array} data list of attribute values for the active records.
 8509 * @param {Boolean} callAfterFind whether to call {@link afterFind} after each record is populated.
 8510 * This parameter is added in version 1.0.3.
 8511 * @param {String} index the name of the attribute whose value will be used as indexes of the query result array.
 8512 * If null, it means the array will be indexed by zero-based integers.
 8513 * @returns {Array} list of active records.
 8514 */
 8515Yii.CAsyncRecord.prototype.populateRecords = function (data, callAfterFind, index) {
 8516		var records, i, limit, record, attributes;
 8517		if (callAfterFind === undefined) {
 8518			callAfterFind = true;
 8519		}
 8520		if (index === undefined) {
 8521			index = null;
 8522		}
 8523		records=[];
 8524		limit = data.length;
 8525		for (i = 0; i < limit; i++) {
 8526			attributes = data[i];
 8527			if((record=this.populateRecord(attributes,callAfterFind))!==null) {
 8528				if(index===null) {
 8529					records.push(record);
 8530				}
 8531				else {
 8532					records[record[index]]=record;
 8533				}
 8534			}
 8535		}
 8536		return records;
 8537	};
 8538/**
 8539 * Creates an active record instance.
 8540 * This method is called by {@link populateRecord} and {@link populateRecords}.
 8541 * You may override this method if the instance being created
 8542 * depends the attributes that are to be populated to the record.
 8543 * For example, by creating a record based on the value of a column,
 8544 * you may implement the so-called single-table inheritance mapping.
 8545 * @param {Object} attributes list of attribute values for the active records.
 8546 * @returns {Yii.CAsyncRecord} the active record
 8547 * @since 1.0.2
 8548 */
 8549Yii.CAsyncRecord.prototype.instantiate = function (attributes) {
 8550		var classVar, model;
 8551		classVar=this.getClassName();
 8552		model=new Yii[classVar]();
 8553		return model;
 8554	};
 8555
 8556/**
 8557 * Returns the primary key value.
 8558 * @returns {Mixed} the primary key value. An array (column name=>column value) is returned if the primary key is composite.
 8559 * If primary key is not defined, null will be returned.
 8560 */
 8561Yii.CAsyncRecord.prototype.getPrimaryKey = function () {
 8562		var table, values,name,pk,self = this;
 8563		pk = this.primaryKey();
 8564		
 8565		if(typeof(pk) === 'string') {
 8566			
 8567			return this.get(pk);
 8568		}
 8569		else if(Object.prototype.toString.call(pk) === '[object Array]') {
 8570			values={};
 8571			Yii.forEach(pk, function (i, name) {
 8572				values[name] = self.get(name);
 8573			});
 8574			return values;
 8575		}
 8576		else {
 8577			return null;
 8578		}
 8579	};
 8580/**
 8581 * Sets the primary key value.
 8582 * After calling this method, the old primary key value can be obtained from {@link oldPrimaryKey}.
 8583 * @param {Mixed} value the new primary key value. If the primary key is composite, the new value
 8584 * should be provided as an array (column name=>column value).
 8585 * @since 1.1.0
 8586 */
 8587Yii.CAsyncRecord.prototype.setPrimaryKey = function (value) {
 8588		var table, values,name,pk,self = this;
 8589		pk = this.primaryKey();
 8590		if(typeof(pk) === 'string') {
 8591			this.set(pk, value);
 8592		}
 8593		else if(Object.prototype.toString.call(pk) === '[object Array]') {
 8594			values={};
 8595			Yii.forEach(pk, function (i, name) {
 8596				self[name] = value[i];
 8597			});
 8598			
 8599		}
 8600		
 8601	};
 8602/**
 8603 * Performs a query, this is mainly used internally by the find / findAll methods
 8604 * @param {Function} callback The callback function to execute when data arrives
 8605 * @param {Object} criteria The criteria that will be sent to the server
 8606 * @param {Boolean} all whether to return all data or not
 8607 */
 8608Yii.CAsyncRecord.prototype.query = function (callback, criteria, all) {
 8609	var command, finder, func, self = this;
 8610	if (all === undefined) {
 8611		all = false;
 8612	}
 8613    this.beforeFind();
 8614    func = function(data, dataSource) {
 8615    	if (all) {
 8616    		return callback(self.populateRecords(data, true), dataSource);
 8617    	}
 8618    	else {
 8619    		return callback(self.populateRecord(data.shift(), true), dataSource);
 8620    	}
 8621    };
 8622    return this.getDataSource().search(criteria,func);
 8623};
 8624
 8625
 8626/**
 8627 * Finds a single remote record with the specified condition.
 8628 * @param {Function} callback The callback function that will recieve the results
 8629 * @param {Mixed} criteria query criteria.
 8630 * @returns {Yii.CAsyncRecord} the record found. Null if no record is found.
 8631 */
 8632Yii.CAsyncRecord.prototype.find = function (callback, criteria) {
 8633		
 8634		Yii.trace(this.getClassName()+'.find()','system.ds.CAsyncRecord');
 8635		
 8636		return this.query(callback, criteria);
 8637	};
 8638/**
 8639 * Finds all remote records satisfying the specified condition.
 8640 * See {@link find()} for detailed explanation about $condition and $params.
 8641 * @param {Function} callback The callback function that will recieve the results
 8642 * @param {Mixed} criteria query criteria.
 8643 * @returns {Array} list of active records satisfying the specified condition. An empty array is returned if none is found.
 8644 */
 8645Yii.CAsyncRecord.prototype.findAll = function (callback, criteria) {
 8646		Yii.trace(this.getClassName()+'.findAll()','system.ds.CAsyncRecord');
 8647		return this.query(callback, criteria,true);
 8648		
 8649	};
 8650/**
 8651 * Finds a remote active record with the specified primary key.
 8652 * See {@link find()} for detailed explanation about $condition and $params.
 8653 * @param {Function} callback The callback function that will recieve the results
 8654 * @param {Mixed} pk primary key value(s). Use array for multiple primary keys. For composite key, each key value must be an array (column name=>column value).
 8655 * @returns {Yii.CAsyncRecord} the record found. Null if none is found.
 8656 */
 8657Yii.CAsyncRecord.prototype.findByPk = function (callback, pk, criteria) {
 8658		var postData;
 8659		if (criteria === undefined) {
 8660			criteria = {};
 8661		}
 8662		criteria[this.primaryKey()] = pk;
 8663		if (this.wrapData === true) {
 8664			postData = {};
 8665			postData[this.getClassName()] = criteria;
 8666		}
 8667		else if (this.wrapData) {
 8668			postData = {};
 8669			postData[this.wrapData] = criteria;
 8670		}
 8671		else {
 8672			postData = criteria;
 8673		}
 8674		Yii.trace(this.getClassName()+'.findByPk()','system.ds.CAsyncRecord');
 8675		
 8676		
 8677		return this.query(callback, postData);
 8678	};
 8679/**
 8680 * Finds all active records with the specified primary keys.
 8681 * See {@link find()} for detailed explanation about $condition and $params.
 8682 * @param {Function} callback The callback function that will recieve the results
 8683 * @param {Mixed} pk primary key value(s). Use array for multiple primary keys. For composite key, each key value must be an array (column name=>column value).
 8684 * @param {Mixed} condition query condition or criteria.
 8685 * @param {Object} params parameters to be bound to an SQL statement.
 8686 * @returns {Array} the records found. An empty array is returned if none is found.
 8687 */
 8688Yii.CAsyncRecord.prototype.findAllByPk = function (callback, pk, criteria) {
 8689		var postData;
 8690		if (criteria === undefined) {
 8691			criteria = {};
 8692		}
 8693		criteria[this.primaryKey()] = pk;
 8694		if (this.wrapData === true) {
 8695			postData = {};
 8696			postData[this.getClassName()] = criteria;
 8697		}
 8698		else if (this.wrapData) {
 8699			postData = {};
 8700			postData[this.wrapData] = criteria;
 8701		}
 8702		else {
 8703			postData = criteria;
 8704		}
 8705		Yii.trace(this.getClassName()+'.findAllByPk()','system.ds.CAsyncRecord');
 8706		return this.query(callback, postData,true);
 8707	};
 8708/**
 8709 * Finds a single active record that has the specified attribute values.
 8710 * See {@link find()} for detailed explanation about $condition and $params.
 8711 * @param {Function} callback The callback function that will recieve the results
 8712 * @param {Object} attributes list of attribute values (indexed by attribute names) that the active records should match.
 8713 * Since version 1.0.8, an attribute value can be an array which will be used to generate an IN condition.
 8714 * @returns {Yii.CAsyncRecord} the record found. Null if none is found.
 8715 */
 8716Yii.CAsyncRecord.prototype.findByAttributes = function (callback, attributes) {
 8717		var postData;
 8718		Yii.trace(this.getClassName()+'.findByAttributes()','system.ds.CAsyncRecord');
 8719		
 8720		if (this.wrapData === true) {
 8721			postData = {};
 8722			postData[this.getClassName()] = attributes;
 8723		}
 8724		else if (this.wrapData) {
 8725			postData = {};
 8726			postData[this.wrapData] = attributes;
 8727		}
 8728		else {
 8729			postData = attributes;
 8730		}
 8731		return this.query(callback, postData);
 8732	};
 8733/**
 8734 * Finds all active records that have the specified attribute values.
 8735 * See {@link find()} for detailed explanation about $condition and $params.
 8736 * @param {Function} callback The callback function that will recieve the results
 8737 * @param {Array} attributes list of attribute values (indexed by attribute names) that the active records should match.
 8738 * Since version 1.0.8, an attribute value can be an array which will be used to generate an IN condition.
 8739 * @returns {Array} the records found. An empty array is returned if none is found.
 8740 */
 8741Yii.CAsyncRecord.prototype.findAllByAttributes = function (callback, attributes) {
 8742		var postData;
 8743		Yii.trace(this.getClassName()+'.findAllByAttributes()','system.ds.CAsyncRecord');
 8744		if (this.wrapData === true) {
 8745			postData = {};
 8746			postData[this.getClassName()] = attributes;
 8747		}
 8748		else if (this.wrapData) {
 8749			postData = {};
 8750			postData[this.wrapData] = attributes;
 8751		}
 8752		else {
 8753			postData = attributes;
 8754		}
 8755		return this.query(callback, postData, true);
 8756	};/*global Yii, php, $, jQuery, alert, clearInterval, clearTimeout, document, event, frames, history, Image, location, name, navigator, Option, parent, screen, setInterval, setTimeout, window, XMLHttpRequest */
 8757/**
 8758 * CAsyncRecordBehavior is the base class for behaviors that can be attached to {@link CAsyncRecord}.
 8759 * Compared with {@link CModelBehavior}, CAsyncRecordBehavior attaches to more events
 8760 * that are only defined by {@link CAsyncRecord}.
 8761 * 
 8762 * @package system.ds
 8763 * @since 1.0.2
 8764 * @author Charles Pick
 8765 * @class
 8766 * @extends Yii.CModelBehavior
 8767 */
 8768Yii.CAsyncRecordBehavior = function CAsyncRecordBehavior () {
 8769};
 8770Yii.CAsyncRecordBehavior.prototype = new Yii.CModelBehavior();
 8771Yii.CAsyncRecordBehavior.prototype.constructor =  Yii.CAsyncRecordBehavior;
 8772/**
 8773 * Declares events and the corresponding event handler methods.
 8774 * If you override this method, make sure you merge the parent result to the return value.
 8775 * @returns {Array} events (array keys) and the corresponding event handler methods (array values).
 8776 * @see CBehavior::events
 8777 */
 8778Yii.CAsyncRecordBehavior.prototype.events = function () {
 8779		return php.array_merge(parent.events(), {
 8780			'onBeforeSave':'beforeSave',
 8781			'onAfterSave':'afterSave',
 8782			'onBeforeDelete':'beforeDelete',
 8783			'onAfterDelete':'afterDelete',
 8784			'onBeforeFind':'beforeFind',
 8785			'onAfterFind':'afterFind'
 8786		});
 8787	};
 8788/**
 8789 * Responds to {@link CAsyncRecord::onBeforeSave} event.
 8790 * Overrides this method if you want to handle the corresponding event of the {@link CBehavior::owner owner}.
 8791 * You may set {@link CModelEvent::isValid} to be false to quit the saving process.
 8792 * @param {Yii.CModelEvent} event event parameter
 8793 */
 8794Yii.CAsyncRecordBehavior.prototype.beforeSave = function (event) {
 8795	};
 8796/**
 8797 * Responds to {@link CAsyncRecord::onAfterSave} event.
 8798 * Overrides this method if you want to handle the corresponding event of the {@link CBehavior::owner owner}.
 8799 * @param {Yii.CModelEvent} event event parameter
 8800 */
 8801Yii.CAsyncRecordBehavior.prototype.afterSave = function (event) {
 8802	};
 8803/**
 8804 * Responds to {@link CAsyncRecord::onBeforeDelete} event.
 8805 * Overrides this method if you want to handle the corresponding event of the {@link CBehavior::owner owner}.
 8806 * You may set {@link CModelEvent::isValid} to be false to quit the deletion process.
 8807 * @param {Yii.CEvent} event event parameter
 8808 */
 8809Yii.CAsyncRecordBehavior.prototype.beforeDelete = function (event) {
 8810	};
 8811/**
 8812 * Responds to {@link CAsyncRecord::onAfterDelete} event.
 8813 * Overrides this method if you want to handle the corresponding event of the {@link CBehavior::owner owner}.
 8814 * @param {Yii.CEvent} event event parameter
 8815 */
 8816Yii.CAsyncRecordBehavior.prototype.afterDelete = function (event) {
 8817	};
 8818/**
 8819 * Responds to {@link CAsyncRecord::onBeforeFind} event.
 8820 * Overrides this method if you want to handle the corresponding event of the {@link CBehavior::owner owner}.
 8821 * @param {Yii.CEvent} event event parameter
 8822 * @since 1.0.9
 8823 */
 8824Yii.CAsyncRecordBehavior.prototype.beforeFind = function (event) {
 8825	};
 8826/**
 8827 * Responds to {@link CAsyncRecord::onAfterFind} event.
 8828 * Overrides this method if you want to handle the corresponding event of the {@link CBehavior::owner owner}.
 8829 * @param {Yii.CEvent} event event parameter
 8830 */
 8831Yii.CAsyncRecordBehavior.prototype.afterFind = function (event) {
 8832	};/*global Yii, php, $, jQuery, alert, clearInterval, clearTimeout, document, event, frames, history, Image, location, name, navigator, Option, parent, screen, setInterval, setTimeout, window, XMLHttpRequest */
 8833/**
 8834 * A class for retrieving data from JSON data sources
 8835 * @package system.ds
 8836 * @since 1.0
 8837 * @author Charles Pick
 8838 * @class
 8839 * @extends Yii.CActiveDataSource
 8840 */
 8841Yii.CJSONDataSource = function CJSONDataSource (construct) {
 8842	if (construct !== false) {
 8843		this.ajaxOptions = {};
 8844		this.cacheDuration = null;
 8845		this.cacheDependency = null;
 8846		this.cacheKey = null;
 8847	}
 8848};
 8849Yii.CJSONDataSource.prototype = new Yii.CActiveDataSource();
 8850Yii.CJSONDataSource.prototype.constructor =  Yii.CJSONDataSource;
 8851Yii.CJSONDataSource.prototype.cacheDependency = null;
 8852Yii.CJSONDataSource.prototype.cacheDuration = null;
 8853Yii.CJSONDataSource.prototype._cacheKey = null;
 8854
 8855Yii.CJSONDataSource.prototype.cache = function (duration, dependency) {
 8856	this.cacheDuration = duration;
 8857	this.cacheDependency = dependency;
 8858};
 8859/**
 8860 * Gets the cache key
 8861 */
 8862Yii.CJSONDataSource.prototype.getCacheKey = function() {
 8863	if (this._cacheKey === null) {
 8864		this._cacheKey = Yii.CJSON.encode(this.ajaxOptions);
 8865	}
 8866	return this._cacheKey;
 8867};
 8868/**
 8869 * Whether to use JSONP or not, defaults to false meaning use AJAX for requests.
 8870 * @var Boolean
 8871 */
 8872Yii.CJSONDataSource.prototype.useJSONP = false;
 8873
 8874/**
 8875 * Options to pass to the ajax request.
 8876 * @var Object
 8877 */
 8878Yii.CJSONDataSource.prototype.ajaxOptions = {};
 8879/**
 8880 * A list of actions and their respective URLs. has the format:
 8881 * {
 8882 * 	'list': 'http://example.com/products/list.json',
 8883 * 	'search': ['product/search', {'format': 'json'}],
 8884 * 	'create': ['product/create', {'format': 'json'}],
 8885 * 	'update': ['product/update', {'format': 'json'}]
 8886 * }
 8887 * @see Yii.CHtml.normalizeUrl
 8888 * @var Object
 8889 */
 8890Yii.CJSONDataSource.prototype.routes = {};
 8891/**
 8892 * Makes the request and executes the callback when data arrives.
 8893 * @param {Function} callback The callback function to execute, this will recieve the
 8894 * data as its first parameter and the data source as its second parameter.
 8895 * @returns {jQuery.ajaxRequest} The ajax request
 8896 */
 8897Yii.CJSONDataSource.prototype.makeRequest = function (callback) {
 8898	var options, source = this, result;
 8899	if (this.ajaxOptions.type === undefined) {
 8900		this.ajaxOptions.type = "GET";
 8901	}
 8902	this.ajaxOptions.success = function (data) {
 8903		if (source.cacheDuration !== null && source.ajaxOptions.type.toLowerCase() === "get") {
 8904			Yii.app().getCache().set(source.getCacheKey(), data, source.cacheDuration);
 8905		}
 8906		callback(data, source);
 8907	};
 8908	if (source.ajaxOptions.type.toLowerCase() === "get" && source.cacheDuration !== null && (result = Yii.app().getCache().get(source.getCacheKey())) !== false) {
 8909		return callback(result, source); 
 8910	}
 8911	
 8912	return Yii.app().ajax.makeRequest(this.ajaxOptions);
 8913};
 8914
 8915/**
 8916 * Gets a list of items from the data source
 8917 * @param {Function} callback the callback function to execute, this will
 8918 * receive the response from the server as its first parameter and the data source
 8919 * as the second parameter
 8920 * @returns {jQuery.ajaxRequest} The ajax request
 8921 */
 8922Yii.CJSONDataSource.prototype.list = function (callback) {
 8923	
 8924	this.ajaxOptions.url = this.routes.list;
 8925	return this.makeRequest(callback);
 8926};
 8927
 8928/**
 8929 * Searches for items from the data source.
 8930 * @param {Object} criteria The search criteria, field:'search query'
 8931 * @param {Function} callback the callback function to execute, this will
 8932 * receive the response from the server as its first parameter and the data source
 8933 * as the second parameter
 8934 * @returns {jQuery.ajaxRequest} The ajax request
 8935 */
 8936Yii.CJSONDataSource.prototype.search = function (criteria, callback) {
 8937	this.ajaxOptions.data = criteria;
 8938	this.ajaxOptions.url = this.routes.search;
 8939	return this.makeRequest(callback);
 8940};
 8941
 8942/**
 8943 * Creates a new item.
 8944 * @param {Object} data The data to post to the server
 8945 * @param {Function} callback the callback function to execute, this will
 8946 * receive the response from the server as its first parameter and the data source
 8947 * as the second parameter
 8948 * @returns {jQuery.ajaxRequest} The ajax request
 8949 */
 8950Yii.CJSONDataSource.prototype.create = function (data, callback) {
 8951	this.ajaxOptions.data = data;
 8952	if (this.ajaxOptions.type === undefined || this.ajaxOptions.type.toLowerCase() === "get") {
 8953		this.ajaxOptions.type = "post";
 8954	}
 8955	this.ajaxOptions.url = this.routes.create;
 8956	return this.makeRequest(callback);
 8957};
 8958
 8959/**
 8960 * Updates an item
 8961 * @param {Object} data The data to post to the server
 8962 * @param {Function} callback the callback function to execute, this will
 8963 * receive the response from the server as its first parameter and the data source
 8964 * as the second parameter
 8965 * @returns {jQuery.ajaxRequest} The ajax request
 8966 */
 8967Yii.CJSONDataSource.prototype.update = function (data, callback) {
 8968	this.ajaxOptions.data = data;
 8969	if (this.ajaxOptions.type === undefined || this.ajaxOptions.type.toLowerCase() === "get") {
 8970		this.ajaxOptions.type = "post";
 8971	}
 8972	this.ajaxOptions.url = this.routes.update;
 8973	return this.makeRequest(callback);
 8974};
 8975
 8976/**
 8977 * Deletes an item
 8978 * @param {Object} data The data to post to the server
 8979 * @param {Function} callback the callback function to execute, this will
 8980 * receive the response from the server as its first parameter and the data source
 8981 * as the second parameter
 8982 * @returns {jQuery.ajaxRequest} The ajax request
 8983 */
 8984Yii.CJSONDataSource.prototype.remove = function (data, callback) {
 8985	this.ajaxOptions.data = data;
 8986	if (this.ajaxOptions.type === undefined || this.ajaxOptions.type.toLowerCase() === "get") {
 8987		this.ajaxOptions.type = "post";
 8988	}
 8989	this.ajaxOptions.url = this.routes.remove;
 8990	return this.makeRequest(callback);
 8991};
 8992
 8993/*global Yii, php, $, jQuery, alert, clearInterval, clearTimeout, document, event, frames, history, Image, location, name, navigator, Option, parent, screen, setInterval, setTimeout, window, XMLHttpRequest */
 8994/**
 8995 * CChoiceFormat is a helper that chooses an appropriate message based on the specified number value.
 8996 * The candidate messages are given as a string in the following format:
 8997 * <pre>
 8998 * 'expr1#message1|expr2#message2|expr3#message3'
 8999 * </pre>
 9000 * where each expression should be a valid PHP expression with 'n' as the only variable.
 9001 * For example, 'n==1' and 'n%10==2 && n>10' are both valid expressions.
 9002 * The variable 'n' will take the given number value, and if an expression evaluates true,
 9003 * the corresponding message will be returned.
 9004 * 
 9005 * For example, given the candidate messages 'n==1#one|n==2#two|n>2#others' and
 9006 * the number value 2, the resulting message will be 'two'.
 9007 * 
 9008 * For expressions like 'n==1', we can also use a shortcut '1'. So the above example
 9009 * candidate messages can be simplified as '1#one|2#two|n>2#others'.
 9010 * 
 9011 * In case the given number doesn't select any message, the last candidate message
 9012 * will be returned.
 9013 * 
 9014 * @originalAuthor Qiang Xue <qiang.xue@gmail.com>
 9015 * @version $Id: CChoiceFormat.php 2899 2011-01-20 21:10:03Z alexander.makarow $
 9016 * @package system.i18n
 9017 * @since 1.0.2
 9018 * @author Charles Pick
 9019 * @class
 9020 */
 9021Yii.CChoiceFormat = function CChoiceFormat () {
 9022};
 9023/**
 9024 * Formats a message according to the specified number value.
 9025 * @param {String} messages the candidate messages in the format of 'expr1#message1|expr2#message2|expr3#message3'.
 9026 * See {@link CChoiceFormat} for more details.
 9027 * @param {Mixed} number the number value
 9028 * @returns {String} the selected message
 9029 */
 9030Yii.CChoiceFormat.prototype.format = function (messages, number) {
 9031		var n, matches, i, expression, message, match;
 9032		matches = (messages + "|").match(/\s*([^#]*)\s*#([^\|]*)\|/g);
 9033		if (matches !== null) {
 9034			n = matches.length;
 9035		}
 9036		else {
 9037			return messages;
 9038		}
 9039		if(n===0) {
 9040			return messages;
 9041		}
 9042		for(i=0;i<n;++i) {
 9043			match = matches[i].match(/\s*([^#]*)\s*#([^\|]*)\|/);
 9044			expression=match[0];
 9045			message=match[1];
 9046			if(expression===String(Number(expression)))	{
 9047				if(expression==number) {
 9048					return message;
 9049				}
 9050			}
 9051			else if(this.evaluate(expression,number)) {
 9052				return message;
 9053		}
 9054		}
 9055		return message; // return the last choice
 9056	};
 9057/**
 9058 * Evaluates a PHP expression with the given number value.
 9059 * @param {String} expression the PHP expression
 9060 * @param {Mixed} n the number value
 9061 * @returns {Boolean} the expression result
 9062 */
 9063Yii.CChoiceFormat.prototype.evaluate = function (expression, n) {
 9064		return eval(expression);
 9065	};/*global Yii, php, $, jQuery, alert, clearInterval, clearTimeout, document, event, frames, history, Image, location, name, navigator, Option, parent, screen, setInterval, setTimeout, window, XMLHttpRequest */
 9066/**
 9067 * CDateFormatter provides date/time localization functionalities.
 9068 * 
 9069 * CDateFormatter allows you to format dates and times in a locale-sensitive manner.
 9070 * Patterns are interpreted in the locale that the CDateFormatter instance
 9071 * is associated with. For example, month names and weekday names may vary
 9072 * under different locales, which yields different formatting results.
 9073 * The patterns that CDateFormatter recognizes are as defined in
 9074 * {@link http://www.unicode.org/reports/tr35/#Date_Format_Patterns CLDR}.
 9075 * 
 9076 * CDateFormatter supports predefined patterns as well as customized ones:
 9077 * <ul>
 9078 * <li>The method {@link formatDateTime()} formats date or time or both using
 9079 *   predefined patterns which include 'full', 'long', 'medium' (default) and 'short'.</li>
 9080 * <li>The method {@link format()} formats datetime using the specified pattern.
 9081 *   See {@link http://www.unicode.org/reports/tr35/#Date_Format_Patterns} for
 9082 *   details about the recognized pattern characters.</li>
 9083 * </ul>
 9084 * 
 9085 * @originalAuthor Wei Zhuo <weizhuo[at]gmail[dot]com>
 9086 * @originalAuthor Qiang Xue <qiang.xue@gmail.com>
 9087 * @version $Id: CDateFormatter.php 2798 2011-01-01 19:29:03Z qiang.xue $
 9088 * @package system.i18n
 9089 * @since 1.0
 9090 * @author Charles Pick
 9091 * @class
 9092 * @extends Yii.CComponent
 9093 */
 9094Yii.CDateFormatter = function CDateFormatter (locale) {
 9095	if (locale !== false) {
 9096		this.construct(false);
 9097	}
 9098};
 9099Yii.CDateFormatter.prototype = new Yii.CComponent();
 9100Yii.CDateFormatter.prototype.constructor =  Yii.CDateFormatter;
 9101/**
 9102 * @var {Array} pattern characters mapping to the corresponding translator methods
 9103 */
 9104Yii.CDateFormatter.prototype._formatters = {'G':'formatEra','y':'formatYear','M':'formatMonth','L':'formatMonth','d':'formatDay','h':'formatHour12','H':'formatHour24','m':'formatMinutes','s':'formatSeconds','E':'formatDayInWeek','c':'formatDayInWeek','e':'formatDayInWeek','D':'formatDayInYear','F':'formatDayInMonth','w':'formatWeekInYear','W':'formatWeekInMonth','a':'formatPeriod','k':'formatHourInDay','K':'formatHourInPeriod','z':'formatTimeZone','Z':'formatTimeZone','v':'formatTimeZone'};
 9105Yii.CDateFormatter.prototype._locale = null;
 9106Yii.CDateFormatter.prototype._formats = [];
 9107/**
 9108 * Constructor.
 9109 * @param {Mixed} locale locale ID (string) or CLocale instance
 9110 */
 9111Yii.CDateFormatter.prototype.construct = function (locale) {
 9112		if(typeof(locale) === 'string') {
 9113			this._locale=Yii.CLocale.getInstance(locale);
 9114		}
 9115		else {
 9116			this._locale=locale;
 9117		}
 9118	};
 9119/**
 9120 * Formats a date according to a customized pattern.
 9121 * @param {String} pattern the pattern (See {@link http://www.unicode.org/reports/tr35/#Date_Format_Patterns})
 9122 * @param {Mixed} time UNIX timestamp or a string in strtotime format
 9123 * @returns {String} formatted date time.
 9124 */
 9125Yii.CDateFormatter.prototype.format = function (pattern, time) {
 9126		var date, tokens, i, token;
 9127		if(typeof(time) === 'string')
 9128		{
 9129			if(php.ctype_digit(time)) {
 9130				time=Number(time);
 9131			}
 9132			else {
 9133				time=php.strtotime(time);
 9134			}
 9135		}
 9136		date=Yii.CTimestamp.getdate(time,false,false);
 9137		tokens=this.parseFormat(pattern);
 9138		for (i in tokens) {
 9139			if (tokens.hasOwnProperty(i)) {
 9140				
 9141				if(Object.prototype.toString.call(tokens[i]) === '[object Array]')  {
 9142					// a callback: method name, sub-pattern
 9143					tokens[i]=this[tokens[i][0]](tokens[i][1],date);
 9144				}
 9145			}
 9146		}
 9147		return tokens.join('');
 9148	};
 9149/**
 9150 * Formats a date according to a predefined pattern.
 9151 * The predefined pattern is determined based on the date pattern width and time pattern width.
 9152 * @param {Mixed} timestamp UNIX timestamp or a string in strtotime format
 9153 * @param {String} dateWidth width of the date pattern. It can be 'full', 'long', 'medium' and 'short'.
 9154 * If null, it means the date portion will NOT appear in the formatting result
 9155 * @param {String} timeWidth width of the time pattern. It can be 'full', 'long', 'medium' and 'short'.
 9156 * If null, it means the time portion will NOT appear in the formatting result
 9157 * @returns {String} formatted date time.
 9158 */
 9159Yii.CDateFormatter.prototype.formatDateTime = function (timestamp, dateWidth, timeWidth) {
 9160		var date, time, dateTimePattern;
 9161		if (dateWidth === undefined) {
 9162			dateWidth = 'medium';
 9163		}
 9164		if (timeWidth === undefined) {
 9165			timeWidth = 'medium';
 9166		}
 9167		if(!php.empty(dateWidth)) {
 9168			date=this.format(this._locale.getDateFormat(dateWidth),timestamp);
 9169		}
 9170		if(!php.empty(timeWidth)) {
 9171			time=this.format(this._locale.getTimeFormat(timeWidth),timestamp);
 9172		}
 9173		if(date !== undefined && time !== undefined) {
 9174			dateTimePattern=this._locale.getDateTimeFormat();
 9175			return php.strtr(dateTimePattern,{'{0}':time,'{1}':date});
 9176		}
 9177		else if(date !== undefined) {
 9178			return date;
 9179		}
 9180		else if(time !== undefined) {
 9181			return time;
 9182		}
 9183	};
 9184/**
 9185 * Parses the datetime format pattern.
 9186 * @param {String} pattern the pattern to be parsed
 9187 * @returns {Array} tokenized parsing result
 9188 */
 9189Yii.CDateFormatter.prototype.parseFormat = function (pattern) {
 9190		var tokens, n, isLiteral, literal, i, c, j, p, _formatters;
 9191		
 9192		if(this._formats[pattern] !== undefined) {
 9193			return this._formats[pattern];
 9194		}
 9195		tokens=[];
 9196		n=php.strlen(pattern);
 9197		isLiteral=false;
 9198		literal='';
 9199		for(i=0;i<n;++i) {
 9200			c=pattern[i];
 9201			if(c==="'")	{
 9202				if(i<n-1 && pattern[i+1]==="'"){
 9203					tokens.push("'");
 9204					i++;
 9205				}
 9206				else if(isLiteral){
 9207					tokens.push(literal);
 9208					literal='';
 9209					isLiteral=false;
 9210				}
 9211				else{
 9212					isLiteral=true;
 9213					literal='';
 9214				}
 9215			}
 9216			else if(isLiteral) {
 9217				literal+=c;
 9218			}
 9219			else {
 9220				for(j=i+1;j<n;++j) {
 9221					if(pattern[j]!==c) {
 9222						break;
 9223					}
 9224				}
 9225				p=php.str_repeat(c,j-i);
 9226				if(this._formatters[c] !== undefined) {
 9227					tokens.push([this._formatters[c],p]);
 9228				}
 9229				else {
 9230					tokens.push(p);
 9231				}
 9232				i=j-1;
 9233			}
 9234		}
 9235		if(literal!=='') {
 9236			tokens.push(literal);
 9237		}
 9238		return (this._formats[pattern]=tokens);
 9239	};
 9240/**
 9241 * Get the year.
 9242 * "yy" will return the last two digits of year.
 9243 * "y...y" will pad the year with 0 in the front, e.g. "yyyyy" will generate "02008" for year 2008.
 9244 * @param {String} pattern a pattern.
 9245 * @param {Array} date result of {@link CTimestamp::getdate}.
 9246 * @returns {String} formatted year
 9247 */
 9248Yii.CDateFormatter.prototype.formatYear = function (pattern, date) {
 9249		var year;
 9250		year=date.year;
 9251		if(pattern==='yy') {
 9252			return php.str_pad(year%100,2,'0','STR_PAD_LEFT');
 9253		}
 9254		else {
 9255			return php.str_pad(year,php.strlen(pattern),'0','STR_PAD_LEFT');
 9256		}
 9257	};
 9258/**
 9259 * Get the month.
 9260 * "M" will return integer 1 through 12;
 9261 * "MM" will return two digits month number with necessary zero padding, e.g. 05;
 9262 * "MMM" will return the abrreviated month name, e.g. "Jan";
 9263 * "MMMM" will return the full month name, e.g. "January";
 9264 * "MMMMM" will return the narrow month name, e.g. "J";
 9265 * @param {String} pattern a pattern.
 9266 * @param {Array} date result of {@link CTimestamp::getdate}.
 9267 * @returns {String} month name
 9268 */
 9269Yii.CDateFormatter.prototype.formatMonth = function (pattern, date) {
 9270		var month;
 9271		month=date.mon;
 9272		switch(pattern)	{
 9273			case 'M':
 9274				return month;
 9275			case 'MM':
 9276				return php.str_pad(month,2,'0','STR_PAD_LEFT');
 9277			case 'MMM':
 9278				return this._locale.getMonthName(month,'abbreviated');
 9279			case 'MMMM':
 9280				return this._locale.getMonthName(month,'wide');
 9281			case 'MMMMM':
 9282				return this._locale.getMonthName(month,'narrow');
 9283			case 'L':
 9284				return month;
 9285			case 'LL':
 9286				return php.str_pad(month,2,'0','STR_PAD_LEFT');
 9287			case 'LLL':
 9288				return this._locale.getMonthName(month,'abbreviated', true);
 9289			case 'LLLL':
 9290				return this._locale.getMonthName(month,'wide', true);
 9291			case 'LLLLL':
 9292				return this._locale.getMonthName(month,'narrow', true);
 9293			default:
 9294				throw new Yii.CException(Yii.t('yii','The pattern for month must be "M", "MM", "MMM", "MMMM", "L", "LL", "LLL" or "LLLL".'));
 9295		}
 9296	};
 9297/**
 9298 * Get the day of the month.
 9299 * "d" for non-padding, "dd" will always return 2 digits day numbers, e.g. 05.
 9300 * @param {String} pattern a pattern.
 9301 * @param {Array} date result of {@link CTimestamp::getdate}.
 9302 * @returns {String} day of the month
 9303 */
 9304Yii.CDateFormatter.prototype.formatDay = function (pattern, date) {
 9305		var day;
 9306		day=date.mday;
 9307		if(pattern==='d') {
 9308			return day;
 9309		}
 9310		else if(pattern==='dd') {
 9311			return php.str_pad(day,2,'0','STR_PAD_LEFT');
 9312		}
 9313		else {
 9314			throw new Yii.CException(Yii.t('yii','The pattern for day of the month must be "d" or "dd".'));
 9315		}
 9316	};
 9317/**
 9318 * Get the day in the year, e.g. [1-366]
 9319 * @param {String} pattern a pattern.
 9320 * @param {Array} date result of {@link CTimestamp::getdate}.
 9321 * @returns {Integer} hours in AM/PM format.
 9322 */
 9323Yii.CDateFormatter.prototype.formatDayInYear = function (pattern, date) {
 9324		var day, n;
 9325		day=date.yday;
 9326		if((n=php.strlen(pattern))<=3) {
 9327			return php.str_pad(day,n,'0','STR_PAD_LEFT');
 9328		}
 9329		else {
 9330			throw new Yii.CException(Yii.t('yii','The pattern for day in year must be "D", "DD" or "DDD".'));
 9331		}
 9332	};
 9333/**
 9334 * Get day of week in the month, e.g. 2nd Wed in July.
 9335 * @param {String} pattern a pattern.
 9336 * @param {Array} date result of {@link CTimestamp::getdate}.
 9337 * @returns {Integer} day in month
 9338 * @see http://www.unicode.org/reports/tr35/#Date_Format_Patterns
 9339 */
 9340Yii.CDateFormatter.prototype.formatDayInMonth = function (pattern, date) {
 9341		if(pattern==='F') {
 9342			return Number((date.mday+6)/7);
 9343		}
 9344		else {
 9345			throw new Yii.CException(Yii.t('yii','The pattern for day in month must be "F".'));
 9346		}
 9347	};
 9348/**
 9349 * Get the day of the week.
 9350 * "E", "EE", "EEE" will return abbreviated week day name, e.g. "Tues";
 9351 * "EEEE" will return full week day name;
 9352 * "EEEEE" will return the narrow week day name, e.g. "T";
 9353 * @param {String} pattern a pattern.
 9354 * @param {Array} date result of {@link CTimestamp::getdate}.
 9355 * @returns {String} day of the week.
 9356 * @see http://www.unicode.org/reports/tr35/#Date_Format_Patterns
 9357 */
 9358Yii.CDateFormatter.prototype.formatDayInWeek = function (pattern, date) {
 9359		var day;
 9360		day=date.wday;
 9361		switch(pattern) {
 9362			case 'E':
 9363			case 'EE':
 9364			case 'EEE':
 9365			case 'eee':
 9366				return this._locale.getWeekDayName(day,'abbreviated');
 9367			case 'EEEE':
 9368			case 'eeee':
 9369				return this._locale.getWeekDayName(day,'wide');
 9370			case 'EEEEE':
 9371			case 'eeeee':
 9372				return this._locale.getWeekDayName(day,'narrow');
 9373			case 'e':
 9374			case 'ee':
 9375			case 'c':
 9376				return day ? day : 7;
 9377			case 'ccc':
 9378				return this._locale.getWeekDayName(day,'abbreviated',true);
 9379			case 'cccc':
 9380				return this._locale.getWeekDayName(day,'wide',true);
 9381			case 'ccccc':
 9382				return this._locale.getWeekDayName(day,'narrow',true);
 9383			default:
 9384				throw new Yii.CException(Yii.t('yii','The pattern for day of the week must be "E", "EE", "EEE", "EEEE", "EEEEE", "e", "ee", "eee", "eeee", "eeeee", "c", "cccc" or "ccccc".'));
 9385		}
 9386	};
 9387/**
 9388 * Get the AM/PM designator, 12 noon is PM, 12 midnight is AM.
 9389 * @param {String} pattern a pattern.
 9390 * @param {Array} date result of {@link CTimestamp::getdate}.
 9391 * @returns {String} AM or PM designator
 9392 */
 9393Yii.CDateFormatter.prototype.formatPeriod = function (pattern, date) {
 9394		if(pattern==='a') {
 9395			if(php.intval(date.hours/12)) {
 9396				return this._locale.getPMName();
 9397			}
 9398			else {
 9399				return this._locale.getAMName();
 9400			}
 9401		}
 9402		else {
 9403			throw new Yii.CException(Yii.t('yii','The pattern for AM/PM marker must be "a".'));
 9404		}
 9405	};
 9406/**
 9407 * Get the hours in 24 hour format, i.e. [0-23].
 9408 * "H" for non-padding, "HH" will always return 2 characters.
 9409 * @param {String} pattern a pattern.
 9410 * @param {Array} date result of {@link CTimestamp::getdate}.
 9411 * @returns {String} hours in 24 hour format.
 9412 */
 9413Yii.CDateFormatter.prototype.formatHour24 = function (pattern, date) {
 9414		var hour;
 9415		hour=date.hours;
 9416		if(pattern==='H') {
 9417			return hour;
 9418		}
 9419		else if(pattern==='HH') {
 9420			return php.str_pad(hour,2,'0','STR_PAD_LEFT');
 9421		}
 9422		else {
 9423			throw new Yii.CException(Yii.t('yii','The pattern for 24 hour format must be "H" or "HH".'));
 9424		}
 9425	};
 9426/**
 9427 * Get the hours in 12 hour format, i.e., [1-12]
 9428 * "h" for non-padding, "hh" will always return 2 characters.
 9429 * @param {String} pattern a pattern.
 9430 * @param {Array} date result of {@link CTimestamp::getdate}.
 9431 * @returns {String} hours in 12 hour format.
 9432 */
 9433Yii.CDateFormatter.prototype.formatHour12 = function (pattern, date) {
 9434		var hour;
 9435		hour=date.hours;
 9436		hour=(hour==12|hour===0)?12:(hour)%12;
 9437		if(pattern==='h') {
 9438			return hour;
 9439		}
 9440		else if(pattern==='hh') {
 9441			return php.str_pad(hour,2,'0','STR_PAD_LEFT');
 9442		}
 9443		else {
 9444			throw new Yii.CException(Yii.t('yii','The pattern for 12 hour format must be "h" or "hh".'));
 9445		}
 9446	};
 9447/**
 9448 * Get the hours [1-24].
 9449 * 'k' for non-padding, and 'kk' with 2 characters padding.
 9450 * @param {String} pattern a pattern.
 9451 * @param {Array} date result of {@link CTimestamp::getdate}.
 9452 * @returns {Integer} hours [1-24]
 9453 */
 9454Yii.CDateFormatter.prototype.formatHourInDay = function (pattern, date) {
 9455		var hour;
 9456		hour=date.hours==0?24:date.hours;
 9457		if(pattern==='k') {
 9458			return hour;
 9459		}
 9460		else if(pattern==='kk') {
 9461			return php.str_pad(hour,2,'0','STR_PAD_LEFT');
 9462		}
 9463		else {
 9464			throw new Yii.CException(Yii.t('yii','The pattern for hour in day must be "k" or "kk".'));
 9465		}
 9466	};
 9467/**
 9468 * Get the hours in AM/PM format, e.g [0-11]
 9469 * "K" for non-padding, "KK" will always return 2 characters.
 9470 * @param {String} pattern a pattern.
 9471 * @param {Array} date result of {@link CTimestamp::getdate}.
 9472 * @returns {Integer} hours in AM/PM format.
 9473 */
 9474Yii.CDateFormatter.prototype.formatHourInPeriod = function (pattern, date) {
 9475		var hour;
 9476		hour=date.hours%12;
 9477		if(pattern==='K') {
 9478			return hour;
 9479		}
 9480		else if(pattern==='KK') {
 9481			return php.str_pad(hour,2,'0','STR_PAD_LEFT');
 9482		}
 9483		else {
 9484			throw new Yii.CException(Yii.t('yii','The pattern for hour in AM/PM must be "K" or "KK".'));
 9485		}
 9486	};
 9487/**
 9488 * Get the minutes.
 9489 * "m" for non-padding, "mm" will always return 2 characters.
 9490 * @param {String} pattern a pattern.
 9491 * @param {Array} date result of {@link CTimestamp::getdate}.
 9492 * @returns {String} minutes.
 9493 */
 9494Yii.CDateFormatter.prototype.formatMinutes = function (pattern, date) {
 9495		var minutes;
 9496		minutes=date.minutes;
 9497		if(pattern==='m') {
 9498			return minutes;
 9499		}
 9500		else if(pattern==='mm') {
 9501			return php.str_pad(minutes,2,'0','STR_PAD_LEFT');
 9502		}
 9503		else {
 9504			throw new Yii.CException(Yii.t('yii','The pattern for minutes must be "m" or "mm".'));
 9505		}
 9506	};
 9507/**
 9508 * Get the seconds.
 9509 * "s" for non-padding, "ss" will always return 2 characters.
 9510 * @param {String} pattern a pattern.
 9511 * @param {Array} date result of {@link CTimestamp::getdate}.
 9512 * @returns {String} seconds
 9513 */
 9514Yii.CDateFormatter.prototype.formatSeconds = function (pattern, date) {
 9515		var seconds;
 9516		seconds=date.seconds;
 9517		if(pattern==='s') {
 9518			return seconds;
 9519		}
 9520		else if(pattern==='ss') {
 9521			return php.str_pad(seconds,2,'0','STR_PAD_LEFT');
 9522		}
 9523		else {
 9524			throw new Yii.CException(Yii.t('yii','The pattern for seconds must be "s" or "ss".'));
 9525		}
 9526	};
 9527/**
 9528 * Get the week in the year.
 9529 * @param {String} pattern a pattern.
 9530 * @param {Array} date result of {@link CTimestamp::getdate}.
 9531 * @returns {Integer} week in year
 9532 */
 9533Yii.CDateFormatter.prototype.formatWeekInYear = function (pattern, date) {
 9534		if(pattern==='w') {
 9535			return php.date('W',php.mktime(0,0,0,date.mon,date.mday,date.year));
 9536		}
 9537		else {
 9538			throw new Yii.CException(Yii.t('yii','The pattern for week in year must be "w".'));
 9539		}
 9540	};
 9541/**
 9542 * Get week in the month.
 9543 * @param {Array} pattern result of {@link CTimestamp::getdate}.
 9544 * @param {String} date a pattern.
 9545 * @returns {Integer} week in month
 9546 */
 9547Yii.CDateFormatter.prototype.formatWeekInMonth = function (pattern, date) {
 9548		if(pattern==='W') {
 9549			return php.date('W',php.mktime(0,0,0,date.mon, date.mday,date.year))-php.date('W', php.mktime(0,0,0,date.mon,1,date.year))+1;
 9550		}
 9551		else {
 9552			throw new Yii.CException(Yii.t('yii','The pattern for week in month must be "W".'));
 9553		}
 9554	};
 9555/**
 9556 * Get the timezone of the server machine.
 9557 * @param {String} pattern a pattern.
 9558 * @param {Array} date result of {@link CTimestamp::getdate}.
 9559 * @returns {String} time zone
 9560 * @todo How to get the timezone for a different region?
 9561 */
 9562Yii.CDateFormatter.prototype.formatTimeZone = function (pattern, date) {
 9563		if(pattern[0]==='z' || pattern[0]==='v') {
 9564			return php.date('T', php.mktime(date.hours, date.minutes, date.seconds, date.mon, date.mday, date.year));
 9565		}
 9566		else if(pattern[0]==='Z') {
 9567			return php.date('O', php.mktime(date.hours, date.minutes, date.seconds, date.mon, date.mday, date.year));
 9568		}
 9569		else {
 9570			throw new Yii.CException(Yii.t('yii','The pattern for time zone must be "z" or "v".'));
 9571		}
 9572	};
 9573/**
 9574 * Get the era. i.e. in gregorian, year > 0 is AD, else BC.
 9575 * @param {String} pattern a pattern.
 9576 * @param {Array} date result of {@link CTimestamp::getdate}.
 9577 * @returns {String} era
 9578 * @todo How to support multiple Eras?, e.g. Japanese.
 9579 */
 9580Yii.CDateFormatter.prototype.formatEra = function (pattern, date) {
 9581		var era;
 9582		era=date.year>0 ? 1 : 0;
 9583		switch(pattern)
 9584		{
 9585			case 'G':
 9586			case 'GG':
 9587			case 'GGG':
 9588				return this._locale.getEraName(era,'abbreviated');
 9589			case 'GGGG':
 9590				return this._locale.getEraName(era,'wide');
 9591			case 'GGGGG':
 9592				return this._locale.getEraName(era,'narrow');
 9593			default:
 9594				throw new Yii.CException(Yii.t('yii','The pattern for era must be "G", "GG", "GGG", "GGGG" or "GGGGG".'));
 9595		}
 9596	};/*global Yii, php, $, jQuery, alert, clearInterval, clearTimeout, document, event, frames, history, Image, location, name, navigator, Option, parent, screen, setInterval, setTimeout, window, XMLHttpRequest */
 9597/**
 9598 * CJavaScriptMessageSource represents a message source that stores translated messages in JavaScript scripts.
 9599 * 
 9600 * CJavaScriptMessageSource uses JavaScript files and arrays to keep message translations.
 9601 * <ul>
 9602 * <li>All translations are saved under the {@link basePath} directory.</li>
 9603 * <li>Translations in one language are kept as JavaScript files under an individual subdirectory
 9604 *   whose name is the same as the language ID. Each JavaScript file contains messages
 9605 *   belonging to the same category, and the file name is the same as the category name.</li>
 9606 * <li>Within a JavaScript file, an object of (source, translation) pairs is returned.
 9607 * For example:
 9608 * <pre>
 9609 * ({
 9610 *     'original message 1' : 'translated message 1',
 9611 *     'original message 2' : 'translated message 2'
 9612 * });
 9613 * </pre>
 9614 * </li>
 9615 * </ul>
 9616 * When {@link cachingDuration} is set as a positive number, message translations will be cached.
 9617 * 
 9618 * Starting from version 1.0.10, messages for an extension class (e.g. a widget, a module) can be specially managed and used.
 9619 * In particular, if a message belongs to an extension whose class name is Xyz, then the message category
 9620 * can be specified in the format of 'Xyz.categoryName'. And the corresponding message file
 9621 * is assumed to be 'BasePath/messages/LanguageID/categoryName.php', where 'BasePath' refers to
 9622 * the directory that contains the extension class file. When using Yii.t() to translate an extension message,
 9623 * the category name should be set as 'Xyz.categoryName'.
 9624 * 
 9625 * @originalAuthor Qiang Xue <qiang.xue@gmail.com>
 9626 * @version $Id: CJavaScriptMessageSource.php 2798 2011-01-01 19:29:03Z qiang.xue $
 9627 * @package system.i18n
 9628 * @since 1.0
 9629 * @author Charles Pick
 9630 * @class
 9631 * @extends Yii.CMessageSource
 9632 */
 9633Yii.CJavaScriptMessageSource = function CJavaScriptMessageSource () {
 9634};
 9635Yii.CJavaScriptMessageSource.prototype = new Yii.CMessageSource(false);
 9636Yii.CJavaScriptMessageSource.prototype.constructor =  Yii.CJavaScriptMessageSource;
 9637/**
 9638 * @const
 9639 */
 9640Yii.CJavaScriptMessageSource.CACHE_KEY_PREFIX = 'Yii.CJavaScriptMessageSource.';
 9641/**
 9642 * @var {Integer} the time in seconds that the messages can remain valid in cache.
 9643 * Defaults to 0, meaning the caching is disabled.
 9644 */
 9645Yii.CJavaScriptMessageSource.prototype.cachingDuration = 0;
 9646/**
 9647 * @var {String} the ID of the cache application component that is used to cache the messages.
 9648 * Defaults to 'cache' which refers to the primary cache application component.
 9649 * Set this property to false if you want to disable caching the messages.
 9650 * @since 1.0.10
 9651 */
 9652Yii.CJavaScriptMessageSource.prototype.cacheID = 'cache';
 9653/**
 9654 * @var {String} the base path for all translated messages. Defaults to null, meaning
 9655 * the "messages" subdirectory of the application directory (e.g. "protected/messages").
 9656 */
 9657Yii.CJavaScriptMessageSource.prototype.basePath = null;
 9658Yii.CJavaScriptMessageSource.prototype._files = {};
 9659/**
 9660 * Initializes the application component.
 9661 * This method overrides the parent implementation by preprocessing
 9662 * the user request data.
 9663 */
 9664Yii.CJavaScriptMessageSource.prototype.init = function () {
 9665		Yii.CMessageSource.prototype.init.call(this);
 9666		if(this.basePath===null) {
 9667			this.basePath=Yii.getPathOfAlias('application.messages');
 9668		}
 9669	};
 9670/**
 9671 * Determines the message file name based on the given category and language.
 9672 * If the category name contains a dot, it will be split into the module class name and the category name.
 9673 * In this case, the message file will be assumed to be located within the 'messages' subdirectory of
 9674 * the directory containing the module class file.
 9675 * Otherwise, the message file is assumed to be under the {@link basePath}.
 9676 * @param {String} category category name
 9677 * @param {String} language language ID
 9678 * @returns {String} the message file path
 9679 * @since 1.0.10
 9680 */
 9681Yii.CJavaScriptMessageSource.prototype.getMessageFile = function (category, language) {
 9682		var pos, moduleClass, moduleCategory, classVar;
 9683		if (this._files[category] === undefined) {
 9684			this._files[category] = {};
 9685		}
 9686		if(this._files[category][language] === undefined) {
 9687			
 9688			if((pos=php.strpos(category,'.'))!==false) {
 9689				moduleClass=category.slice(0, pos);
 9690				moduleCategory=category.slice(pos+1);
 9691				this._files[category][language]=Yii.getPathOfAlias(moduleClass + ".messages." + moduleCategory) + ".js";
 9692			}
 9693			else {
 9694				this._files[category][language]=this.basePath+'/'+language+'/'+category+'.js';
 9695			}
 9696		}
 9697		return this._files[category][language];
 9698	};
 9699/**
 9700 * Loads the message translation for the specified language and category.
 9701 * @param {String} category the message category
 9702 * @param {String} language the target language
 9703 * @returns {Object} the loaded messages
 9704 */
 9705Yii.CJavaScriptMessageSource.prototype.loadMessages = function (category, language) {
 9706		var messageFile, cache, key, data, messages, dependency;
 9707		messageFile=this.getMessageFile(category,language);
 9708		if(this.cachingDuration>0 && this.cacheID!==false && (cache=Yii.app().getComponent(this.cacheID))!==null) {
 9709			key=this.Yii.CACHE_KEY_PREFIX + messageFile;
 9710			if((data=cache.get(key))!==false) {
 9711				if (!data instanceof "Object") {
 9712					data = Yii.CJSON.decode(data);
 9713				}
 9714				return data;
 9715			}
 9716		}
 9717		try {
 9718			data = Yii.include(messageFile, false);
 9719			if (data === false) {
 9720				return {};
 9721			}
 9722			if (this.cachingDuration > 0 && this.cacheID !== false && (cache=Yii.app().getComponent(this.cacheID))!==null) {
 9723				key=this.Yii.CACHE_KEY_PREFIX + messageFile;
 9724				cache.set(key, data, this.cachingDuration);
 9725			}
 9726			return data;
 9727		}
 9728		catch (e) {
 9729			return {};
 9730		}
 9731	};/*global Yii, php, $, jQuery, alert, clearInterval, clearTimeout, document, event, frames, history, Image, location, name, navigator, Option, parent, screen, setInterval, setTimeout, window, XMLHttpRequest */
 9732/**
 9733 * CLocale represents the data relevant to a locale.
 9734 * 
 9735 * The data includes the number formatting information and date formatting information.
 9736 * 
 9737 * @originalAuthor Qiang Xue <qiang.xue@gmail.com>
 9738 * @version $Id: CLocale.php 2844 2011-01-13 01:29:55Z alexander.makarow $
 9739 * @package system.i18n
 9740 * @since 1.0
 9741 * @author Charles Pick
 9742 * @class
 9743 * @extends Yii.CComponent
 9744 */
 9745Yii.CLocale = function CLocale (id) {
 9746	
 9747	if (id !== false) {
 9748		this.construct(id);
 9749	}
 9750};
 9751Yii.CLocale._locales = null;
 9752Yii.CLocale.prototype = new Yii.CComponent();
 9753Yii.CLocale.prototype.constructor =  Yii.CLocale;
 9754/**
 9755 * @var {String} the directory that contains the locale data. If this property is not set,
 9756 * the locale data will be loaded from 'framework/i18n/data'.
 9757 * @since 1.1.0
 9758 */
 9759Yii.CLocale.prototype.dataPath = null;
 9760Yii.CLocale.prototype._id = null;
 9761Yii.CLocale.prototype._data = null;
 9762Yii.CLocale.prototype._dateFormatter = null;
 9763Yii.CLocale.prototype._numberFormatter = null;
 9764/**
 9765 * Returns the instance of the specified locale.
 9766 * Since the constructor of CLocale is protected, you can only use
 9767 * this method to obtain an instance of the specified locale.
 9768 * @param {String} id the locale ID (e.g. en_US)
 9769 * @returns {Yii.CLocale} the locale instance
 9770 */
 9771Yii.CLocale.getInstance = function (id) {
 9772		
 9773		if(this._locales === null) {
 9774			this._locales = {};
 9775		}
 9776		if(this._locales[id] !== undefined) {
 9777			return this._locales[id];
 9778		}
 9779		else {
 9780			return (this._locales[id]=new Yii.CLocale(id));
 9781		}
 9782	};
 9783/**
 9784 * @returns {Array} IDs of the locales which the framework can recognize
 9785 */
 9786Yii.CLocale.prototype.getLocaleIDs = function () {
 9787		var locales;
 9788		locales=["aa","aa_dj","aa_er","aa_et","af","af_na","af_za","ak","ak_gh","am","am_et","ar","ar_ae","ar_bh","ar_dz","ar_eg","ar_iq","ar_jo","ar_kw","ar_lb","ar_ly","ar_ma","ar_om","ar_qa","ar_sa","ar_sd","ar_sy","ar_tn","ar_ye","as","as_in","asa","asa_tz","az","az_arab","az_arab_ir","az_az","az_cyrl","az_cyrl_az","az_ir","az_latn","az_latn_az","be","be_by","bem","bem_zm","bez","bez_tz","bg","bg_bg","bm","bm_ml","bn","bn_bd","bn_in","bo","bo_cn","bo_in","br","br_fr","brx","brx_in","bs","bs_ba","byn","byn_er","ca","ca_es","cch","cch_ng","cgg","cgg_ug","chr","chr_us","cs","cs_cz","cy","cy_gb","da","da_dk","dav","dav_ke","de","de_at","de_be","de_ch","de_de","de_li","de_lu","dv","dv_mv","dz","dz_bt","ebu","ebu_ke","ee","ee_gh","ee_tg","el","el_cy","el_gr","el_polyton","en","en_as","en_au","en_be","en_bw","en_bz","en_ca","en_dsrt","en_dsrt_us","en_gb","en_gu","en_hk","en_ie","en_in","en_jm","en_mh","en_mp","en_mt","en_mu","en_na","en_nz","en_ph","en_pk","en_sg","en_shaw","en_tt","en_um","en_us","en_us_posix","en_vi","en_za","en_zw","en_zz","eo","es","es_419","es_ar","es_bo","es_cl","es_co","es_cr","es_do","es_ec","es_es","es_gq","es_gt","es_hn","es_mx","es_ni","es_pa","es_pe","es_pr","es_py","es_sv","es_us","es_uy","es_ve","et","et_ee","eu","eu_es","fa","fa_af","fa_ir","ff","ff_sn","fi","fi_fi","fil","fil_ph","fo","fo_fo","fr","fr_be","fr_bf","fr_bi","fr_bj","fr_bl","fr_ca","fr_cd","fr_cf","fr_cg","fr_ch","fr_ci","fr_cm","fr_dj","fr_fr","fr_ga","fr_gn","fr_gp","fr_gq","fr_km","fr_lu","fr_mc","fr_mf","fr_mg","fr_ml","fr_mq","fr_ne","fr_re","fr_rw","fr_sn","fr_td","fr_tg","fur","fur_it","ga","ga_ie","gaa","gaa_gh","gez","gez_er","gez_et","gl","gl_es","gsw","gsw_ch","gu","gu_in","guz","guz_ke","gv","gv_gb","ha","ha_arab","ha_arab_ng","ha_arab_sd","ha_gh","ha_latn","ha_latn_gh","ha_latn_ne","ha_latn_ng","ha_ne","ha_ng","ha_sd","haw","haw_us","he","he_il","hi","hi_in","hr","hr_hr","hu","hu_hu","hy","hy_am","ia","id","id_id","ig","ig_ng","ii","ii_cn","in","is","is_is","it","it_ch","it_it","iu","iw","ja","ja_jp","jmc","jmc_tz","ka","ka_ge","kab","kab_dz","kaj","kaj_ng","kam","kam_ke","kcg","kcg_ng","kde","kde_tz","kea","kea_cv","kfo","kfo_ci","khq","khq_ml","ki","ki_ke","kk","kk_cyrl","kk_cyrl_kz","kk_kz","kl","kl_gl","kln","kln_ke","km","km_kh","kn","kn_in","ko","ko_kr","kok","kok_in","kpe","kpe_gn","kpe_lr","ksb","ksb_tz","ksh","ksh_de","ku","ku_arab","ku_arab_iq","ku_arab_ir","ku_iq","ku_ir","ku_latn","ku_latn_sy","ku_latn_tr","ku_sy","ku_tr","kw","kw_gb","ky","ky_kg","lag","lag_tz","lg","lg_ug","ln","ln_cd","ln_cg","lo","lo_la","lt","lt_lt","luo","luo_ke","luy","luy_ke","lv","lv_lv","mas","mas_ke","mas_tz","mer","mer_ke","mfe","mfe_mu","mg","mg_mg","mi","mi_nz","mk","mk_mk","ml","ml_in","mn","mn_cn","mn_cyrl","mn_cyrl_mn","mn_mn","mn_mong","mn_mong_cn","mo","mr","mr_in","ms","ms_bn","ms_my","mt","mt_mt","my","my_mm","naq","naq_na","nb","nb_no","nd","nd_zw","nds","nds_de","ne","ne_in","ne_np","nl","nl_be","nl_nl","nn","nn_no","no","nr","nr_za","nso","nso_za","ny","ny_mw","nyn","nyn_ug","oc","oc_fr","om","om_et","om_ke","or","or_in","pa","pa_arab","pa_arab_pk","pa_guru","pa_guru_in","pa_in","pa_pk","pl","pl_pl","ps","ps_af","pt","pt_ao","pt_br","pt_gw","pt_mz","pt_pt","rm","rm_ch","ro","ro_md","ro_ro","rof","rof_tz","root","ru","ru_md","ru_ru","ru_ua","rw","rw_rw","rwk","rwk_tz","sa","sa_in","saq","saq_ke","se","se_fi","se_no","seh","seh_mz","ses","ses_ml","sg","sg_cf","sh","sh_ba","sh_cs","sh_yu","shi","shi_latn","shi_latn_ma","shi_ma","shi_tfng","shi_tfng_ma","si","si_lk","sid","sid_et","sk","sk_sk","sl","sl_si","sn","sn_zw","so","so_dj","so_et","so_ke","so_so","sq","sq_al","sr","sr_ba","sr_cs","sr_cyrl","sr_cyrl_ba","sr_cyrl_cs","sr_cyrl_me","sr_cyrl_rs","sr_cyrl_yu","sr_latn","sr_latn_ba","sr_latn_cs","sr_latn_me","sr_latn_rs","sr_latn_yu","sr_me","sr_rs","sr_yu","ss","ss_sz","ss_za","ssy","ssy_er","st","st_ls","st_za","sv","sv_fi","sv_se","sw","sw_ke","sw_tz","syr","syr_sy","ta","ta_in","ta_lk","te","te_in","teo","teo_ke","teo_ug","tg","tg_cyrl","tg_cyrl_tj","tg_tj","th","th_th","ti","ti_er","ti_et","tig","tig_er","tl","tl_ph","tn","tn_za","to","to_to","tr","tr_tr","trv","trv_tw","ts","ts_za","tt","tt_ru","tzm","tzm_latn","tzm_latn_ma","tzm_ma","ug","ug_arab","ug_arab_cn","ug_cn","uk","uk_ua","ur","ur_in","ur_pk","uz","uz_af","uz_arab","uz_arab_af","uz_cyrl","uz_cyrl_uz","uz_latn","uz_latn_uz","uz_uz","ve","ve_za","vi","vi_vn","vun","vun_tz","wal","wal_et","wo","wo_latn","wo_latn_sn","wo_sn","xh","xh_za","xog","xog_ug","yo","yo_ng","zh","zh_cn","zh_hans","zh_hans_cn","zh_hans_hk","zh_hans_mo","zh_hans_sg","zh_hant","zh_hant_hk","zh_hant_mo","zh_hant_tw","zh_hk","zh_mo","zh_sg","zh_tw","zu","zu_za"];
 9789			
 9790		return locales;
 9791	};
 9792/**
 9793 * Constructor.
 9794 * Since the constructor is protected, please use {@link getInstance}
 9795 * to obtain an instance of the specified locale.
 9796 * @param {String} id the locale ID (e.g. en_US)
 9797 */
 9798Yii.CLocale.prototype.construct = function (id) {
 9799		var dataPath, dataFile;
 9800		this._id=this.getCanonicalID(id);
 9801		dataPath=this.dataPath===null ? YII_PATH + '/i18n/data' : this.dataPath;
 9802		dataFile=dataPath+"/"+this._id+'.js';
 9803		this._data= Yii.include(dataFile,false);
 9804		
 9805	};
 9806/**
 9807 * Converts a locale ID to its canonical form.
 9808 * In canonical form, a locale ID consists of only underscores and lower-case letters.
 9809 * @param {String} id the locale ID to be converted
 9810 * @returns {String} the locale ID in canonical form
 9811 */
 9812Yii.CLocale.prototype.getCanonicalID = function (id) {
 9813		return php.str_replace('-','_',id).toLowerCase();
 9814	};
 9815/**
 9816 * @returns {String} the locale ID (in canonical form)
 9817 */
 9818Yii.CLocale.prototype.getId = function () {
 9819		return this._id;
 9820	};
 9821/**
 9822 * @returns {Yii.CNumberFormatter} the number formatter for this locale
 9823 */
 9824Yii.CLocale.prototype.getNumberFormatter = function () {
 9825		if(this._numberFormatter===null) {
 9826			this._numberFormatter=new Yii.CNumberFormatter(this);
 9827		}
 9828		return this._numberFormatter;
 9829	};
 9830/**
 9831 * @returns {Yii.CDateFormatter} the date formatter for this locale
 9832 */
 9833Yii.CLocale.prototype.getDateFormatter = function () {
 9834		if(this._dateFormatter===null) {
 9835			this._dateFormatter=new Yii.CDateFormatter(this);
 9836		}
 9837		return this._dateFormatter;
 9838	};
 9839/**
 9840 * @param {String} currency 3-letter ISO 4217 code. For example, the code "USD" represents the US Dollar and "EUR" represents the Euro currency.
 9841 * @returns {String} the localized currency symbol. Null if the symbol does not exist.
 9842 */
 9843Yii.CLocale.prototype.getCurrencySymbol = function (currency) {
 9844		return this._data.currencySymbols[currency] !== undefined ? this._data.currencySymbols[currency] : null;
 9845	};
 9846/**
 9847 * @param {String} name symbol name
 9848 * @returns {String} symbol
 9849 */
 9850Yii.CLocale.prototype.getNumberSymbol = function (name) {
 9851		return this._data.numberSymbols[name] !== undefined ? this._data.numberSymbols[name] : null;
 9852	};
 9853/**
 9854 * @returns {String} the decimal format
 9855 */
 9856Yii.CLocale.prototype.getDecimalFormat = function () {
 9857		return this._data.decimalFormat;
 9858	};
 9859/**
 9860 * @returns {String} the currency format
 9861 */
 9862Yii.CLocale.prototype.getCurrencyFormat = function () {
 9863		return this._data.currencyFormat;
 9864	};
 9865/**
 9866 * @returns {String} the percent format
 9867 */
 9868Yii.CLocale.prototype.getPercentFormat = function () {
 9869		return this._data.percentFormat;
 9870	};
 9871/**
 9872 * @returns {String} the scientific format
 9873 */
 9874Yii.CLocale.prototype.getScientificFormat = function () {
 9875		return this._data.scientificFormat;
 9876	};
 9877/**
 9878 * @param {Integer} month month (1-12)
 9879 * @param {String} width month name width. It can be 'wide', 'abbreviated' or 'narrow'.
 9880 * @param {Boolean} standAlone whether the month name should be returned in stand-alone format
 9881 * @returns {String} the month name
 9882 */
 9883Yii.CLocale.prototype.getMonthName = function (month, width, standAlone) {
 9884		if (width === undefined) {
 9885			width = 'wide';
 9886		}
 9887		if (standAlone === undefined) {
 9888			standAlone = false;
 9889		}
 9890		if(standAlone) {
 9891			return this._data.monthNamesSA[width][month] !== undefined ? this._data.monthNamesSA[width][month] : this._data.monthNames[width][month];
 9892		}
 9893		else {
 9894			return this._data.monthNames[width][month] !== undefined ? this._data.monthNames[width][month] : this._data.monthNamesSA[width][month];
 9895		}
 9896	};
 9897/**
 9898 * Returns the month names in the specified width.
 9899 * @param {String} width month name width. It can be 'wide', 'abbreviated' or 'narrow'.
 9900 * @param {Boolean} standAlone whether the month names should be returned in stand-alone format
 9901 * @returns {Array} month names indexed by month values (1-12)
 9902 * @since 1.0.9
 9903 */
 9904Yii.CLocale.prototype.getMonthNames = function (width, standAlone) {
 9905		if (width === undefined) {
 9906			width = 'wide';
 9907		}
 9908		if (standAlone === undefined) {
 9909			standAlone = false;
 9910		}
 9911		if(standAlone) {
 9912			return this._data.monthNamesSA[width] !== undefined ? this._data.monthNamesSA[width] : this._data.monthNames[width];
 9913		}
 9914		else {
 9915			return this._data.monthNames[width] !== undefined ? this._data.monthNames[width] : this._data.monthNamesSA[width];
 9916		}
 9917	};
 9918/**
 9919 * @param {Integer} day weekday (0-6, 0 means Sunday)
 9920 * @param {String} width weekday name width.  It can be 'wide', 'abbreviated' or 'narrow'.
 9921 * @param {Boolean} standAlone whether the week day name should be returned in stand-alone format
 9922 * @returns {String} the weekday name
 9923 */
 9924Yii.CLocale.prototype.getWeekDayName = function (day, width, standAlone) {
 9925		if (width === undefined) {
 9926			width = 'wide';
 9927		}
 9928		if (standAlone === undefined) {
 9929			standAlone = false;
 9930		}
 9931		if(standAlone) {
 9932			return this._data.weekDayNamesSA[width][day] !== undefined ? this._data.weekDayNamesSA[width][day] : this._data.weekDayNames[width][day];
 9933		}
 9934		else {
 9935			return this._data.weekDayNames[width][day] !== undefined ? this._data.weekDayNames[width][day] : this._data.weekDayNamesSA[width][day];
 9936		}
 9937	};
 9938/**
 9939 * Returns the week day names in the specified width.
 9940 * @param {String} width weekday name width.  It can be 'wide', 'abbreviated' or 'narrow'.
 9941 * @param {Boolean} standAlone whether the week day name should be returned in stand-alone format
 9942 * @returns {Array} the weekday names indexed by weekday values (0-6, 0 means Sunday, 1 Monday, etc.)
 9943 * @since 1.0.9
 9944 */
 9945Yii.CLocale.prototype.getWeekDayNames = function (width, standAlone) {
 9946		if (width === undefined) {
 9947			width = 'wide';
 9948		}
 9949		if (standAlone === undefined) {
 9950			standAlone = false;
 9951		}
 9952		if(standAlone) {
 9953			return this._data.weekDayNamesSA[width] !== undefined ? this._data.weekDayNamesSA[width] : this._data.weekDayNames[width];
 9954		}
 9955		else {
 9956			return this._data.weekDayNames[width] !== undefined ? this._data.weekDayNames[width] : this._data.weekDayNamesSA[width];
 9957		}
 9958	};
 9959/**
 9960 * @param {Integer} era era (0,1)
 9961 * @param {String} width era name width.  It can be 'wide', 'abbreviated' or 'narrow'.
 9962 * @returns {String} the era name
 9963 */
 9964Yii.CLocale.prototype.getEraName = function (era, width) {
 9965		if (width === undefined) {
 9966			width = 'wide';
 9967		}
 9968		return this._data.eraNames[width][era];
 9969	};
 9970/**
 9971 * @returns {String} the AM name
 9972 */
 9973Yii.CLocale.prototype.getAMName = function () {
 9974		return this._data.amName;
 9975	};
 9976/**
 9977 * @returns {String} the PM name
 9978 */
 9979Yii.CLocale.prototype.getPMName = function () {
 9980		return this._data.pmName;
 9981	};
 9982/**
 9983 * @param {String} width date format width. It can be 'full', 'long', 'medium' or 'short'.
 9984 * @returns {String} date format
 9985 */
 9986Yii.CLocale.prototype.getDateFormat = function (width) {
 9987		if (width === undefined) {
 9988			width = 'medium';
 9989		}
 9990		return this._data.dateFormats[width];
 9991	};
 9992/**
 9993 * @param {String} width time format width. It can be 'full', 'long', 'medium' or 'short'.
 9994 * @returns {String} date format
 9995 */
 9996Yii.CLocale.prototype.getTimeFormat = function (width) {
 9997		if (width === undefined) {
 9998			width = 'medium';
 9999		}
10000		return this._data.timeFormats[width];
10001	};
10002/**
10003 * @returns {String} datetime format, i.e., the order of date and time.
10004 */
10005Yii.CLocale.prototype.getDateTimeFormat = function () {
10006		return this._data.dateTimeFormat;
10007	};
10008/**
10009 * @returns {String} the character orientation, which is either 'ltr' (left-to-right) or 'rtl' (right-to-left)
10010 * @since 1.1.2
10011 */
10012Yii.CLocale.prototype.getOrientation = function () {
10013		return this._data.orientation !== undefined ? this._data.orientation : 'ltr';
10014	};
10015/**
10016 * @returns {Array} plural forms expressions
10017 */
10018Yii.CLocale.prototype.getPluralRules = function () {
10019		return this._data.pluralRules !== undefined ? this._data.pluralRules : [];
10020};/*global Yii, php, $, jQuery, alert, clearInterval, clearTimeout, document, event, frames, history, Image, location, name, navigator, Option, parent, screen, setInterval, setTimeout, window, XMLHttpRequest */
10021/**
10022 * CMissingTranslationEvent represents the parameter for the {@link CMessageSource::onMissingTranslation onMissingTranslation} event.
10023 * 
10024 * @originalAuthor Qiang Xue <qiang.xue@gmail.com>
10025 * @version $Id: CMessageSource.php 2798 2011-01-01 19:29:03Z qiang.xue $
10026 * @package system.i18n
10027 * @since 1.0
10028 * @author Charles Pick
10029 * @class
10030 * @extends Yii.CEvent
10031 */
10032Yii.CMissingTranslationEvent = function CMissingTranslationEvent (sender, params) {
10033	if (sender !== false) {
10034		this.construct(sender, params);
10035	}
10036};
10037Yii.CMissingTranslationEvent.prototype = new Yii.CEvent(false);
10038Yii.CMissingTranslationEvent.prototype.constructor =  Yii.CMissingTranslationEvent;
10039/**
10040 * @var {String} the message to be translated
10041 */
10042Yii.CMissingTranslationEvent.prototype.message = null;
10043/**
10044 * @var {String} the category that the message belongs to
10045 */
10046Yii.CMissingTranslationEvent.prototype.category = null;
10047/**
10048 * @var {String} the ID of the language that the message is to be translated to
10049 */
10050Yii.CMissingTranslationEvent.prototype.language = null;
10051/**
10052 * Constructor.
10053 * @param {Mixed} sender sender of this event
10054 * @param {String} category the category that the message belongs to
10055 * @param {String} message the message to be translated
10056 * @param {String} language the ID of the language that the message is to be translated to
10057 */
10058Yii.CMissingTranslationEvent.prototype.construct = function (sender, category, message, language) {
10059		Yii.CEvent.prototype.construct.call(this, sender);
10060		this.message=message;
10061		this.category=category;
10062		this.language=language;
10063	};/*global Yii, php, $, jQuery, alert, clearInterval, clearTimeout, document, event, frames, history, Image, location, name, navigator, Option, parent, screen, setInterval, setTimeout, window, XMLHttpRequest */
10064/**
10065 * CLogFilter preprocesses the logged messages before they are handled by a log route.
10066 * 
10067 * CLogFilter is meant to be used by a log route to preprocess the logged messages
10068 * before they are handled by the route. The default implementation of CLogFilter
10069 * prepends additional context information to the logged messages. In particular,
10070 * by setting {@link logVars}, predefined PHP variables such as
10071 * $_SERVER, $_POST, etc. can be saved as a log message, which may help identify/debug
10072 * issues encountered.
10073 * 
10074 * @originalAuthor Qiang Xue <qiang.xue@gmail.com>
10075 * @version $Id: CLogFilter.php 2799 2011-01-01 19:31:13Z qiang.xue $
10076 * @package system.logging
10077 * @since 1.0.6
10078 * @author Charles Pick
10079 * @class
10080 * @extends Yii.CComponent
10081 */
10082Yii.CLogFilter = function CLogFilter () {
10083};
10084Yii.CLogFilter.prototype = new Yii.CComponent();
10085Yii.CLogFilter.prototype.constructor =  Yii.CLogFilter;
10086/**
10087 * @var {Boolean} whether to prefix each log message with the current user session ID.
10088 * Defaults to false.
10089 */
10090Yii.CLogFilter.prototype.prefixSession = false;
10091/**
10092 * @var {Boolean} whether to prefix each log message with the current user
10093 * {@link CWebUser::name name} and {@link CWebUser::id ID}. Defaults to false.
10094 */
10095Yii.CLogFilter.prototype.prefixUser = false;
10096/**
10097 * @var {Boolean} whether to log the current user name and ID. Defaults to true.
10098 */
10099Yii.CLogFilter.prototype.logUser = true;
10100/**
10101 * @var {Array} list of the predefined variables that should be logged.
10102 * Note that a variable must be globally accessible. Otherwise it won't be logged.
10103 */
10104Yii.CLogFilter.prototype.logVars = [];
10105/**
10106 * Filters the given log messages.
10107 * This is the main method of CLogFilter. It processes the log messages
10108 * by adding context information, etc.
10109 * @param {Array} logs the log messages
10110 */
10111Yii.CLogFilter.prototype.filter = function (logs) {
10112		var message;
10113		if (!php.empty(logs)) {
10114			if((message=this.getContext())!=='') {
10115				php.array_unshift(logs,[message,Yii.CLogger.LEVEL_INFO,'application',YII_BEGIN_TIME]);
10116			}
10117			this.format(logs);			
10118		}
10119		return logs;
10120	};
10121/**
10122 * Formats the log messages.
10123 * The default implementation will prefix each message with session ID
10124 * if {@link prefixSession} is set true. It may also prefix each message
10125 * with the current user's name and ID if {@link prefixUser} is true.
10126 * @param {Array} logs the log messages
10127 */
10128Yii.CLogFilter.prototype.format = function (logs) {
10129		var prefix, id, user, i, log;
10130		prefix='';
10131		if(this.prefixSession && (id=document.cookie.match(/PHPSESSID=[^;]+/))!==null) {
10132			prefix+="[" + id + "]";
10133		}
10134		if(this.prefixUser && (user=Yii.app().getComponent('user',false))!==null) {
10135			prefix+='['+user.getName()+']['+user.getId()+']';
10136		}
10137		if(prefix!=='')	{
10138			for (i in logs) {
10139				if (logs.hasOwnProperty(i)) {
10140					logs[i][0]=prefix+' '+logs[i][0];
10141				}
10142			}
10143		}
10144	};
10145/**
10146 * Generates the context information to be logged.
10147 * The default implementation will dump user information, system variables, etc.
10148 * @returns {String} the context information. If an empty string, it means no context information.
10149 */
10150Yii.CLogFilter.prototype.getContext = function () {
10151		var context, user, i, name;
10152		context=[];
10153		if(this.logUser && (user=Yii.app().getComponent('user',false))!==null) {
10154			context.push('User: '+user.getName()+' (ID: '+user.getId()+')');
10155		}
10156		for (i in this.logVars)	{
10157			if (this.logVars.hasOwnProperty(i)) {
10158				name = this.logVars[i];
10159				if(window[name] !== undefined) {
10160					context.push(name + " = "  + window[name]);
10161				}
10162			}
10163		}
10164		return context.join("\n\n");
10165	};/*global Yii, php, $, jQuery, alert, clearInterval, clearTimeout, document, event, frames, history, Image, location, name, navigator, Option, parent, screen, setInterval, setTimeout, window, XMLHttpRequest */
10166/**
10167 * CLogRouter manages log routes that record log messages in different media.
10168 * 
10169 * For example, a file log route {@link CFileLogRoute} records log messages
10170 * in log files. An email log route {@link CEmailLogRoute} sends log messages
10171 * to specific email addresses. See {@link CLogRoute} for more details about
10172 * different log routes.
10173 * 
10174 * Log routes may be configured in application configuration like following:
10175 * <pre>
10176 * {
10177 *     'preload':{'log'}, // preload log component when app starts
10178 *     'components':{
10179 *         'log':{
10180 *             'class':'CLogRouter',
10181 *             'routes':{
10182 *                 {
10183 *                     'class':'CFileLogRoute',
10184 *                     'levels':'trace, info',
10185 *                     'categories':'system.*',
10186 *                 },
10187 *                 {
10188 *                     'class':'CEmailLogRoute',
10189 *                     'levels':'error, warning',
10190 *                     'email':'admin@example.com',
10191 *                 },
10192 *             ),
10193 *         ),
10194 *     ),
10195 * }
10196 * </pre>
10197 * 
10198 * You can specify multiple routes with different filtering conditions and different
10199 * targets, even if the routes are of the same type.
10200 * 
10201 * @originalAuthor Qiang Xue <qiang.xue@gmail.com>
10202 * @version $Id: CLogRouter.php 3066 2011-03-13 14:22:55Z qiang.xue $
10203 * @package system.logging
10204 * @since 1.0
10205 * @author Charles Pick
10206 * @class
10207 * @extends Yii.CApplicationComponent
10208 */
10209Yii.CLogRouter = function CLogRouter () {
10210};
10211Yii.CLogRouter.prototype = new Yii.CApplicationComponent();
10212Yii.CLogRouter.prototype.constructor =  Yii.CLogRouter;
10213Yii.CLogRouter.prototype._routes = [];
10214/**
10215 * Initializes this application component.
10216 * This method is required by the IApplicationComponent interface.
10217 */
10218Yii.CLogRouter.prototype.init = function () {
10219		var route, name;
10220		Yii.CApplicationComponent.prototype.init();
10221		for (name in this._routes) {
10222			if (this._routes.hasOwnProperty(name)) {
10223				route = this._routes[name];
10224				route=Yii.createComponent(route);
10225				route.init();
10226				this._routes[name]=route;
10227			}
10228		}
10229		Yii.getLogger().attachEventHandler('onFlush',[this,'collectLogs']);
10230		Yii.app().attachEventHandler('onEndRequest',[this,'processLogs']);
10231		
10232	};
10233/**
10234 * @returns {Array} the currently initialized routes
10235 */
10236Yii.CLogRouter.prototype.getRoutes = function () {
10237		return new Yii.CMap(this._routes);
10238	};
10239/**
10240 * @param {Array} config list of route configurations. Each array element represents
10241 * the configuration for a single route and has the following array structure:
10242 * <ul>
10243 * <li>class: specifies the class name or alias for the route class.</li>
10244 * <li>name-value pairs: configure the initial property values of the route.</li>
10245 * </ul>
10246 */
10247Yii.CLogRouter.prototype.setRoutes = function (config) {
10248		var name, route;
10249		for (name in config) {
10250			if (config.hasOwnProperty(name)) {
10251				route = config[name];
10252				this._routes[name]=route;
10253			}
10254		}
10255		
10256	};
10257/**
10258 * Collects log messages from a logger.
10259 * This method is an event handler to the {@link CLogger::onFlush} event.
10260 * @param {Yii.CEvent} event event parameter
10261 */
10262Yii.CLogRouter.prototype.collectLogs = function (event) {
10263		var logger, dumpLogs, i, route;
10264		logger=Yii.getLogger();
10265		dumpLogs=event.params.dumpLogs !== undefined && event.params.dumpLogs;
10266		for (i in this._routes) {
10267			if (this._routes.hasOwnProperty(i)) {
10268				route = this._routes[i];
10269				if(route.enabled) {
10270					route.collectLogs(logger,dumpLogs);
10271				}
10272			}
10273		}
10274	};
10275/**
10276 * Collects and processes log messages from a logger.
10277 * This method is an event handler to the {@link CApplication::onEndRequest} event.
10278 * @param {Yii.CEvent} event event parameter
10279 * @since 1.1.0
10280 */
10281Yii.CLogRouter.prototype.processLogs = function (event) {
10282		var logger, i, route;
10283		logger=Yii.getLogger();
10284		
10285		for (i in this._routes)	{
10286			if (this._routes.hasOwnProperty(i)) {
10287				route = this._routes[i];
10288				
10289				if(route.enabled) {
10290					
10291					route.collectLogs(logger,true);
10292					
10293				}
10294			}
10295		}
10296	};/*global Yii, php, $, jQuery, alert, clearInterval, clearTimeout, document, event, frames, history, Image, location, name, navigator, Option, parent, screen, setInterval, setTimeout, window, XMLHttpRequest */
10297/**
10298 * CLogger records log messages in memory.
10299 * 
10300 * CLogger implements the methods to retrieve the messages with
10301 * various filter conditions, including log levels and log categories.
10302 * 
10303 * @originalAuthor Qiang Xue <qiang.xue@gmail.com>
10304 * @version $Id: CLogger.php 3137 2011-03-28 11:08:06Z mdomba $
10305 * @package system.logging
10306 * @since 1.0
10307 * @author Charles Pick
10308 * @class
10309 * @extends Yii.CComponent
10310 */
10311Yii.CLogger = function() {
10312};
10313Yii.CLogger.prototype = new Yii.CComponent();
10314Yii.CLogger.prototype.constructor =  Yii.CLogger;
10315/**
10316 * @const
10317 */
10318Yii.CLogger.prototype.LEVEL_TRACE = 'trace';
10319/**
10320 * @const
10321 */
10322Yii.CLogger.prototype.LEVEL_WARNING = 'warning';
10323/**
10324 * @const
10325 */
10326Yii.CLogger.prototype.LEVEL_ERROR = 'error';
10327/**
10328 * @const
10329 */
10330Yii.CLogger.prototype.LEVEL_INFO = 'info';
10331/**
10332 * @const
10333 */
10334Yii.CLogger.prototype.LEVEL_PROFILE = 'profile';
10335/**
10336 * @var {Integer} how many messages should be logged before they are flushed to destinations.
10337 * Defaults to 10,000, meaning for every 10,000 messages, the {@link flush} method will be
10338 * automatically invoked once. If this is 0, it means messages will never be flushed automatically.
10339 * @since 1.1.0
10340 */
10341Yii.CLogger.prototype.autoFlush = 10000;
10342/**
10343 * @var {Array} log messages
10344 */
10345Yii.CLogger.prototype._logs = [];
10346/**
10347 * @var {Integer} number of log messages
10348 */
10349Yii.CLogger.prototype._logCount = 0;
10350/**
10351 * @var {Array} log levels for filtering (used when filtering)
10352 */
10353Yii.CLogger.prototype._levels = null;
10354/**
10355 * @var {Array} log categories for filtering (used when filtering)
10356 */
10357Yii.CLogger.prototype._categories = null;
10358/**
10359 * @var {Array} the profiling results (category, token => time in seconds)
10360 * @since 1.0.6
10361 */
10362Yii.CLogger.prototype._timings = null;
10363/**
10364 * Logs a message.
10365 * Messages logged by this method may be retrieved back via {@link getLogs}.
10366 * @param {String} message message to be logged
10367 * @param {String} level level of the message (e.g. 'Trace', 'Warning', 'Error'). It is case-insensitive.
10368 * @param {String} category category of the message (e.g. 'system.web'). It is case-insensitive.
10369 * @see getLogs
10370 */
10371Yii.CLogger.prototype.log = function (message, level, category) {
10372		if (level === undefined) {
10373			level = 'info';
10374		}
10375		if (category === undefined) {
10376			category = 'application';
10377		}
10378		this._logs.push([message,level,category,php.microtime(true)]);
10379		this._logCount++;
10380		if(this.autoFlush>0 && this._logCount>=this.autoFlush) {
10381			this.flush();
10382		}
10383	};
10384/**
10385 * Retrieves log messages.
10386 * 
10387 * Messages may be filtered by log levels and/or categories.
10388 * A level filter is specified by a list of levels separated by comma or space
10389 * (e.g. 'trace, error'). A category filter is similar to level filter
10390 * (e.g. 'system, system.web'). A difference is that in category filter
10391 * you can use pattern like 'system.*' to indicate all categories starting
10392 * with 'system'.
10393 * 
10394 * If you do not specify level filter, it will bring back logs at all levels.
10395 * The same applies to category filter.
10396 * 
10397 * Level filter and category filter are combinational, i.e., only messages
10398 * satisfying both filter conditions will be returned.
10399 * 
10400 * @param {String} levels level filter
10401 * @param {String} categories category filter
10402 * @returns {Array} list of messages. Each array elements represents one message
10403 * with the following structure:
10404 * array(
10405 *   [0] => message (string)
10406 *   [1] => level (string)
10407 *   [2] => category (string)
10408 *   [3] => timestamp (float, obtained by microtime(true));
10409 */
10410Yii.CLogger.prototype.getLogs = function (levels, categories) {
10411		var ret, self;
10412		if (levels === undefined) {
10413			levels = '';
10414			this._levels = [];
10415		}
10416		else {
10417			this._levels=levels.toLowerCase().split(/[\s,]+/);
10418		}
10419		if (categories === undefined) {
10420			categories = '';
10421			this._categories = [];
10422		}
10423		else {
10424			this._categories=categories.toLowerCase().split(/[\s,]+/);	
10425		}
10426		
10427		
10428		self = this;
10429		if(php.empty(levels) && php.empty(categories)) {
10430			return this._logs;
10431		}		
10432		else if(php.empty(levels)) {
10433			
10434			return Yii.filter(this._logs,function(value, k, arr) {
10435				var matched = false, cat = value[2].toLowerCase(), c;
10436				Yii.forEach(self._categories, function(i, category) {
10437					if(cat===category || ((c=php.rtrim(category,'.*'))!==category && php.strpos(cat,c)===0)) {
10438						matched = true;
10439						return false;
10440					}
10441				});
10442				return matched ? value : false;
10443			});
10444			
10445		}
10446		else if(php.empty(categories)) {
10447			return Yii.filter(this._logs,function(value, k, arr) {
10448				var matched = false, matchLevel = value[1].toLowerCase();
10449				Yii.forEach(self._levels, function(i, level) {
10450					if (level === matchLevel) {
10451						matched = true;
10452						return false;
10453					}
10454				});
10455				return matched ? value : false;
10456			});
10457		}
10458		else {
10459			return Yii.filter(Yii.filter(this._logs,function(value, k, arr) {
10460				var matched = false, cat = value[2].toLowerCase(), c;
10461				Yii.forEach(self._categories, function(i, category) {
10462					if(cat===category || ((c=php.rtrim(category,'.*'))!==category && php.strpos(cat,c)===0)) {
10463						matched = true;
10464						return false;
10465					}
10466				});
10467				return matched ? value : false;
10468			}), function(value, k, arr) {
10469				var matched = false, matchLevel = value[1].toLowerCase();
10470				Yii.forEach(self._levels, function(i, level) {
10471					if (level === matchLevel) {
10472						matched = true;
10473						return false;
10474					}
10475				});
10476				return matched ? value : false;
10477			});
10478			
10479		}
10480	};
10481/**
10482 * Filter function used by {@link getLogs}
10483 * @param {Array} value element to be filtered
10484 * @returns {Array} valid log, false if not.
10485 */
10486Yii.CLogger.prototype.filterByCategory = function (value) {
10487		var i, cat, category, c;
10488		for (i in this._categories) {
10489			if (this._categories.hasOwnProperty(i)) {
10490				category = this._categories[i];
10491				cat=value[2].toLowerCase();
10492				if(cat===category || ((c=php.rtrim(category,'.*'))!==category && php.strpos(cat,c)===0)) {
10493					return value;
10494				}
10495			}
10496		}
10497		return false;
10498	};
10499/**
10500 * Filter function used by {@link getLogs}
10501 * @param {Array} value element to be filtered
10502 * @returns {Array} valid log, false if not.
10503 */
10504Yii.CLogger.prototype.filterByLevel = function (value) {
10505		var matched = false, matchLevel = value[1].toLowerCase();
10506		
10507		Yii.forEach(this._levels, function(i, level) {
10508			console.log(level);
10509			if (level === matchLevel) {
10510				matched = true;
10511				return false;
10512			}
10513		});
10514		return matched ? value : false;
10515	};
10516/**
10517 * Returns the total time for serving the current request.
10518 * This method calculates the difference between now and the timestamp
10519 * defined by constant YII_BEGIN_TIME.
10520 * To estimate the execution time more accurately, the constant should
10521 * be defined as early as possible (best at the beginning of the entry script.)
10522 * @returns {Float} the total time for serving the current request.
10523 */
10524Yii.CLogger.prototype.getExecutionTime = function () {
10525		return php.microtime(true)-YII_BEGIN_TIME;
10526	};
10527/**
10528 * Not Available in JavaScript, always returns 0
10529 * @returns {Integer} memory usage of the application (in bytes).
10530 */
10531Yii.CLogger.prototype.getMemoryUsage = function () {
10532		return 0;
10533	};
10534/**
10535 * Returns the profiling results.
10536 * The results may be filtered by token and/or category.
10537 * If no filter is specified, the returned results would be an array with each element
10538 * being array($token,$category,$time).
10539 * If a filter is specified, the results would be an array of timings.
10540 * @param {String} token token filter. Defaults to null, meaning not filtered by token.
10541 * @param {String} category category filter. Defaults to null, meaning not filtered by category.
10542 * @param {Boolean} refresh whether to refresh the internal timing calculations. If false,
10543 * only the first time calling this method will the timings be calculated internally.
10544 * @returns {Array} the profiling results.
10545 * @since 1.0.6
10546 */
10547Yii.CLogger.prototype.getProfilingResults = function (token, category, refresh) {
10548		var results, i, timing;
10549		if (token === undefined) {
10550			token = null;
10551		}
10552		if (category === undefined) {
10553			category = null;
10554		}
10555		if (refresh === undefined) {
10556			refresh = false;
10557		}
10558		if(this._timings===null || refresh) {
10559			this.calculateTimings();
10560		}
10561		if(token===null && category===null) {
10562			return this._timings;
10563		}
10564		results=[];
10565		for (i in this._timings) {
10566			if (this._timings.hasOwnProperty(i)) {
10567				timing = this._timings[i];
10568				if((category===null || timing[1]===category) && (token===null || timing[0]===token)) {
10569					results.push(timing[2]);
10570				}
10571			}
10572		}
10573		return results;
10574	};
10575Yii.CLogger.prototype.calculateTimings = function () {
10576		var stack, i, log, message, level, category, timestamp, token, last, delta, now;
10577		this._timings=[];
10578		stack=[];
10579		for (i in this._logs) {
10580			if (this._logs.hasOwnProperty(i)) {
10581				log = this._logs[i];
10582				if(log[1]!==Yii.CLogger.prototype.LEVEL_PROFILE) {
10583					continue;
10584				}
10585				message = log[0];
10586				level = log[1];
10587				category = log[2];
10588				timestamp = log[3];
10589				if(!php.strncasecmp(message,'begin:',6)) {
10590					log[0]=message.slice(6);
10591					stack.push(log);
10592				}
10593				else if(!php.strncasecmp(message,'end:',4)) {
10594					token=message.slice(4);
10595					if((last=php.array_pop(stack))!==null && last[0]===token) {
10596						delta=log[3]-last[3];
10597						this._timings.push([message,category,delta]);
10598					}
10599					else {
10600						throw new Yii.CException(Yii.t('yii','CProfileLogRoute found a mismatching code block "{token}". Make sure the calls to Yii::beginProfile() and Yii::endProfile() be properly nested.',
10601							{'{token}':token}));
10602					}
10603				}
10604			}
10605		}
10606		now=php.microtime(true);
10607		while((last=php.array_pop(stack))!==null) {
10608			delta=now-last[3];
10609			this._timings.push([last[0],last[2],delta]);
10610		}
10611	};
10612/**
10613 * Removes all recorded messages from the memory.
10614 * This method will raise an {@link onFlush} event.
10615 * The attached event handlers can process the log messages before they are removed.
10616 * @param {Boolean} dumpLogs whether to process the logs
10617 * @since 1.1.0
10618 */
10619Yii.CLogger.prototype.flush = function (dumpLogs) {
10620		if (dumpLogs === undefined) {
10621			dumpLogs = false;
10622		}
10623		this.onFlush(new Yii.CEvent(this, {'dumpLogs':dumpLogs}));
10624		this._logs=[];
10625		this._logCount=0;
10626	};
10627/**
10628 * Raises an <code>onFlush</code> event.
10629 * @param {Yii.CEvent} event the event parameter
10630 * @since 1.1.0
10631 */
10632Yii.CLogger.prototype.onFlush = function (event) {
10633		this.raiseEvent('onFlush', event);
10634	}/*global Yii, php, $, jQuery, alert, clearInterval, clearTimeout, document, event, frames, history, Image, location, name, navigator, Option, parent, screen, setInterval, setTimeout, window, XMLHttpRequest */
10635/**
10636 * CProfileLogRoute displays the profiling results in Web page.
10637 * 
10638 * The profiling is done by calling {@link YiiBase::beginProfile()} and {@link YiiBase::endProfile()},
10639 * which marks the begin and end of a code block.
10640 * 
10641 * CProfileLogRoute supports two types of report by setting the {@link setReport report} property:
10642 * <ul>
10643 * <li>summary: list the execution time of every marked code block</li>
10644 * <li>callstack: list the mark code blocks in a hierarchical view reflecting their calling sequence.</li>
10645 * </ul>
10646 * 
10647 * @originalAuthor Qiang Xue <qiang.xue@gmail.com>
10648 * @version $Id: CProfileLogRoute.php 3001 2011-02-24 16:42:44Z alexander.makarow $
10649 * @package system.logging
10650 * @since 1.0
10651 * @author Charles Pick
10652 * @class
10653 * @extends Yii.CWebLogRoute
10654 */
10655Yii.CProfileLogRoute = function CProfileLogRoute () {
10656};
10657Yii.CProfileLogRoute.prototype = new Yii.CWebLogRoute();
10658Yii.CProfileLogRoute.prototype.constructor =  Yii.CProfileLogRoute;
10659/**
10660 * @var {Boolean} whether to aggregate results according to profiling tokens.
10661 * If false, the results will be aggregated by categories.
10662 * Defaults to true. Note that this property only affects the summary report
10663 * that is enabled when {@link report} is 'summary'.
10664 * @since 1.0.6
10665 */
10666Yii.CProfileLogRoute.prototype.groupByToken = true;
10667/**
10668 * @var {String} type of profiling report to display
10669 */
10670Yii.CProfileLogRoute.prototype._report = 'summary';
10671/**
10672 * Initializes the route.
10673 * This method is invoked after the route is created by the route manager.
10674 */
10675Yii.CProfileLogRoute.prototype.init = function () {
10676		
10677		this.levels=Yii.CLogger.prototype.LEVEL_PROFILE;
10678	};
10679/**
10680 * @returns {String} the type of the profiling report to display. Defaults to 'summary'.
10681 */
10682Yii.CProfileLogRoute.prototype.getReport = function () {
10683		return this._report;
10684	};
10685/**
10686 * @param {String} value the type of the profiling report to display. Valid values include 'summary' and 'callstack'.
10687 */
10688Yii.CProfileLogRoute.prototype.setReport = function (value) {
10689		if(value==='summary' || value==='callstack') {
10690			this._report=value;
10691		}
10692		else {
10693			throw new Yii.CException(Yii.t('yii','CProfileLogRoute.report "{report}" is invalid. Valid values include "summary" and "callstack".',
10694				{'{report}':value}));
10695		}
10696	};
10697/**
10698 * Displays the log messages.
10699 * @param {Array} logs list of log messages
10700 */
10701Yii.CProfileLogRoute.prototype.processLogs = function (logs) {
10702		var app;
10703		app=Yii.app();
10704		
10705		if(!(app instanceof Yii.CWebApplication) || app.getRequest().getIsAjaxRequest()) {
10706			return;
10707		}
10708		
10709		if(this.getReport()==='summary') {
10710			this.displaySummary(logs);
10711		}
10712		else {
10713			this.displayCallstack(logs);
10714		}
10715	};
10716/**
10717 * Displays the callstack of the profiling procedures for display.
10718 * @param {Array} logs list of logs
10719 */
10720Yii.CProfileLogRoute.prototype.displayCallstack = function (logs) {
10721		var stack, results, n, i, log, message, token, last, delta, now;
10722		stack=[];
10723		results={};
10724		n=0;
10725		for (i in logs)	{
10726			if (logs.hasOwnProperty(i)) {
10727				log = logs[i];
10728				if(log[1]!==Yii.CLogger.prototype.LEVEL_PROFILE) {
10729					continue;
10730				}
10731				message=log[0];
10732				if(!php.strncasecmp(message,'begin:',6)){
10733					log[0]=message.slice(6);
10734					log[4]=n;
10735					stack.push(log);
10736					n++;
10737				}
10738				else if(!php.strncasecmp(message,'end:',4)) {
10739					token=message.slice(4);
10740					if((last=php.array_pop(stack))!==null && last[0]===token) {
10741						delta=log[3]-last[3];
10742						results[last[4]]=[token,delta,php.count(stack)];
10743					}
10744					else {
10745						throw new Yii.CException(Yii.t('yii','CProfileLogRoute found a mismatching code block "{token}". Make sure the calls to Yii::beginProfile() and Yii::endProfile() be properly nested.',
10746							{'{token}':token}));
10747					}
10748				}
10749			}
10750		}
10751		// remaining entries should be closed here
10752		now=php.microtime(true);
10753		while((last=php.array_pop(stack))!==null) {
10754			results[last[4]]=[last[0],now-last[3],php.count(stack)];
10755		}
10756		php.ksort(results);
10757		this.render('profile-callstack',results);
10758	};
10759/**
10760 * Displays the summary report of the profiling result.
10761 * @param {Array} logs list of logs
10762 */
10763Yii.CProfileLogRoute.prototype.displaySummary = function (logs) {
10764		var stack, i, log, message, token, last, delta, results = {}, now, entries, func, data;
10765		stack=[];
10766		for (i in logs)	{
10767			if (logs.hasOwnProperty(i)) {
10768			
10769				log = logs[i];
10770				
10771				if(log[1]!==Yii.CLogger.prototype.LEVEL_PROFILE) {
10772					continue;
10773				}
10774				message=log[0];
10775				
10776				if(!php.strncasecmp(message,'begin:',6)) {
10777					log[0]=message.slice(6);
10778					stack.push(log);
10779				}
10780				else if(!php.strncasecmp(message,'end:',4)) {
10781					token=message.slice(4);
10782					
10783					if((last=php.array_pop(stack))!==null && last[0]===token) {
10784						delta=log[3]-last[3];
10785						if(!this.groupByToken) {
10786							token=log[2];
10787						}
10788						if(results[token] !== undefined) {
10789							
10790							results[token]=this.aggregateResult(results[token],delta);
10791						}
10792						else {
10793							results[token]=[token,1,delta,delta,delta];
10794						}
10795					}
10796					else {
10797					
10798						throw new Yii.CException(Yii.t('yii','CProfileLogRoute found a mismatching code block "{token}". Make sure the calls to Yii::beginProfile() and Yii::endProfile() be properly nested.',
10799							{'{token}':token}));
10800					}
10801				}
10802			}
10803		}
10804		
10805		now=php.microtime(true);
10806		while((last=php.array_pop(stack))!==null) {
10807			delta=now-last[3];
10808			token=this.groupByToken ? last[0] : last[2];
10809			if(results[token] !== undefined) {
10810				results[token]=this.aggregateResult(results[token],delta);
10811			}
10812			else {
10813				results[token]=[token,1,delta,delta,delta];
10814			}
10815		}
10816		entries=php.array_values(results);
10817		func = function(a,b) {
10818			return a[4] < b[4] ? 1 : 0;
10819		};
10820		php.usort(entries,func);
10821		data = {
10822			time: php.sprintf('%0.5f',Yii.getLogger().getExecutionTime()),
10823			entries: []
10824		};
10825		
10826		Yii.forEach(entries, function(k, entry) {
10827			data.entries.push({
10828				'proc': Yii.CHtml.encode(entry[0]),
10829				'count': php.sprintf('%5d',entry[1]),
10830				'min': php.sprintf('%0.5f',entry[2]),
10831				'max': php.sprintf('%0.5f',entry[3]),
10832				'total': php.sprintf('%0.5f',entry[4]),
10833				'average': php.sprintf('%0.5f',entry[4] / entry[1])
10834			});
10835		});
10836		if (this.showInFireBug && window['console'] !== undefined) {
10837			if (console.group !== undefined) {
10838				console.group("Profiling Summary Report");
10839			}
10840			console.log(" count   total   average    min      max   ");
10841			Yii.forEach(data.entries, function(k, entry) {
10842				console.log(" " + entry.count + "  " + entry.total + "  " + entry.average + "  " + entry.min + "  " + entry.max + "    " + entry.proc);
10843			});
10844			if (console.group !== undefined) {
10845				console.groupEnd();
10846			}
10847		}
10848		else {
10849			this.render('profile-summary',data);
10850		}
10851	};
10852/**
10853 * Aggregates the report result.
10854 * @param {Array} result log result for this code block
10855 * @param {Float} delta time spent for this code block
10856 */
10857Yii.CProfileLogRoute.prototype.aggregateResult = function (result, delta) {
10858		var token, calls, min, max, total;
10859		token = result[0];
10860		calls = result[1];
10861		min = result[2];
10862		max = result[3];
10863		total = result[4];
10864		if(delta<min) {
10865			min=delta;
10866		}
10867		else if(delta>max) {
10868			max=delta;
10869		}
10870		calls++;
10871		total+=delta;
10872		return [token,calls,min,max,total];
10873	};/*global Yii, php, $, jQuery, alert, clearInterval, clearTimeout, document, event, frames, history, Image, location, name, navigator, Option, parent, screen, setInterval, setTimeout, window, XMLHttpRequest */
10874/**
10875 * CDateTimeParser converts a date/time string to a UNIX timestamp according to the specified pattern.
10876 * 
10877 * The following pattern characters are recognized:
10878 * <pre>
10879 * Pattern |      Description
10880 * ----------------------------------------------------
10881 * d       | Day of month 1 to 31, no padding
10882 * dd      | Day of month 01 to 31, zero leading
10883 * M       | Month digit 1 to 12, no padding
10884 * MM      | Month digit 01 to 12, zero leading
10885 * yy      | 2 year digit, e+g+, 96, 05
10886 * yyyy    | 4 year digit, e+g+, 2005
10887 * h       | Hour in 0 to 23, no padding
10888 * hh      | Hour in 00 to 23, zero leading
10889 * H       | Hour in 0 to 23, no padding
10890 * HH      | Hour in 00 to 23, zero leading
10891 * m       | Minutes in 0 to 59, no padding
10892 * mm      | Minutes in 00 to 59, zero leading
10893 * s       | Seconds in 0 to 59, no padding
10894 * ss      | Seconds in 00 to 59, zero leading
10895 * a       | AM or PM, case-insensitive (since version 1.1.5)
10896 * ----------------------------------------------------
10897 * </pre>
10898 * All other characters must appear in the date string at the corresponding positions.
10899 * 
10900 * For example, to parse a date string '21/10/2008', use the following:
10901 * <pre>
10902 * timestamp=Yii.CDateTimeParser.parse('21/10/2008','dd/MM/yyyy');
10903 * </pre>
10904 * 
10905 * To format a timestamp to a date string, please use {@link CDateFormatter}.
10906 * 
10907 * @originalAuthor Wei Zhuo <weizhuo[at]gmail[dot]com>
10908 * @originalAuthor Qiang Xue <qiang.xue@gmail.com>
10909 * @version $Id: CDateTimeParser.php 2928 2011-02-01 17:41:51Z alexander.makarow $
10910 * @package system.utils
10911 * @since 1.0
10912 * @author Charles Pick
10913 * @class
10914 */
10915Yii.CDateTimeParser = {
10916	
10917};
10918/**
10919 * Converts a date string to a timestamp.
10920 * @param {String} value the date string to be parsed
10921 * @param {String} pattern the pattern that the date string is following
10922 * @param {Array} defaults the default values for year, month, day, hour, minute and second.
10923 * The default values will be used in case when the pattern doesn't specify the
10924 * corresponding fields. For example, if the pattern is 'MM/dd/yyyy' and this
10925 * parameter is array('minute'=>0, 'second'=>0), then the actual minute and second
10926 * for the parsing result will take value 0, while the actual hour value will be
10927 * the current hour obtained by date('H'). This parameter has been available since version 1.1.5.
10928 * @returns {Integer} timestamp for the date string. False if parsing fails.
10929 */
10930Yii.CDateTimeParser.parse = function (value, pattern, defaults) {
10931		var tokens, i, n, j, token, year, month, day, hour, minute, second, ampm, tn;
10932		if (pattern === undefined) {
10933			pattern = 'MM/dd/yyyy';
10934		}
10935		if (defaults === undefined) {
10936			defaults = [];
10937		}
10938		tokens=this.tokenize(pattern);
10939		i=0;
10940		n=php.strlen(value);
10941		for (j in tokens)
10942		{
10943			if (tokens.hasOwnProperty(j)) {
10944				token = tokens[j];
10945			switch(token)
10946			{
10947				case 'yyyy':
10948					if((year=this.parseInteger(value,i,4,4))===false) {
10949						return false;
10950					}
10951					i+=4;
10952					break;
10953				case 'yy':
10954					if((year=this.parseInteger(value,i,1,2))===false) {
10955						return false;
10956					}
10957					i+=php.strlen(year);
10958					break;
10959				case 'MM':
10960					if((month=this.parseInteger(value,i,2,2))===false) {
10961						return false;
10962					}
10963					i+=2;
10964					break;
10965				case 'M':
10966					if((month=this.parseInteger(value,i,1,2))===false) {
10967						return false;
10968					}
10969					i+=php.strlen(month);
10970					break;
10971				case 'dd':
10972					if((day=this.parseInteger(value,i,2,2))===false) {
10973						return false;
10974					}
10975					i+=2;
10976					break;
10977				case 'd':
10978					if((day=this.parseInteger(value,i,1,2))===false) {
10979						return false;
10980					}
10981					i+=php.strlen(day);
10982					break;
10983				case 'h':
10984				case 'H':
10985					if((hour=this.parseInteger(value,i,1,2))===false) {
10986						return false;
10987					}
10988					i+=php.strlen(hour);
10989					break;
10990				case 'hh':
10991				case 'HH':
10992					if((hour=this.parseInteger(value,i,2,2))===false) {
10993						return false;
10994					}
10995					i+=2;
10996					break;
10997				case 'm':
10998					if((minute=this.parseInteger(value,i,1,2))===false) {
10999						return false;
11000					}
11001					i+=php.strlen(minute);
11002					break;
11003				case 'mm':
11004					if((minute=this.parseInteger(value,i,2,2))===false) {
11005						return false;
11006					}
11007					i+=2;
11008					break;
11009				case 's':
11010					if((second=this.parseInteger(value,i,1,2))===false) {
11011						return false;
11012					}
11013					i+=php.strlen(second);
11014					break;
11015				case 'ss':
11016					if((second=this.parseInteger(value,i,2,2))===false) {
11017						return false;
11018					}
11019					i+=2;
11020					break;
11021				case 'a':
11022				    if((ampm=this.parseAmPm(value,i))===false) {
11023				        return false;
11024					}
11025				    if(hour !== undefined)
11026				    {
11027						if(hour==12 && ampm==='am') {
11028							hour=0;
11029						}
11030						else if(hour<12 && ampm==='pm') {
11031							hour+=12;
11032						}
11033				    }
11034					i+=2;
11035					break;
11036				default:
11037					tn=php.strlen(token);
11038					if(i>=n || value.slice(i, tn)!==token) {
11039						return false;
11040					}
11041					i+=tn;
11042					break;
11043			}
11044		}
11045		}
11046		if(i<n) {
11047			return false;
11048		}
11049		if(year === undefined) {
11050			year=defaults.year !== undefined ? defaults.year : php.date('Y');
11051		}
11052		if(month === undefined) {
11053			month=defaults.month !== undefined ? defaults.month : php.date('n');
11054		}
11055		if(day === undefined) {
11056			day=defaults.day !== undefined ? defaults.day : php.date('j');
11057		}
11058		if(php.strlen(year)===2) {
11059			if(year>=70) {
11060				year+=1900;
11061			}
11062			else {
11063				year+=2000;
11064			}
11065		}
11066		year=Number(year);
11067		month=Number(month);
11068		day=Number(day);
11069		if(hour === undefined && minute === undefined && second === undefined && defaults.hour === undefined && defaults.minute === undefined && defaults.second === undefined) {
11070			hour=minute=second=0;
11071		}
11072		else {
11073			if(hour === undefined) {
11074				hour=defaults.hour !== undefined ? defaults.hour : php.date('H');
11075			}
11076			if(minute === undefined) {
11077				minute=defaults.minute !== undefined ? defaults.minute : php.date('i');
11078			}
11079			if(second === undefined) {
11080				second=defaults.second !== undefined ? defaults.second : php.date('s');
11081			}
11082			hour=Number(hour);
11083			minute=Number(minute);
11084			second=Number(second);
11085		}
11086		if(Yii.CTimestamp.isValidDate(year,month,day) && Yii.CTimestamp.isValidTime(hour,minute,second)) {
11087			return Yii.CTimestamp.getTimestamp(hour,minute,second,month,day,year);
11088		}
11089		else {
11090			return false;
11091		}
11092	};
11093Yii.CDateTimeParser.tokenize = function (pattern) {
11094		var n, tokens, c0, start, i, c;
11095		if(!(n=php.strlen(pattern))) {
11096			return [];
11097		}
11098		tokens=[];
11099		for(c0=pattern[0],start=0,i=1;i<n;++i) {
11100			if((c=pattern[i])!==c0)	{
11101				tokens.push(pattern.slice(start, i-start));
11102				c0=c;
11103				start=i;
11104			}
11105		}
11106		tokens.push(pattern.slice(start, n-start));
11107		return tokens;
11108	};
11109Yii.CDateTimeParser.parseInteger = function (value, offset, minLength, maxLength) {
11110		var len, v;
11111		for(len=maxLength;len>=minLength;--len)	{
11112			v=value.slice(offset, len);
11113			if(php.ctype_digit(v) && php.strlen(v)>=minLength) {
11114				return v;
11115			}
11116		}
11117		return false;
11118	};
11119Yii.CDateTimeParser.parseAmPm = function (value, offset) {
11120		var v;
11121		v=value.slice(offset, 2).toLowerCase();
11122		return v==='am' || v==='pm' ? v : false;
11123	}/*global Yii, php, $, jQuery, alert, clearInterval, clearTimeout, document, event, frames, history, Image, location, name, navigator, Option, parent, screen, setInterval, setTimeout, window, XMLHttpRequest */
11124/**
11125 * CFormatter provides a set of commonly used data formatting methods.
11126 * 
11127 * The formatting methods provided by CFormatter are all named in the form of <code>formatXyz</code>.
11128 * The behavior of some of them may be configured via the properties of CFormatter. For example,
11129 * by configuring {@link dateFormat}, one may control how {@link formatDate} formats the value into a date string.
11130 * 
11131 * For convenience, CFormatter also implements the mechanism of calling formatting methods with their shortcuts (called types).
11132 * In particular, if a formatting method is named <code>formatXyz</code>, then its shortcut method is <code>xyz</code>
11133 * (case-insensitive). For example, calling <code>$formatter->date($value)</code> is equivalent to calling
11134 * <code>$formatter->formatDate($value)</code>.
11135 * 
11136 * Currently, the following types are recognizable:
11137 * <ul>
11138 * <li>raw: the attribute value will not be changed at all.</li>
11139 * <li>text: the attribute value will be HTML-encoded when rendering.</li>
11140 * <li>ntext: the {@link formatNtext} method will be called to format the attribute value as a HTML-encoded plain text with newlines converted as the HTML &lt;br /&gt; tags.</li>
11141 * <li>html: the attribute value will be purified and then returned.</li>
11142 * <li>date: the {@link formatDate} method will be called to format the attribute value as a date.</li>
11143 * <li>time: the {@link formatTime} method will be called to format the attribute value as a time.</li>
11144 * <li>datetime: the {@link formatDatetime} method will be called to format the attribute value as a date with time.</li>
11145 * <li>boolean: the {@link formatBoolean} method will be called to format the attribute value as a boolean display.</li>
11146 * <li>number: the {@link formatNumber} method will be called to format the attribute value as a number display.</li>
11147 * <li>email: the {@link formatEmail} method will be called to format the attribute value as a mailto link.</li>
11148 * <li>image: the {@link formatImage} method will be called to format the attribute value as an image tag where the attribute value is the image URL.</li>
11149 * <li>url: the {@link formatUrl} method will be called to format the attribute value as a hyperlink where the attribute value is the URL.</li>
11150 * </ul>
11151 * 
11152 * By default, {@link CApplication} registers {@link CFormatter} as an application component whose ID is 'format'.
11153 * Therefore, one may call <code>Yii::app()->format->boolean(1)</code>.
11154 * 
11155 * @originalAuthor Qiang Xue <qiang.xue@gmail.com>
11156 * @version $Id: CFormatter.php 2799 2011-01-01 19:31:13Z qiang.xue $
11157 * @package system.utils
11158 * @since 1.1.0
11159 * @author Charles Pick
11160 * @class
11161 * @extends Yii.CApplicationComponent
11162 */
11163Yii.CFormatter = function CFormatter() {
11164};
11165Yii.CFormatter.prototype = new Yii.CApplicationComponent();
11166Yii.CFormatter.prototype.constructor =  Yii.CFormatter;
11167Yii.CFormatter.prototype._htmlPurifier = null;
11168/**
11169 * @var {String} the format string to be used to format a date using PHP date() function. Defaults to 'Y/m/d'.
11170 */
11171Yii.CFormatter.prototype.dateFormat = 'Y/m/d';
11172/**
11173 * @var {String} the format string to be used to format a time using PHP date() function. Defaults to 'h:i:s A'.
11174 */
11175Yii.CFormatter.prototype.timeFormat = 'h:i:s A';
11176/**
11177 * @var {String} the format string to be used to format a date and time using PHP date() function. Defaults to 'Y/m/d h:i:s A'.
11178 */
11179Yii.CFormatter.prototype.datetimeFormat = 'Y/m/d h:i:s A';
11180/**
11181 * @var {Array} the format used to format a number with PHP number_format() function.
11182 * Three elements may be specified: "decimals", "decimalSeparator" and "thousandSeparator". They
11183 * correspond to the number of digits after the decimal point, the character displayed as the decimal point,
11184 * and the thousands separator character.
11185 */
11186Yii.CFormatter.prototype.numberFormat = {
11187	'decimals':null,
11188	'decimalSeparator':null,
11189	'thousandSeparator':null
11190};
11191/**
11192 * @var {Array} the text to be displayed when formatting a boolean value. The first element corresponds
11193 * to the text display for false, the second element for true. Defaults to <code>array('No', 'Yes')</code>.
11194 */
11195Yii.CFormatter.prototype.booleanFormat = ['No','Yes'];
11196/**
11197 * Calls the format method when its shortcut is invoked.
11198 * This is a PHP magic method that we override to implement the shortcut format methods.
11199 * @param {String} name the method name
11200 * @param {Array} parameters method parameters
11201 * @returns {Mixed} the method return value
11202 */
11203Yii.CFormatter.prototype.call = function (name, parameters) {
11204		if(php.method_exists(this,'format'+name)) {
11205			return php.call_user_func_array([this,'format'+name],parameters);
11206		}
11207		else {
11208			return parent.call(name,parameters);
11209		}
11210	};
11211/**
11212 * Formats a value based on the given type.
11213 * @param {Mixed} value the value to be formatted
11214 * @param {String} type the data type. This must correspond to a format method available in CFormatter.
11215 * For example, we can use 'text' here because there is method named {@link formatText}.
11216 * @returns {String} the formatted data
11217 */
11218Yii.CFormatter.prototype.format = function (value, type) {
11219		var method;
11220		method='format'+php.ucfirst(type);
11221		if(php.method_exists(this,method)) {
11222			return this[method](value);
11223		}
11224		else {
11225			throw new Yii.CException(Yii.t('yii','Unknown type "{type}".',{'{type}':type}));
11226		}
11227	};
11228/**
11229 * Formats the value as is without any formatting.
11230 * This method simply returns back the parameter without any format.
11231 * @param {Mixed} value the value to be formatted
11232 * @returns {String} the formatted result
11233 */
11234Yii.CFormatter.prototype.formatRaw = function (value) {
11235		return value;
11236	};
11237/**
11238 * Formats the value as a HTML-encoded plain text.
11239 * @param {Mixed} value the value to be formatted
11240 * @returns {String} the formatted result
11241 */
11242Yii.CFormatter.prototype.formatText = function (value) {
11243		return Yii.CHtml.encode(value);
11244	};
11245/**
11246 * Formats the value as a HTML-encoded plain text and converts newlines with HTML br tags.
11247 * @param {Mixed} value the value to be formatted
11248 * @returns {String} the formatted result
11249 */
11250Yii.CFormatter.prototype.formatNtext = function (value) {
11251		return php.nl2br(Yii.CHtml.encode(value));
11252	};
11253/**
11254 * Formats the value as HTML text without any encoding.
11255 * @param {Mixed} value the value to be formatted
11256 * @returns {String} the formatted result
11257 */
11258Yii.CFormatter.prototype.formatHtml = function (value) {
11259		return this.getHtmlPurifier().purify(value);
11260	};
11261/**
11262 * Formats the value as a date.
11263 * @param {Mixed} value the value to be formatted
11264 * @returns {String} the formatted result
11265 * @see dateFormat
11266 */
11267Yii.CFormatter.prototype.formatDate = function (value) {
11268		return php.date(this.dateFormat,value);
11269	};
11270/**
11271 * Formats the value as a time.
11272 * @param {Mixed} value the value to be formatted
11273 * @returns {String} the formatted result
11274 * @see timeFormat
11275 */
11276Yii.CFormatter.prototype.formatTime = function (value) {
11277		return php.date(this.timeFormat,value);
11278	};
11279/**
11280 * Formats the value as a date and time.
11281 * @param {Mixed} value the value to be formatted
11282 * @returns {String} the formatted result
11283 * @see datetimeFormat
11284 */
11285Yii.CFormatter.prototype.formatDatetime = function (value) {
11286		return php.date(this.datetimeFormat,value);
11287	};
11288/**
11289 * Formats the value as a boolean.
11290 * @param {Mixed} value the value to be formatted
11291 * @returns {String} the formatted result
11292 * @see trueText
11293 * @see falseText
11294 */
11295Yii.CFormatter.prototype.formatBoolean = function (value) {
11296		return value ? this.booleanFormat[1] : this.booleanFormat[0];
11297	};
11298/**
11299 * Formats the value as a mailto link.
11300 * @param {Mixed} value the value to be formatted
11301 * @returns {String} the formatted result
11302 */
11303Yii.CFormatter.prototype.formatEmail = function (value) {
11304		return Yii.CHtml.mailto(value);
11305	};
11306/**
11307 * Formats the value as an image tag.
11308 * @param {Mixed} value the value to be formatted
11309 * @returns {String} the formatted result
11310 */
11311Yii.CFormatter.prototype.formatImage = function (value) {
11312		return Yii.CHtml.image(value);
11313	};
11314/**
11315 * Formats the value as a hyperlink.
11316 * @param {Mixed} value the value to be formatted
11317 * @returns {String} the formatted result
11318 */
11319Yii.CFormatter.prototype.formatUrl = function (value) {
11320		var url;
11321		url=value;
11322		if(php.strpos(url,'http://')!==0 && php.strpos(url,'https://')!==0) {
11323			url='http://'+url;
11324		}
11325		return Yii.CHtml.link(Yii.CHtml.encode(value),url);
11326	};
11327/**
11328 * Formats the value as a number using PHP number_format() function.
11329 * @param {Mixed} value the value to be formatted
11330 * @returns {String} the formatted result
11331 * @see numberFormat
11332 */
11333Yii.CFormatter.prototype.formatNumber = function (value) {
11334		return php.number_format(value,this.numberFormat['decimals'],this.numberFormat['decimalSeparator'],this.numberFormat['thousandSeparator']);
11335	};
11336/**
11337 * @returns {Yii.CHtmlPurifier} the HTML purifier instance
11338 */
11339Yii.CFormatter.prototype.getHtmlPurifier = function () {
11340		if(this._htmlPurifier===null) {
11341			this._htmlPurifier=new Yii.CHtmlPurifier();
11342		}
11343		return this._htmlPurifier;
11344	}/*global Yii, php, $, jQuery, alert, clearInterval, clearTimeout, document, event, frames, history, Image, location, name, navigator, Option, parent, screen, setInterval, setTimeout, window, XMLHttpRequest */
11345/**
11346 * CTimestamp represents a timestamp.
11347 * 
11348 * Part of this class was adapted from the ADOdb Date Library
11349 * {@link http://phplens.com/phpeverywhere/ ADOdb abstraction library}.
11350 * The original source code was released under both BSD and GNU Lesser GPL
11351 * library license, with the following copyright notice:
11352 *     Copyright (c) 2000, 2001, 2002, 2003, 2004 John Lim
11353 *     All rights reserved.
11354 * 
11355 * This class is provided to support UNIX timestamp that is beyond the range
11356 * of 1901-2038 on Unix and1970-2038 on Windows. Except {@link getTimestamp},
11357 * all other methods in this class can work with the extended timestamp range.
11358 * For {@link getTimestamp}, because it is merely a wrapper of
11359 * {@link mktime http://php.net/manual/en/function.mktime.php}, it may still
11360 * be subject to the limit of timestamp range on certain platforms. Please refer
11361 * to the PHP manual for more information.
11362 * 
11363 * @originalAuthor Wei Zhuo <weizhuo[at]gmail[dot]com>
11364 * @version $Id: CTimestamp.php 3046 2011-03-12 01:48:15Z qiang.xue $
11365 * @package system.utils
11366 * @since 1.0
11367 * @author Charles Pick
11368 * @class
11369 */
11370Yii.CTimestamp = {
11371};
11372/**
11373 * Gets day of week, 0 = Sunday,... 6=Saturday.
11374 * Algorithm from PEAR::Date_Calc
11375 * @param {Integer} year year
11376 * @param {Integer} month month
11377 * @param {Integer} day day
11378 * @returns {Integer} day of week
11379 */
11380Yii.CTimestamp.getDayofWeek = function (year, month, day) {
11381		var greg_correction;
11382		/*
11383		Pope Gregory removed 10 days - October 5 to October 14 - from the year 1582 and
11384		proclaimed that from that time onwards 3 days would be dropped from the calendar
11385		every 400 years.
11386		Thursday, October 4, 1582 (Julian) was followed immediately by Friday, October 15, 1582 (Gregorian).
11387		*/
11388		if (year <= 1582) {
11389			if (year < 1582 || (year == 1582 && (month < 10 || (month == 10 && day < 15)))) {
11390				greg_correction = 3;
11391			}
11392			else {
11393				greg_correction = 0;
11394			}
11395		}
11396		else {
11397			greg_correction = 0;
11398		}
11399		if(month > 2) {
11400		    month -= 2;
11401		}
11402		else {
11403		    month += 10;
11404		    year--;
11405		}
11406		day = php.floor((13 * month - 1) / 5) +
11407		        day + (year % 100) +
11408		        php.floor((year % 100) / 4) +
11409		        php.floor((year / 100) / 4) - 2 *
11410		        php.floor(year / 100) + 77 + greg_correction;
11411		return day - 7 * php.floor(day / 7);
11412	};
11413/**
11414 * Checks for leap year, returns true if it is. No 2-digit year check. Also
11415 * handles julian calendar correctly.
11416 * @param {Integer} year year to check
11417 * @returns {Boolean} true if is leap year
11418 */
11419Yii.CTimestamp.isLeapYear = function (year) {
11420		year = this.digitCheck(year);
11421		if (year % 4 !== 0) {
11422			return false;
11423		}
11424		if (year % 400 === 0) {
11425			return true;
11426		}
11427		// if gregorian calendar (>1582), century not-divisible by 400 is not leap
11428		else if (year > 1582 && year % 100 === 0 ) {
11429			return false;
11430		}
11431		return true;
11432	};
11433/**
11434 * Fix 2-digit years. Works for any century.
11435 * Assumes that if 2-digit is more than 30 years in future, then previous century.
11436 * @param {Integer} y year
11437 * @returns {Integer} change two digit year into multiple digits
11438 */
11439Yii.CTimestamp.digitCheck = function (y) {
11440		var yr, century, c1, c0;
11441		if (y < 100){
11442			yr = Number(php.date("Y"));
11443			century = Number((yr /100));
11444			if (yr%100 > 50) {
11445				c1 = century + 1;
11446				c0 = century;
11447			} else {
11448				c1 = century;
11449				c0 = century - 1;
11450			}
11451			c1 *= 100;
11452			// if 2-digit year is less than 30 years in future, set it to this century
11453			// otherwise if more than 30 years in future, then we set 2-digit year to the prev century.
11454			if ((y + c1) < yr+30) { y = y + c1;
11455		}
11456			else { y = y + c0*100;
11457		}
11458		}
11459		return y;
11460	};
11461/**
11462 * Returns 4-digit representation of the year.
11463 * @param {Integer} y year
11464 * @returns {Integer} 4-digit representation of the year
11465 */
11466Yii.CTimestamp.get4DigitYear = function (y) {
11467		return this.digitCheck(y);
11468	};
11469/**
11470 * @returns {Integer} get local time zone offset from GMT
11471 */
11472Yii.CTimestamp.getGMTDiff = function () {
11473		var TZ;
11474		if (TZ !== undefined) { return TZ; }
11475		TZ = php.mktime(0,0,0,1,2,1970) - php.gmmktime(0,0,0,1,2,1970);
11476		return TZ;
11477	};
11478/**
11479 * Returns the getdate() array.
11480 * @param {Integer} d original date timestamp. False to use the current timestamp.
11481 * @param {Boolean} fast false to compute the day of the week, default is true
11482 * @param {Boolean} gmt true to calculate the GMT dates (ignored for now)
11483 * @returns {Array} an array with date info.
11484 */
11485Yii.CTimestamp.getDate = function (d, fast, gmt) {
11486		var tz, result;
11487		if (d === undefined) {
11488			d = false;
11489		}
11490		if (fast === undefined) {
11491			fast = false;
11492		}
11493		if (gmt === undefined) {
11494			gmt = false;
11495		}
11496		result = php.getdate(d);
11497		
11498		return result;
11499	};
11500/**
11501 * Checks to see if the year, month, day are valid combination.
11502 * @param {Integer} y year
11503 * @param {Integer} m month
11504 * @param {Integer} d day
11505 * @returns {Boolean} true if valid date, semantic check only.
11506 */
11507Yii.CTimestamp.isValidDate = function (y, m, d) {
11508		return php.checkdate(m, d, y);
11509	};
11510/**
11511 * Checks to see if the hour, minute and second are valid.
11512 * @param {Integer} h hour
11513 * @param {Integer} m minute
11514 * @param {Integer} s second
11515 * @param {Boolean} hs24 whether the hours should be 0 through 23 (default) or 1 through 12.
11516 * @returns {Boolean} true if valid date, semantic check only.
11517 * @since 1.0.5
11518 */
11519Yii.CTimestamp.isValidTime = function (h, m, s, hs24) {
11520		if (hs24 === undefined) {
11521			hs24 = true;
11522		}
11523		if(hs24 && (h < 0 || h > 23) || !hs24 && (h < 1 || h > 12)) {
11524			return false;
11525		}
11526		if(m > 59 || m < 0) {
11527			return false;
11528		}
11529		if(s > 59 || s < 0) {
11530			return false;
11531		}
11532		return true;
11533	};
11534/**
11535 * Formats a timestamp to a date string.
11536 * @param {String} fmt format pattern
11537 * @param {Integer} d timestamp
11538 * @param {Boolean} is_gmt whether this is a GMT timestamp
11539 * @returns {String} formatted date based on timestamp $d
11540 */
11541Yii.CTimestamp.formatDate = function (fmt, d, is_gmt) {
11542		var _day_power, arr, year, month, day, hour, min, secs, max, dates, i, gmt, d10, hh;
11543		if (d === undefined) {
11544			d = false;
11545		}
11546		if (is_gmt === undefined) {
11547			is_gmt = false;
11548		}
11549		if (d === false) {
11550			return (is_gmt)? php.gmdate(fmt): php.date(fmt);
11551		}
11552		// check if number in 32-bit signed range
11553		if ((php.abs(d) <= 0x7FFFFFFF))	{
11554			// if windows, must be +ve integer
11555			if (d >= 0) {
11556				return (is_gmt)? php.gmdate(fmt,d): php.date(fmt,d);
11557			}
11558		}
11559		_day_power = 86400;
11560		arr = this.getDate(d,true,is_gmt);
11561		year = arr.year;
11562		month = arr.mon;
11563		day = arr.mday;
11564		hour = arr.hours;
11565		min = arr.minutes;
11566		secs = arr.seconds;
11567		max = php.strlen(fmt);
11568		dates = '';
11569		/*
11570			at this point, we have the following integer vars to manipulate:
11571			$year, $month, $day, $hour, $min, $secs
11572		*/
11573		for (i=0; i < max; i++)
11574		{
11575			switch(fmt[i])
11576			{
11577				case 'T':
11578					dates += php.date('T');
11579					break;
11580				// YEAR
11581				case 'L':
11582					dates += arr.leap ? '1' : '0';
11583					break;
11584				case 'r': // Thu, 21 Dec 2000 16:01:07 +0200
11585					// 4.3.11 uses '04 Jun 2004'
11586					// 4.3.8 uses  ' 4 Jun 2004'
11587					dates += php.gmdate('D',_day_power*(3+this.getDayOfWeek(year,month,day)))+', ' + (day<10?'0'+day:day) + ' '+php.date('M',php.mktime(0,0,0,month,2,1971))+' '+year+' ';
11588					if (hour < 10) {
11589						dates += '0'+hour;
11590					}
11591					else {
11592						dates += hour;
11593					}
11594					if (min < 10) {
11595						dates += ':0'+min;
11596					}
11597					else {
11598						dates += ':'+min;
11599					}
11600					if (secs < 10) {
11601						dates += ':0'+secs;
11602					}
11603					else {
11604						dates += ':'+secs;
11605					}
11606					gmt = this.getGMTDiff();
11607					dates += php.sprintf(' %s%04d',(gmt<=0)?'+':'-',php.abs(gmt)/36);
11608					break;
11609				case 'Y':
11610					dates += year;
11611					break;
11612				case 'y':
11613					dates += year.slice(php.strlen(year)-2, 2);
11614					break;
11615				// MONTH
11616				case 'm':
11617					if (month<10) {
11618						dates += '0'+month;
11619					}
11620					else {
11621						dates += month;
11622					}
11623					break;
11624				case 'Q':
11625					dates += (month+3)>>2;
11626					break;
11627				case 'n':
11628					dates += month;
11629					break;
11630				case 'M':
11631					dates += php.date('M',php.mktime(0,0,0,month,2,1971));
11632					break;
11633				case 'F':
11634					dates += php.date('F',php.mktime(0,0,0,month,2,1971));
11635					break;
11636				// DAY
11637				case 't':
11638					dates += arr.ndays;
11639					break;
11640				case 'z':
11641					dates += arr.yday;
11642					break;
11643				case 'w':
11644					dates += this.getDayOfWeek(year,month,day);
11645					break;
11646				case 'l':
11647					dates += php.gmdate('l',_day_power*(3+this.getDayOfWeek(year,month,day)));
11648					break;
11649				case 'D':
11650					dates += php.gmdate('D',_day_power*(3+this.getDayOfWeek(year,month,day)));
11651					break;
11652				case 'j':
11653					dates += day;
11654					break;
11655				case 'd':
11656					if (day<10) {
11657						dates += '0'+day;
11658					}
11659					else {
11660						dates += day;
11661					}
11662					break;
11663				case 'S':
11664					d10 = day % 10;
11665					if (d10 == 1) {
11666						dates += 'st';
11667					}
11668					else if (d10 == 2 && day != 12) {
11669						dates += 'nd';
11670					}
11671					else if (d10 == 3) {
11672						dates += 'rd';
11673					}
11674					else {
11675						dates += 'th';
11676					}
11677					break;
11678				// HOUR
11679				case 'Z':
11680					dates += (is_gmt) ? 0 : -this.getGMTDiff();
11681					break;
11682				case 'O':
11683					gmt = (is_gmt) ? 0 : this.getGMTDiff();
11684					dates += php.sprintf('%s%04d',(gmt<=0)?'+':'-',php.abs(gmt)/36);
11685					break;
11686				case 'H':
11687					if (hour < 10) {
11688						dates += '0'+hour;
11689					}
11690					else {
11691						dates += hour;
11692					}
11693					break;
11694				case 'h':
11695					if (hour > 12) {
11696						hh = hour - 12;
11697					}
11698					else {
11699						if (hour === 0) {
11700							hh = '12';
11701						}
11702						else {
11703							hh = hour;
11704						}
11705					}
11706					if (hh < 10) {
11707						dates += '0'+hh;
11708					}
11709					else {
11710						dates += hh;
11711					}
11712					break;
11713				case 'G':
11714					dates += hour;
11715					break;
11716				case 'g':
11717					if (hour > 12) {
11718						hh = hour - 12;
11719					}
11720					else {
11721						if (hour === 0) {
11722							hh = '12';
11723						}
11724						else {
11725							hh = hour;
11726						}
11727					}
11728					dates += hh;
11729					break;
11730				// MINUTES
11731				case 'i':
11732					if (min < 10) {
11733						dates += '0'+min;
11734					}
11735					else {
11736						dates += min;
11737					}
11738					break;
11739			// SECONDS
11740			case 'U':
11741				dates += d;
11742				break;
11743			case 's':
11744				if (secs < 10) {
11745					dates += '0'+secs;
11746				}
11747				else {
11748					dates += secs;
11749				}
11750				break;
11751			// AM/PM
11752			// Note 00:00 to 11:59 is AM, while 12:00 to 23:59 is PM
11753			case 'a':
11754				if (hour>=12) {
11755					dates += 'pm';
11756				}
11757				else {
11758					dates += 'am';
11759				}
11760				break;
11761				case 'A':
11762					if (hour>=12) {
11763						dates += 'PM';
11764					}
11765				else {
11766					dates += 'AM';
11767				}
11768				break;
11769			default:
11770				dates += fmt[i];
11771				break;
11772			// ESCAPE
11773			case "\\":
11774				i++;
11775				if (i < max) {
11776					dates += fmt[i];
11777				}
11778				break;
11779			}
11780		}
11781		return dates;
11782	};
11783/**
11784 * Generates a timestamp.
11785 * This is the same as the PHP function {@link mktime http://php.net/manual/en/function.mktime.php}.
11786 * @param {Integer} hr hour
11787 * @param {Integer} min minute
11788 * @param {Integer} sec second
11789 * @param {Integer} mon month
11790 * @param {Integer} day day
11791 * @param {Integer} year year
11792 * @param {Boolean} is_gmt whether this is GMT time. If true, gmmktime() will be used.
11793 * @returns {Integer|float} a timestamp given a local time.
11794 */
11795Yii.CTimestamp.getTimestamp = function (hr, min, sec, mon, day, year, is_gmt) {
11796	if (mon === undefined) {
11797		mon = false;
11798	}
11799	if (day === undefined) {
11800		day = false;
11801	}
11802	if (year === undefined) {
11803		year = false;
11804	}
11805	if (is_gmt === undefined) {
11806		is_gmt = false;
11807	}
11808	if (mon === false) {
11809		return is_gmt? php.gmmktime(hr,min,sec): php.mktime(hr,min,sec);
11810	}
11811	return is_gmt ? php.gmmktime(hr,min,sec,mon,day,year) : php.mktime(hr,min,sec,mon,day,year);
11812};/*global Yii, php, $, jQuery, alert, clearInterval, clearTimeout, document, event, frames, history, Image, location, name, navigator, Option, parent, screen, setInterval, setTimeout, window, XMLHttpRequest */
11813/**
11814 * CBooleanValidator validates that the attribute value is either {@link trueValue}  or {@link falseValue}.
11815 * 
11816 * @originalAuthor Qiang Xue <qiang.xue@gmail.com>
11817 * @version $Id: CBooleanValidator.php 3120 2011-03-25 01:50:48Z qiang.xue $
11818 * @package system.validators
11819 * @since 1.0.10
11820 * @author Charles Pick
11821 * @class
11822 * @extends Yii.CValidator
11823 */
11824Yii.CBooleanValidator = function CBooleanValidator() {
11825};
11826Yii.CBooleanValidator.prototype = new Yii.CValidator();
11827Yii.CBooleanValidator.prototype.constructor =  Yii.CBooleanValidator;
11828/**
11829 * @var {Mixed} the value representing true status. Defaults to '1'.
11830 */
11831Yii.CBooleanValidator.prototype.trueValue = '1';
11832/**
11833 * @var {Mixed} the value representing false status. Defaults to '0'.
11834 */
11835Yii.CBooleanValidator.prototype.falseValue = '0';
11836/**
11837 * @var {Boolean} whether the comparison to {@link trueValue} and {@link falseValue} is strict.
11838 * When this is true, the attribute value and type must both match those of {@link trueValue} or {@link falseValue}.
11839 * Defaults to false, meaning only the value needs to be matched.
11840 */
11841Yii.CBooleanValidator.prototype.strict = false;
11842/**
11843 * @var {Boolean} whether the attribute value can be null or empty. Defaults to true,
11844 * meaning that if the attribute is empty, it is considered valid.
11845 */
11846Yii.CBooleanValidator.prototype.allowEmpty = true;
11847/**
11848 * Validates the attribute of the object.
11849 * If there is any error, the error message is added to the object.
11850 * @param {Yii.CModel} object the object being validated
11851 * @param {String} attribute the attribute being validated
11852 */
11853Yii.CBooleanValidator.prototype.validateAttribute = function (object, attribute) {
11854		var value, message;
11855		value=object.get(attribute);
11856		if(this.allowEmpty && this.isEmpty(value)) {
11857			return;
11858		}
11859		if(!this.strict && value!=this.trueValue && value!=this.falseValue || this.strict && value!==this.trueValue && value!==this.falseValue) {
11860			message=this.message!==null?this.message:Yii.t('yii','{attribute} must be either {true} or {false}.');
11861			this.addError(object,attribute,message,{
11862				'{true}':this.trueValue,
11863				'{false}':this.falseValue
11864			});
11865		}
11866	};
11867/*global Yii, php, $, jQuery, alert, clearInterval, clearTimeout, document, event, frames, history, Image, location, name, navigator, Option, parent, screen, setInterval, setTimeout, window, XMLHttpRequest */
11868/**
11869 * CEmailValidator validates that the attribute value is a valid email address.
11870 * 
11871 * @originalAuthor Qiang Xue <qiang.xue@gmail.com>
11872 * @version $Id: CEmailValidator.php 3120 2011-03-25 01:50:48Z qiang.xue $
11873 * @package system.validators
11874 * @since 1.0
11875 * @author Charles Pick
11876 * @class
11877 * @extends Yii.CValidator
11878 */
11879Yii.CEmailValidator = function CEmailValidator() {
11880};
11881Yii.CEmailValidator.prototype = new Yii.CValidator();
11882Yii.CEmailValidator.prototype.constructor =  Yii.CEmailValidator;
11883/**
11884 * @var {String} the regular expression used to validate the attribute value.
11885 * @see http://www.regular-expressions.info/email.html
11886 */
11887Yii.CEmailValidator.prototype.pattern = '^[a-zA-Z0-9!#$%&\'*+\\/=?^_`{|}~-]+(?:\\.[a-zA-Z0-9!#$%&\'*+\\/=?^_`{|}~-]+)*@(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\\.)+[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?$';
11888/**
11889 * @var {String} the regular expression used to validate email addresses with the name part.
11890 * This property is used only when {@link allowName} is true.
11891 * @since 1.0.5
11892 * @see allowName
11893 */
11894Yii.CEmailValidator.prototype.fullPattern = '^[^@]*<[a-zA-Z0-9!#$%&\'*+\\/=?^_`{|}~-]+(?:\\.[a-zA-Z0-9!#$%&\'*+\\/=?^_`{|}~-]+)*@(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\\.)+[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?>$';
11895/**
11896 * @var {Boolean} whether to allow name in the email address (e.g. "Qiang Xue <qiang.xue@gmail.com>"). Defaults to false.
11897 * @since 1.0.5
11898 * @see fullPattern
11899 */
11900Yii.CEmailValidator.prototype.allowName = false;
11901
11902/**
11903 * @var {Boolean} whether the attribute value can be null or empty. Defaults to true,
11904 * meaning that if the attribute is empty, it is considered valid.
11905 */
11906Yii.CEmailValidator.prototype.allowEmpty = true;
11907/**
11908 * Validates the attribute of the object.
11909 * If there is any error, the error message is added to the object.
11910 * @param {Yii.CModel} object the object being validated
11911 * @param {String} attribute the attribute being validated
11912 */
11913Yii.CEmailValidator.prototype.validateAttribute = function (object, attribute) {
11914		var value, message;
11915		
11916		value=object[attribute];
11917		if(this.allowEmpty && this.isEmpty(value)) {
11918			return;
11919		}
11920		if(!this.validateValue(value)) {
11921			message=this.message!==null?this.message:Yii.t('yii','{attribute} is not a valid email address.');
11922			
11923			this.addError(object,attribute,message);
11924		}
11925	};
11926/**
11927 * Validates a static value to see if it is a valid email.
11928 * Note that this method does not respect {@link allowEmpty} property.
11929 * This method is provided so that you can call it directly without going through the model validation rule mechanism.
11930 * @param {Mixed} value the value to be validated
11931 * @returns {Boolean} whether the value is a valid email
11932 * @since 1.1.1
11933 */
11934Yii.CEmailValidator.prototype.validateValue = function (value) {
11935	
11936		var valid, re, reFull;
11937		re = new RegExp(this.pattern);
11938		reFull = new RegExp(this.fullPattern);
11939		
11940		valid=typeof(value) === 'string' && (re.exec(value) || this.allowName && reFull.exec(value));
11941		
11942		return valid;
11943	};
11944/*global Yii, php, $, jQuery, alert, clearInterval, clearTimeout, document, event, frames, history, Image, location, name, navigator, Option, parent, screen, setInterval, setTimeout, window, XMLHttpRequest */
11945/**
11946 * CInlineValidator represents a validator which is defined as a method in the object being validated.
11947 * 
11948 * @originalAuthor Qiang Xue <qiang.xue@gmail.com>
11949 * @version $Id: CInlineValidator.php 2799 2011-01-01 19:31:13Z qiang.xue $
11950 * @package system.validators
11951 * @since 1.0
11952 * @author Charles Pick
11953 * @class
11954 * @extends Yii.CValidator
11955 */
11956Yii.CInlineValidator = function CInlineValidator() {
11957};
11958Yii.CInlineValidator.prototype = new Yii.CValidator();
11959Yii.CInlineValidator.prototype.constructor =  Yii.CInlineValidator;
11960/**
11961 * @var {String} the name of the validation method defined in the active record class
11962 */
11963Yii.CInlineValidator.prototype.method = null;
11964/**
11965 * @var {Array} additional parameters that are passed to the validation method
11966 */
11967Yii.CInlineValidator.prototype.params = null;
11968/**
11969 * Validates the attribute of the object.
11970 * If there is any error, the error message is added to the object.
11971 * @param {Yii.CModel} object the object being validated
11972 * @param {String} attribute the attribute being validated
11973 */
11974Yii.CInlineValidator.prototype.validateAttribute = function (object, attribute) {
11975		var method;
11976		method=this.method;
11977		object[method](attribute,this.params);
11978};/*global Yii, php, $, jQuery, alert, clearInterval, clearTimeout, document, event, frames, history, Image, location, name, navigator, Option, parent, screen, setInterval, setTimeout, window, XMLHttpRequest */
11979/**
11980 * CNumberValidator validates that the attribute value is a number.
11981 * 
11982 * @originalAuthor Qiang Xue <qiang.xue@gmail.com>
11983 * @version $Id: CNumberValidator.php 3120 2011-03-25 01:50:48Z qiang.xue $
11984 * @package system.validators
11985 * @since 1.0
11986 * @author Charles Pick
11987 * @class
11988 * @extends Yii.CValidator
11989 */
11990Yii.CNumberValidator = function CNumberValidator() {
11991};
11992Yii.CNumberValidator.prototype = new Yii.CValidator();
11993Yii.CNumberValidator.prototype.constructor =  Yii.CNumberValidator;
11994/**
11995 * @var {Boolean} whether the attribute value can only be an integer. Defaults to false.
11996 */
11997Yii.CNumberValidator.prototype.integerOnly = false;
11998/**
11999 * @var {Boolean} whether the attribute value can be null or empty. Defaults to true,
12000 * meaning that if the attribute is empty, it is considered valid.
12001 */
12002Yii.CNumberValidator.prototype.allowEmpty = true;
12003/**
12004 * @var {Integer|float} upper limit of the number. Defaults to null, meaning no upper limit.
12005 */
12006Yii.CNumberValidator.prototype.max = null;
12007/**
12008 * @var {Integer|float} lower limit of the number. Defaults to null, meaning no lower limit.
12009 */
12010Yii.CNumberValidator.prototype.min = null;
12011/**
12012 * @var {String} user-defined error message used when the value is too big.
12013 */
12014Yii.CNumberValidator.prototype.tooBig = null;
12015/**
12016 * @var {String} user-defined error message used when the value is too small.
12017 */
12018Yii.CNumberValidator.prototype.tooSmall = null;
12019/**
12020 * @var {String} the regular expression for matching integers.
12021 * @since 1.1.7
12022 */
12023Yii.CNumberValidator.prototype.integerPattern = '^\\s*[+-]?\\d+\\s*$';
12024/**
12025 * @var {String} the regular expression for matching numbers.
12026 * @since 1.1.7
12027 */
12028Yii.CNumberValidator.prototype.numberPattern = '^\\s*[-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?\\s*$';
12029/**
12030 * Validates the attribute of the object.
12031 * If there is any error, the error message is added to the object.
12032 * @param {Yii.CModel} object the object being validated
12033 * @param {String} attribute the attribute being validated
12034 */
12035Yii.CNumberValidator.prototype.validateAttribute = function (object, attribute) {
12036	var value, message, intRe = new RegExp(this.integerPattern), numRe = new RegExp(this.numberPattern);
12037	value=String(object[attribute]);
12038	if(this.allowEmpty && this.isEmpty(value)) {
12039		return;
12040	}
12041	if(this.integerOnly) {
12042		if(!intRe.exec(value)) {
12043			message=this.message!==null?this.message:Yii.t('yii','{attribute} must be an integer.');
12044			this.addError(object,attribute,message);
12045		}
12046	}
12047	else {
12048		if(!numRe.exec(value)) {
12049			message=this.message!==null?this.message:Yii.t('yii','{attribute} must be a number.');
12050			this.addError(object,attribute,message);
12051		}
12052	}
12053	if(this.min!==null && value<this.min) {
12054		message=this.tooSmall!==null?this.tooSmall:Yii.t('yii','{attribute} is too small (minimum is {min}).');
12055		this.addError(object,attribute,message,{'{min}':this.min});
12056	}
12057	if(this.max!==null && value>this.max) {
12058		message=this.tooBig!==null?this.tooBig:Yii.t('yii','{attribute} is too big (maximum is {max}).');
12059		this.addError(object,attribute,message,{'{max}':this.max});
12060	}
12061};
12062/*global Yii, php, $, jQuery, alert, clearInterval, clearTimeout, document, event, frames, history, Image, location, name, navigator, Option, parent, screen, setInterval, setTimeout, window, XMLHttpRequest */
12063/**
12064 * CRangeValidator validates that the attribute value is among the list (specified via {@link range}).
12065 * You may invert the validation logic with help of the {@link not} property (available since 1.1.5).
12066 * 
12067 * @originalAuthor Qiang Xue <qiang.xue@gmail.com>
12068 * @version $Id: CRangeValidator.php 3120 2011-03-25 01:50:48Z qiang.xue $
12069 * @package system.validators
12070 * @since 1.0
12071 * @author Charles Pick
12072 * @class
12073 * @extends Yii.CValidator
12074 */
12075Yii.CRangeValidator = function CRangeValidator() {
12076};
12077Yii.CRangeValidator.prototype = new Yii.CValidator();
12078Yii.CRangeValidator.prototype.constructor =  Yii.CRangeValidator;
12079/**
12080 * @var {Array} list of valid values that the attribute value should be among
12081 */
12082Yii.CRangeValidator.prototype.range = null;
12083/**
12084 * @var {Boolean} whether the comparison is strict (both type and value must be the same)
12085 */
12086Yii.CRangeValidator.prototype.strict = false;
12087/**
12088 * @var {Boolean} whether the attribute value can be null or empty. Defaults to true,
12089 * meaning that if the attribute is empty, it is considered valid.
12090 */
12091Yii.CRangeValidator.prototype.allowEmpty = true;
12092/**
12093 * @var {Boolean} whether to invert the validation logic. Defaults to false. If set to true,
12094 * the attribute value should NOT be among the list of values defined via {@link range}.
12095 * @since 1.1.5
12096 */
12097Yii.CRangeValidator.prototype.not = false;
12098/**
12099 * Validates the attribute of the object.
12100 * If there is any error, the error message is added to the object.
12101 * @param {Yii.CModel} object the object being validated
12102 * @param {String} attribute the attribute being validated
12103 */
12104Yii.CRangeValidator.prototype.validateAttribute = function (object, attribute) {
12105	var value, message;
12106	value=object.get(attribute);
12107	
12108	if(this.allowEmpty && this.isEmpty(value)) {
12109		return;
12110	}
12111	if(Object.prototype.toString.call(this.range) !== '[object Array]') {
12112		throw new Yii.CException(Yii.t('yii','The "range" property must be specified with a list of values.'));
12113	}
12114	if(!this.not && !php.in_array(value,this.range,this.strict))
12115	{
12116		message=this.message!==null?this.message:Yii.t('yii','{attribute} is not in the list.');
12117		this.addError(object,attribute,message);
12118	}
12119	else if(this.not && php.in_array(value,this.range,this.strict))
12120	{
12121		message=this.message!==null?this.message:Yii.t('yii','{attribute} is in the list.');
12122		this.addError(object,attribute,message);
12123	}
12124};
12125/*global Yii, php, $, jQuery, alert, clearInterval, clearTimeout, document, event, frames, history, Image, location, name, navigator, Option, parent, screen, setInterval, setTimeout, window, XMLHttpRequest */
12126/**
12127 * CRequiredValidator validates that the specified attribute does not have null or empty value.
12128 * 
12129 * @originalAuthor Qiang Xue <qiang.xue@gmail.com>
12130 * @version $Id: CRequiredValidator.php 3157 2011-04-02 19:21:06Z qiang.xue $
12131 * @package system.validators
12132 * @since 1.0
12133 * @author Charles Pick
12134 * @class
12135 * @extends Yii.CValidator
12136 */
12137Yii.CRequiredValidator = function CRequiredValidator() {
12138};
12139Yii.CRequiredValidator.prototype = new Yii.CValidator();
12140Yii.CRequiredValidator.prototype.constructor =  Yii.CRequiredValidator;
12141/**
12142 * @var {Mixed} the desired value that the attribute must have.
12143 * If this is null, the validator will validate that the specified attribute does not have null or empty value.
12144 * If this is set as a value that is not null, the validator will validate that
12145 * the attribute has a value that is the same as this property value.
12146 * Defaults to null.
12147 * @since 1.0.10
12148 */
12149Yii.CRequiredValidator.prototype.requiredValue = null;
12150/**
12151 * @var {Boolean} whether the comparison to {@link requiredValue} is strict.
12152 * When this is true, the attribute value and type must both match those of {@link requiredValue}.
12153 * Defaults to false, meaning only the value needs to be matched.
12154 * This property is only used when {@link requiredValue} is not null.
12155 * @since 1.0.10
12156 */
12157Yii.CRequiredValidator.prototype.strict = false; 
12158/**
12159 * Validates the attribute of the object.
12160 * If there is any error, the error message is added to the object.
12161 * @param {Yii.CModel} object the object being validated
12162 * @param {String} attribute the attribute being validated
12163 */
12164Yii.CRequiredValidator.prototype.validateAttribute = function (object, attribute) {
12165	var value, message;
12166	value=object.get(attribute);
12167	
12168	if(this.requiredValue!==null) {
12169		if(!this.strict && value!=this.requiredValue || this.strict && value!==this.requiredValue) {
12170			message=this.message!==null?this.message:Yii.t('yii','{attribute} must be {value}.',
12171				{'{value}':this.requiredValue});
12172			this.addError(object,attribute,message);
12173		}
12174	}
12175	else if(this.isEmpty(value,true)) {
12176		message=this.message!==null?this.message:Yii.t('yii','{attribute} cannot be blank.');
12177		this.addError(object,attribute,message);
12178	}
12179};
12180/*global Yii, php, $, jQuery, alert, clearInterval, clearTimeout, document, event, frames, history, Image, location, name, navigator, Option, parent, screen, setInterval, setTimeout, window, XMLHttpRequest */
12181/**
12182 * CTypeValidator verifies if the attribute is of the type specified by {@link type}.
12183 * 
12184 * The following data types are supported:
12185 * <ul>
12186 * <li><b>integer</b> A 32-bit signed integer data type.</li>
12187 * <li><b>float</b> A double-precision floating point number data type.</li>
12188 * <li><b>string</b> A string data type.</li>
12189 * <li><b>array</b> An array value. </li>
12190 * <li><b>date</b> A date data type.</li>
12191 * <li><b>time</b> A time data type (available since version 1.0.5).</li>
12192 * <li><b>datetime</b> A date and time data type (available since version 1.0.5).</li>
12193 * </ul>
12194 * 
12195 * For <b>date</b> type, the property {@link dateFormat}
12196 * will be used to determine how to parse the date string. If the given date
12197 * value doesn't follow the format, the attribute is considered as invalid.
12198 * 
12199 * Starting from version 1.1.7, we have a dedicated date validator {@link CDateValidator}.
12200 * Please consider using this validator to validate a date-typed value.
12201 * 
12202 * @originalAuthor Qiang Xue <qiang.xue@gmail.com>
12203 * @version $Id: CTypeValidator.php 3052 2011-03-12 14:27:07Z qiang.xue $
12204 * @package system.validators
12205 * @since 1.0
12206 * @author Charles Pick
12207 * @class
12208 * @extends Yii.CValidator
12209 */
12210Yii.CTypeValidator = function CTypeValidator() {
12211};
12212Yii.CTypeValidator.prototype = new Yii.CValidator();
12213Yii.CTypeValidator.prototype.constructor =  Yii.CTypeValidator;
12214/**
12215 * @var {String} the data type that the attribute should be. Defaults to 'string'.
12216 * Valid values include 'string', 'integer', 'float', 'array', 'date', 'time' and 'datetime'.
12217 * Note that 'time' and 'datetime' have been available since version 1.0.5.
12218 */
12219Yii.CTypeValidator.prototype.type = 'string';
12220/**
12221 * @var {String} the format pattern that the date value should follow. Defaults to 'MM/dd/yyyy'.
12222 * Please see {@link CDateTimeParser} for details about how to specify a date format.
12223 * This property is effective only when {@link type} is 'date'.
12224 */
12225Yii.CTypeValidator.prototype.dateFormat = 'MM/dd/yyyy';
12226/**
12227 * @var {String} the format pattern that the time value should follow. Defaults to 'hh:mm'.
12228 * Please see {@link CDateTimeParser} for details about how to specify a time format.
12229 * This property is effective only when {@link type} is 'time'.
12230 * @since 1.0.5
12231 */
12232Yii.CTypeValidator.prototype.timeFormat = 'hh:mm';
12233/**
12234 * @var {String} the format pattern that the datetime value should follow. Defaults to 'MM/dd/yyyy hh:mm'.
12235 * Please see {@link CDateTimeParser} for details about how to specify a datetime format.
12236 * This property is effective only when {@link type} is 'datetime'.
12237 * @since 1.0.5
12238 */
12239Yii.CTypeValidator.prototype.datetimeFormat = 'MM/dd/yyyy hh:mm';
12240/**
12241 * @var {Boolean} whether the attribute value can be null or empty. Defaults to true,
12242 * meaning that if the attribute is empty, it is considered valid.
12243 */
12244Yii.CTypeValidator.prototype.allowEmpty = true;
12245/**
12246 * Validates the attribute of the object.
12247 * If there is any error, the error message is added to the object.
12248 * @param {Yii.CModel} object the object being validated
12249 * @param {String} attribute the attribute being validated
12250 */
12251Yii.CTypeValidator.prototype.validateAttribute = function (object, attribute) {
12252		var value, valid, message;
12253		value=object.get(attribute);
12254		if(this.allowEmpty && this.isEmpty(value)) {
12255			return;
12256		}
12257		if(this.type==='integer') {
12258			valid=/^[\-+]?[0-9]+$/.exec(php.trim(value));
12259		}
12260		else if(this.type==='float') {
12261			valid=/^[\-+]?([0-9]*\.)?[0-9]+([eE][\-+]?[0-9]+)?$/.exec(php.trim(value));
12262		}
12263		else if(this.type==='date') {
12264			valid=Yii.CDateTimeParser.parse(value,this.dateFormat,{'month':1,'day':1,'hour':0,'minute':0,'second':0})!==false;
12265		}
12266	    else if(this.type==='time') {
12267			valid=Yii.CDateTimeParser.parse(value,this.timeFormat)!==false;
12268		}
12269	    else if(this.type==='datetime') {
12270			valid=Yii.CDateTimeParser.parse(value,this.datetimeFormat, {'month':1,'day':1,'hour':0,'minute':0,'second':0})!==false;
12271		}
12272		else if(this.type==='array') {
12273			valid=Object.prototype.toString.call(value) === '[object Array]';
12274		}
12275		else {
12276			return;
12277		}
12278		if(!valid)	{
12279			message=this.message!==null?this.message : Yii.t('yii','{attribute} must be {type}.');
12280			this.addError(object,attribute,message,{'{type}':this.type});
12281		}
12282	}/*global Yii, php, $, jQuery, alert, clearInterval, clearTimeout, document, event, frames, history, Image, location, name, navigator, Option, parent, screen, setInterval, setTimeout, window, XMLHttpRequest */
12283/**
12284 * CUrlValidator validates that the attribute value is a valid http or https URL.
12285 * 
12286 * @originalAuthor Qiang Xue <qiang.xue@gmail.com>
12287 * @version $Id: CUrlValidator.php 3120 2011-03-25 01:50:48Z qiang.xue $
12288 * @package system.validators
12289 * @since 1.0
12290 * @author Charles Pick
12291 * @class
12292 * @extends Yii.CValidator
12293 */
12294Yii.CUrlValidator = function CUrlValidator() {
12295	
12296};
12297Yii.CUrlValidator.prototype = new Yii.CValidator();
12298Yii.CUrlValidator.prototype.constructor =  Yii.CUrlValidator;
12299/**
12300 * @var {String} the regular expression used to validate the attribute value.
12301 * Since version 1.1.7 the pattern may contain a {schemes} token that will be replaced
12302 * by a regular expression which represents the {@see validSchemes}.
12303 */
12304Yii.CUrlValidator.prototype.pattern = '^{schemes}:\\/\\/(([A-Z0-9][A-Z0-9_-]*)(\\.[A-Z0-9][A-Z0-9_-]*)+)';
12305/**
12306 * @var {Array} list of URI schemes which should be considered valid. By default, http and https
12307 * are considered to be valid schemes.
12308 * @since 1.1.7
12309 */
12310Yii.CUrlValidator.prototype.validSchemes = ['http','https'];
12311/**
12312 * @var {String} the default URI scheme. If the input doesn't contain the scheme part, the default
12313 * scheme will be prepended to it (thus changing the input). Defaults to null, meaning a URL must
12314 * contain the scheme part.
12315 * @since 1.1.7
12316 */
12317Yii.CUrlValidator.prototype.defaultScheme = null;
12318/**
12319 * @var {Boolean} whether the attribute value can be null or empty. Defaults to true,
12320 * meaning that if the attribute is empty, it is considered valid.
12321 */
12322Yii.CUrlValidator.prototype.allowEmpty = true;
12323/**
12324 * Validates the attribute of the object.
12325 * If there is any error, the error message is added to the object.
12326 * @param {Yii.CModel} object the object being validated
12327 * @param {String} attribute the attribute being validated
12328 */
12329Yii.CUrlValidator.prototype.validateAttribute = function (object, attribute) {
12330		var value, message;
12331		value=object.get(attribute);
12332		if(this.allowEmpty && this.isEmpty(value)) {
12333			return;
12334		}
12335		if((value=this.validateValue(value))!==false) {
12336			object[attribute]=value;
12337		}
12338		else {
12339			message=this.message!==null?this.message:Yii.t('yii','{attribute} is not a valid URL.');
12340			this.addError(object,attribute,message);
12341		}
12342	};
12343/**
12344 * Validates a static value to see if it is a valid URL.
12345 * Note that this method does not respect {@link allowEmpty} property.
12346 * This method is provided so that you can call it directly without going through the model validation rule mechanism.
12347 * @param {Mixed} value the value to be validated
12348 * @returns {Mixed} false if the the value is not a valid URL, otherwise the possibly modified value ({@see defaultScheme})
12349 * @since 1.1.1
12350 */
12351Yii.CUrlValidator.prototype.validateValue = function (value) {
12352		var pattern, re;
12353		if(typeof(value) === 'string')	{
12354			if(this.defaultScheme!==null && php.strpos(value,'://')===false) {
12355				value=this.defaultScheme+'://'+value;
12356			}
12357			if(php.strpos(this.pattern,'{schemes}')!==false) {
12358				pattern=php.str_replace('{schemes}','('+this.validSchemes.join('|')+')',this.pattern);
12359			}
12360			else {
12361				pattern=this.pattern;
12362			}
12363			re = new RegExp(this.pattern,"i");
12364			if(re.exec(value)) {
12365				return value;
12366			}
12367		}
12368		return false;
12369	};
12370/* 
12371 * Original script by Josh Fraser (http://www.onlineaspect.com)
12372 * Continued by Jon Nylander, (jon at pageloom dot com)
12373 * According to both of us, you are absolutely free to do whatever 
12374 * you want with this code.
12375 * 
12376 * This code is  maintained at bitbucket.org as jsTimezoneDetect.
12377 */
12378
12379/**
12380 * Namespace to hold all the code for timezone detection.
12381 */
12382var jzTimezoneDetector = {};
12383
12384jzTimezoneDetector.HEMISPHERE_SOUTH = 'SOUTH';
12385jzTimezoneDetector.HEMISPHERE_NORTH = 'NORTH';
12386jzTimezoneDetector.HEMISPHERE_UNKNOWN = 'N/A';
12387jzTimezoneDetector.olson = {};
12388
12389/**
12390 * A simple object containing information of utc_offset, which olson timezone key to use, 
12391 * and if the timezone cares about daylight savings or not.
12392 * 
12393 * @constructor
12394 * @param {string} offset - for example '-11:00'
12395 * @param {string} olson_tz - the olson Identifier, such as "America/Denver"
12396 * @param {boolean} uses_dst - flag for whether the time zone somehow cares about daylight savings.
12397 */
12398jzTimezoneDetector.TimeZone = function (offset, olson_tz, uses_dst) {
12399	this.utc_offset = offset;
12400	this.olson_tz = olson_tz;
12401	this.uses_dst = uses_dst;
12402};
12403
12404/**
12405 * Prints out the result.
12406 * But before it does that, it calls this.ambiguity_check.
12407 */
12408jzTimezoneDetector.TimeZone.prototype.display = function() {
12409	this.ambiguity_check();
12410	var response_text = '<b>UTC-offset</b>: ' + this.utc_offset + '<br/>';
12411	response_text += '<b>Zoneinfo key</b>: ' + this.olson_tz + '<br/>';
12412	response_text += '<b>Zone uses DST</b>: ' + (this.uses_dst ? 'yes' : 'no') + '<br/>';
12413	
12414	return response_text;
12415};
12416
12417/**
12418 * Checks if a timezone has possible ambiguities. I.e timezones that are similar.
12419 * 
12420 * If the preliminary scan determines that we're in America/Denver. We double check
12421 * here that we're really there and not in America/Mazatlan.
12422 * 
12423 * This is done by checking known dates for when daylight savings start for different
12424 * timezones.
12425 */
12426jzTimezoneDetector.TimeZone.prototype.ambiguity_check = function() {
12427	var local_ambiguity_list = jzTimezoneDetector.olson.ambiguity_list[this.olson_tz];
12428	
12429	if (typeof(local_ambiguity_list) == 'undefined') {
12430		return;
12431	}
12432	
12433	var length = local_ambiguity_list.length;
12434	
12435	for (var i = 0; i < length; i++) {
12436		var tz = local_ambiguity_list[i];
12437
12438		if (jzTimezoneDetector.date_is_dst(jzTimezoneDetector.olson.dst_start_dates[tz])) {
12439			this.olson_tz = tz;
12440			return;
12441		}	
12442	}
12443};
12444
12445/**
12446 * Checks whether a given date is in daylight savings time.
12447 * 
12448 * If the date supplied is after june, we assume that we're checking
12449 * for southern hemisphere DST.
12450 * 
12451 * @param {Date} date
12452 * @returns {boolean}
12453 */
12454jzTimezoneDetector.date_is_dst = function (date) {
12455	var base_offset, date_offset;
12456	base_offset = ( (date.getMonth() > 5 ? jzTimezoneDetector.get_june_offset() : jzTimezoneDetector.get_january_offset()) );
12457	date_offset = jzTimezoneDetector.get_date_offset(date);
12458	
12459	return (base_offset - date_offset) !== 0;
12460};
12461
12462/** 
12463 * Gets the offset in minutes from UTC for a certain date.
12464 * 
12465 * @param date
12466 * @returns {number}
12467 */
12468jzTimezoneDetector.get_date_offset = function (date) {
12469	return -date.getTimezoneOffset();
12470};
12471
12472/**
12473 * This function does some basic calculations to create information about 
12474 * the user's timezone.
12475 * 
12476 * Returns a primitive object on the format
12477 * {'utc_offset' : -9, 'dst': 1, hemisphere' : 'north'}
12478 * where dst is 1 if the region uses daylight savings.
12479 * 
12480 * @returns {Object}  
12481 */
12482jzTimezoneDetector.get_timezone_info = function () {
12483	var january_offset = jzTimezoneDetector.get_january_offset();
12484	
12485	var june_offset = jzTimezoneDetector.get_june_offset();
12486	
12487	var diff = january_offset - june_offset;
12488
12489	if (diff < 0) {
12490	    return {'utc_offset' : january_offset,
12491				'dst':	1,
12492				'hemisphere' : jzTimezoneDetector.HEMISPHERE_NORTH};
12493	}
12494	else if (diff > 0) {
12495		return {'utc_offset' : june_offset,
12496				'dst' : 1,
12497				'hemisphere' : jzTimezoneDetector.HEMISPHERE_SOUTH};
12498	}
12499    return {'utc_offset' : january_offset, 
12500			'dst': 0, 
12501			'hemisphere' : jzTimezoneDetector.HEMISPHERE_UNKNOWN};
12502};
12503
12504jzTimezoneDetector.get_january_offset = function () {
12505	return jzTimezoneDetector.get_date_offset(new Date(2011, 0, 1, 0, 0, 0, 0));
12506};
12507
12508jzTimezoneDetector.get_june_offset = function () {
12509	return jzTimezoneDetector.get_date_offset(new Date(2011, 5, 1, 0, 0, 0, 0));
12510};
12511
12512/**
12513 * Uses get_timezone_info() to formulate a key to use in the olson.timezones dictionary.
12514 * 
12515 * Returns a primitive object on the format:
12516 * {'timezone': TimeZone, 'key' : 'the key used to find the TimeZone object'}
12517 * 
12518 * @returns Object 
12519 */
12520jzTimezoneDetector.determine_timezone = function () {
12521	var tz_key, timezone_key_info = jzTimezoneDetector.get_timezone_info(), hemisphere_suffix = '';
12522		
12523	if (timezone_key_info.hemisphere == jzTimezoneDetector.HEMISPHERE_SOUTH) {
12524		hemisphere_suffix = ',s';
12525	}
12526	
12527	tz_key = timezone_key_info.utc_offset + ',' + timezone_key_info.dst + hemisphere_suffix;
12528	
12529	return {'timezone' : jzTimezoneDetector.olson.timezones[tz_key], 'key' : tz_key};
12530};
12531
12532/**
12533 * The keys in this dictionary are comma separated as such:
12534 * 
12535 * First the offset compared to UTC time in minutes.
12536 *  
12537 * Then a flag which is 0 if the timezone does not take daylight savings into account and 1 if it does.
12538 * 
12539 * Thirdly an optional 's' signifies that the timezone is in the southern hemisphere, only interesting for timezones with DST.
12540 * 
12541 * The values of the dictionary are TimeZone objects.
12542 */
12543jzTimezoneDetector.olson.timezones = {
12544    '-720,0'   : new jzTimezoneDetector.TimeZone('-12:00','Etc/GMT+12', false),
12545    '-660,0'   : new jzTimezoneDetector.TimeZone('-11:00','Pacific/Pago_Pago', false),
12546    '-600,1'   : new jzTimezoneDetector.TimeZone('-11:00','America/Adak',true),
12547    '-660,1,s' : new jzTimezoneDetector.TimeZone('-11:00','Pacific/Apia', true),
12548    '-600,0'   : new jzTimezoneDetector.TimeZone('-10:00','Pacific/Honolulu', false),
12549    '-570,0'   : new jzTimezoneDetector.TimeZone('-10:30','Pacific/Marquesas',false),
12550    '-540,0'   : new jzTimezoneDetector.TimeZone('-09:00','Pacific/Gambier',false),
12551    '-540,1'   : new jzTimezoneDetector.TimeZone('-09:00','America/Anchorage', true),
12552    '-480,1'   : new jzTimezoneDetector.TimeZone('-08:00','America/Los_Angeles', true),
12553    '-480,0'   : new jzTimezoneDetector.TimeZone('-08:00','Pacific/Pitcairn',false),
12554    '-420,0'   : new jzTimezoneDetector.TimeZone('-07:00','America/Phoenix', false),
12555    '-420,1'   : new jzTimezoneDetector.TimeZone('-07:00','America/Denver', true),
12556    '-360,0'   : new jzTimezoneDetector.TimeZone('-06:00','America/Guatemala', false),
12557    '-360,1'   : new jzTimezoneDetector.TimeZone('-06:00','America/Chicago', true),
12558    '-360,1,s' : new jzTimezoneDetector.TimeZone('-06:00','Pacific/Easter',true),
12559    '-300,0'   : new jzTimezoneDetector.TimeZone('-05:00','America/Bogota', false),
12560    '-300,1'   : new jzTimezoneDetector.TimeZone('-05:00','America/New_York', true),
12561    '-270,0'   : new jzTimezoneDetector.TimeZone('-04:30','America/Caracas', false),
12562    '-240,1'   : new jzTimezoneDetector.TimeZone('-04:00','America/Halifax', true),
12563    '-240,0'   : new jzTimezoneDetector.TimeZone('-04:00','America/Santo_Domingo', false),
12564    '-240,1,s' : new jzTimezoneDetector.TimeZone('-04:00','America/Asuncion', true),
12565    '-210,1'   : new jzTimezoneDetector.TimeZone('-03:30','America/St_Johns', true),
12566    '-180,1'   : new jzTimezoneDetector.TimeZone('-03:00','America/Godthab', true),
12567    '-180,0'   : new jzTimezoneDetector.TimeZone('-03:00','America/Argentina/Buenos_Aires', false),
12568    '-180,1,s' : new jzTimezoneDetector.TimeZone('-03:00','America/Montevideo', true),
12569    '-120,0'   : new jzTimezoneDetector.TimeZone('-02:00','America/Noronha', false),
12570    '-120,1'   : new jzTimezoneDetector.TimeZone('-02:00','Etc/GMT+2', true),
12571    '-60,1'    : new jzTimezoneDetector.TimeZone('-01:00','Atlantic/Azores', true),
12572    '-60,0'    : new jzTimezoneDetector.TimeZone('-01:00','Atlantic/Cape_Verde', false),
12573    '0,0'      : new jzTimezoneDetector.TimeZone('00:00','Etc/UTC', false),
12574    '0,1'      : new jzTimezoneDetector.TimeZone('00:00','Europe/London', true),
12575    '60,1'     : new jzTimezoneDetector.TimeZone('+01:00','Europe/Berlin', true),
12576    '60,0'     : new jzTimezoneDetector.TimeZone('+01:00','Africa/Lagos', false),
12577    '60,1,s'   : new jzTimezoneDetector.TimeZone('+01:00','Africa/Windhoek',true),
12578    '120,1'    : new jzTimezoneDetector.TimeZone('+02:00','Asia/Beirut', true),
12579    '120,0'    : new jzTimezoneDetector.TimeZone('+02:00','Africa/Johannesburg', false),
12580    '180,1'    : new jzTimezoneDetector.TimeZone('+03:00','Europe/Moscow', true),
12581    '180,0'    : new jzTimezoneDetector.TimeZone('+03:00','Asia/Baghdad', false),
12582    '210,1'    : new jzTimezoneDetector.TimeZone('+03:30','Asia/Tehran', true),
12583    '240,0'    : new jzTimezoneDetector.TimeZone('+04:00','Asia/Dubai', false),
12584    '240,1'    : new jzTimezoneDetector.TimeZone('+04:00','Asia/Yerevan', true),
12585    '270,0'    : new jzTimezoneDetector.TimeZone('+04:30','Asia/Kabul', false),
12586    '300,1'    : new jzTimezoneDetector.TimeZone('+05:00','Asia/Yekaterinburg', true),
12587    '300,0'    : new jzTimezoneDetector.TimeZone('+05:00','Asia/Karachi', false),
12588    '330,0'    : new jzTimezoneDetector.TimeZone('+05:30','Asia/Kolkata', false),
12589    '345,0'    : new jzTimezoneDetector.TimeZone('+05:45','Asia/Kathmandu', false),
12590    '360,0'    : new jzTimezoneDetector.TimeZone('+06:00','Asia/Dhaka', false),
12591    '360,1'    : new jzTimezoneDetector.TimeZone('+06:00','Asia/Omsk', true),
12592    '390,0'    : new jzTimezoneDetector.TimeZone('+06:30','Asia/Rangoon', false),
12593    '420,1'    : new jzTimezoneDetector.TimeZone('+07:00','Asia/Krasnoyarsk', true),
12594    '420,0'    : new jzTimezoneDetector.TimeZone('+07:00','Asia/Jakarta', false),
12595    '480,0'    : new jzTimezoneDetector.TimeZone('+08:00','Asia/Shanghai', false),
12596    '480,1'    : new jzTimezoneDetector.TimeZone('+08:00','Asia/Irkutsk', true),
12597    '525,0'    : new jzTimezoneDetector.TimeZone('+08:45','Australia/Eucla', true),
12598    '525,1,s'  : new jzTimezoneDetector.TimeZone('+08:45','Australia/Eucla', true),
12599    '540,1'    : new jzTimezoneDetector.TimeZone('+09:00','Asia/Yakutsk', true),
12600    '540,0'    : new jzTimezoneDetector.TimeZone('+09:00','Asia/Tokyo', false),
12601    '570,0'    : new jzTimezoneDetector.TimeZone('+09:30','Australia/Darwin', false),
12602    '570,1,s'  : new jzTimezoneDetector.TimeZone('+09:30','Australia/Adelaide', true),
12603    '600,0'    : new jzTimezoneDetector.TimeZone('+10:00','Australia/Brisbane', false),
12604    '600,1'    : new jzTimezoneDetector.TimeZone('+10:00','Asia/Vladivostok', true),
12605    '600,1,s'  : new jzTimezoneDetector.TimeZone('+10:00','Australia/Sydney', true),
12606    '630,1,s'  : new jzTimezoneDetector.TimeZone('+10:30','Australia/Lord_Howe', true),
12607    '660,1'    : new jzTimezoneDetector.TimeZone('+11:00','Asia/Kamchatka', true),
12608    '660,0'    : new jzTimezoneDetector.TimeZone('+11:00','Pacific/Noumea', false),
12609    '690,0'    : new jzTimezoneDetector.TimeZone('+11:30','Pacific/Norfolk', false),
12610    '720,1,s'  : new jzTimezoneDetector.TimeZone('+12:00','Pacific/Auckland', true),
12611    '720,0'    : new jzTimezoneDetector.TimeZone('+12:00','Pacific/Tarawa', false),
12612    '765,1,s'  : new jzTimezoneDetector.TimeZone('+12:45','Pacific/Chatham', true),
12613    '780,0'    : new jzTimezoneDetector.TimeZone('+13:00','Pacific/Tongatapu', false),
12614    '840,0'    : new jzTimezoneDetector.TimeZone('+14:00','Pacific/Kiritimati', false)
12615};
12616
12617/**
12618 * This object contains information on when daylight savings starts for
12619 * different timezones.
12620 * 
12621 * The list is short for a reason. Often we do not have to be very specific
12622 * to single out the correct timezone. But when we do, this list comes in
12623 * handy.
12624 * 
12625 * Each value is a date denoting when daylight savings starts for that timezone.
12626 */
12627jzTimezoneDetector.olson.dst_start_dates = {
12628    'America/Denver' : new Date(2011, 2, 13, 3, 0, 0, 0),
12629    'America/Mazatlan' : new Date(2011, 3, 3, 3, 0, 0, 0),
12630    'America/Chicago' : new Date(2011, 2, 13, 3, 0, 0, 0),
12631    'America/Mexico_City' : new Date(2011, 3, 3, 3, 0, 0, 0),
12632    'Atlantic/Stanley' : new Date(2011, 8, 4, 7, 0, 0, 0),
12633    'America/Asuncion' : new Date(2011, 9, 2, 3, 0, 0, 0),
12634    'America/Santiago' : new Date(2011, 9, 9, 3, 0, 0, 0),
12635    'America/Campo_Grande' : new Date(2011, 9, 16, 5, 0, 0, 0),
12636    'America/Montevideo' : new Date(2011, 9, 2, 3, 0, 0, 0),
12637    'America/Sao_Paulo' : new Date(2011, 9, 16, 5, 0, 0, 0),
12638    'America/Los_Angeles' : new Date(2011, 2, 13, 8, 0, 0, 0),
12639    'America/Santa_Isabel' : new Date(2011, 3, 5, 8, 0, 0, 0),
12640    'America/Havana' : new Date(2011, 2, 13, 2, 0, 0, 0),
12641    'America/New_York' : new Date(2011, 2, 13, 7, 0, 0, 0),
12642    'Asia/Gaza' : new Date(2011, 2, 26, 23, 0, 0, 0),
12643    'Asia/Beirut' : new Date(2011, 2, 27, 1, 0, 0, 0),
12644    'Europe/Minsk' : new Date(2011, 2, 27, 3, 0, 0, 0),
12645    'Europe/Istanbul' : new Date(2011, 2, 27, 7, 0, 0, 0),
12646    'Asia/Damascus' : new Date(2011, 3, 1, 2, 0, 0, 0),
12647    'Asia/Jerusalem' : new Date(2011, 3, 1, 6, 0, 0, 0),
12648    'Africa/Cairo' : new Date(2011, 3, 29, 4, 0, 0, 0),
12649    'Asia/Yerevan' : new Date(2011, 2, 27, 4, 0, 0, 0),
12650    'Asia/Baku'    : new Date(2011, 2, 27, 8, 0, 0, 0),
12651    'Pacific/Auckland' : new Date(2011, 8, 26, 7, 0, 0, 0),
12652    'Pacific/Fiji' : new Date(2010, 11, 29, 23, 0, 0, 0),
12653    'America/Halifax' : new Date(2011, 2, 13, 6, 0, 0, 0),
12654    'America/Goose_Bay' : new Date(2011, 2, 13, 2, 1, 0, 0),
12655    'America/Miquelon' : new Date(2011, 2, 13, 5, 0, 0, 0),
12656    'America/Godthab' : new Date(2011, 2, 27, 1, 0, 0, 0)
12657};
12658
12659/**
12660 * The keys in this object are timezones that we know may be ambiguous after
12661 * a preliminary scan through the olson_tz object.
12662 * 
12663 * The array of timezones to compare must be in the order that daylight savings
12664 * starts for the regions.
12665 */
12666jzTimezoneDetector.olson.ambiguity_list = {
12667    'America/Denver' : ['America/Denver','America/Mazatlan'],
12668    'America/Chicago' : ['America/Chicago','America/Mexico_City'],
12669    'America/Asuncion' : ['Atlantic/Stanley', 'America/Asuncion', 'America/Santiago','America/Campo_Grande'],
12670    'America/Montevideo' : ['America/Montevideo', 'America/Sao_Paulo'],
12671    'Asia/Beirut' : ['Asia/Gaza','Asia/Beirut', 'Europe/Minsk', 'Europe/Istanbul', 'Asia/Damascus', 'Asia/Jerusalem','Africa/Cairo'],
12672    'Asia/Yerevan' : ['Asia/Yerevan', 'Asia/Baku'],
12673    'Pacific/Auckland' : ['Pacific/Auckland', 'Pacific/Fiji'],
12674    'America/Los_Angeles' : ['America/Los_Angeles', 'America/Santa_Isabel'],
12675    'America/New_York' : ['America/Havana','America/New_York'],
12676    'America/Halifax' : ['America/Goose_Bay','America/Halifax'],
12677    'America/Godthab' : ['America/Miquelon', 'America/Godthab']
12678};
12679/*
12680  mustache.js — Logic-less templates in JavaScript
12681
12682  See http://mustache.github.com/ for more info.
12683*/
12684
12685var Mustache = function() {
12686  var Renderer = function() {};
12687
12688  Renderer.prototype = {
12689    otag: "{{",
12690    ctag: "}}",
12691    pragmas: {},
12692    buffer: [],
12693    pragmas_implemented: {
12694      "IMPLICIT-ITERATOR": true
12695    },
12696    context: {},
12697
12698    render: function(template, context, partials, in_recursion) {
12699      // reset buffer & set context
12700      if(!in_recursion) {
12701        this.context = context;
12702        this.buffer = []; // TODO: make this non-lazy
12703      }
12704
12705      // fail fast
12706      if(!this.includes("", template)) {
12707        if(in_recursion) {
12708          return template;
12709        } else {
12710          this.send(template);
12711          return;
12712        }
12713      }
12714
12715      template = this.render_pragmas(template);
12716      var html = this.render_section(template, context, partials);
12717      if(in_recursion) {
12718        return this.render_tags(html, context, partials, in_recursion);
12719      }
12720
12721      this.render_tags(html, context, partials, in_recursion);
12722    },
12723
12724    /*
12725      Sends parsed lines
12726    */
12727    send: function(line) {
12728      if(line != "") {
12729        this.buffer.push(line);
12730      }
12731    },
12732
12733    /*
12734      Looks for %PRAGMAS
12735    */
12736    render_pragmas: function(template) {
12737      // no pragmas
12738      if(!this.includes("%", template)) {
12739        return template;
12740      }
12741
12742      var that = this;
12743      var regex = new RegExp(this.otag + "%([\\w-]+) ?([\\w]+=[\\w]+)?" +
12744            this.ctag);
12745      return template.replace(regex, function(match, pragma, options) {
12746        if(!that.pragmas_implemented[pragma]) {
12747          throw({message: 
12748            "This implementation of mustache doesn't understand the '" +
12749            pragma + "' pragma"});
12750        }
12751        that.pragmas[pragma] = {};
12752        if(options) {
12753          var opts = options.split("=");
12754          that.pragmas[pragma][opts[0]] = opts[1];
12755        }
12756        return "";
12757        // ignore unknown pragmas silently
12758      });
12759    },
12760
12761    /*
12762      Tries to find a partial in the curent scope and render it
12763    */
12764    render_partial: function(name, context, partials) {
12765      name = this.trim(name);
12766      if(!partials || partials[name] === undefined) {
12767        throw({message: "unknown_partial '" + name + "'"});
12768      }
12769      if(typeof(context[name]) != "object") {
12770        return this.render(partials[name], context, partials, true);
12771      }
12772      return this.render(partials[name], context[name], partials, true);
12773    },
12774
12775    /*
12776      Renders inverted (^) and normal (#) sections
12777    */
12778    render_section: function(template, context, partials) {
12779      if(!this.includes("#", template) && !this.includes("^", template)) {
12780        return template;
12781      }
12782
12783      var that = this;
12784      // CSW - Added "+?" so it finds the tighest bound, not the widest
12785      var regex = new RegExp(this.otag + "(\\^|\\#)\\s*(.+)\\s*" + this.ctag +
12786              "\n*([\\s\\S]+?)" + this.otag + "\\/\\s*\\2\\s*" + this.ctag +
12787              "\\s*", "mg");
12788
12789      // for each {{#foo}}{{/foo}} section do...
12790      return template.replace(regex, function(match, type, name, content) {
12791        var value = that.find(name, context);
12792        if(type == "^") { // inverted section
12793          if(!value || that.is_array(value) && value.length === 0) {
12794            // false or empty list, render it
12795            return that.render(content, context, partials, true);
12796          } else {
12797            return "";
12798          }
12799        } else if(type == "#") { // normal section
12800          if(that.is_array(value)) { // Enumerable, Let's loop!
12801            return that.map(value, function(row) {
12802              return that.render(content, that.create_context(row),
12803                partials, true);
12804            }).join("");
12805          } else if(that.is_object(value)) { // Object, Use it as subcontext!
12806            return that.render(content, that.create_context(value),
12807              partials, true);
12808          } else if(typeof value === "function") {
12809            // higher order section
12810            return value.call(context, content, function(text) {
12811              return that.render(text, context, partials, true);
12812            });
12813          } else if(value) { // boolean section
12814            return that.render(content, context, partials, true);
12815          } else {
12816            return "";
12817          }
12818        }
12819      });
12820    },
12821
12822    /*
12823      Replace {{foo}} and friends with values from our view
12824    */
12825    render_tags: function(template, context, partials, in_recursion) {
12826      // tit for tat
12827      var that = this;
12828
12829      var new_regex = function() {
12830        return new RegExp(that.otag + "(=|!|>|\\{|%)?([^\\/#\\^]+?)\\1?" +
12831          that.ctag + "+", "g");
12832      };
12833
12834      var regex = new_regex();
12835      var tag_replace_callback = function(match, operator, name) {
12836        switch(operator) {
12837        case "!": // ignore comments
12838          return "";
12839        case "=": // set new delimiters, rebuild the replace regexp
12840          that.set_delimiters(name);
12841          regex = new_regex();
12842          return "";
12843        case ">": // render partial
12844          return that.render_partial(name, context, partials);
12845        case "{": // the triple mustache is unescaped
12846          return that.find(name, context);
12847        default: // escape the value
12848          return that.escape(that.find(name, context));
12849        }
12850      };
12851      var lines = template.split("\n");
12852      for(var i = 0; i < lines.length; i++) {
12853        lines[i] = lines[i].replace(regex, tag_replace_callback, this);
12854        if(!in_recursion) {
12855          this.send(lines[i]);
12856        }
12857      }
12858
12859      if(in_recursion) {
12860        return lines.join("\n");
12861      }
12862    },
12863
12864    set_delimiters: function(delimiters) {
12865      var dels = delimiters.split(" ");
12866      this.otag = this.escape_regex(dels[0]);
12867      this.ctag = this.escape_regex(dels[1]);
12868    },
12869
12870    escape_regex: function(text) {
12871      // thank you Simon Willison
12872      if(!arguments.callee.sRE) {
12873        var specials = [
12874          '/', '.', '*', '+', '?', '|',
12875          '(', ')', '[', ']', '{', '}', '\\'
12876        ];
12877        arguments.callee.sRE = new RegExp(
12878          '(\\' + specials.join('|\\') + ')', 'g'
12879        );
12880      }
12881      return text.replace(arguments.callee.sRE, '\\$1');
12882    },
12883
12884    /*
12885      find `name` in current `context`. That is find me a value
12886      from the view object
12887    */
12888    find: function(name, context) {
12889      name = this.trim(name);
12890
12891      // Checks whether a value is thruthy or false or 0
12892      function is_kinda_truthy(bool) {
12893        return bool === false || bool === 0 || bool;
12894      }
12895
12896      var value = context;
12897      var path = name.split(/\./);
12898      for(var i = 0; i < path.length; i++) {
12899        name = path[i];
12900        if(value && is_kinda_truthy(value[name])) {
12901          value = value[name];
12902        } else if(i == 0 && is_kinda_truthy(this.context[name])) {
12903          value = this.context[name];
12904        } else {
12905          value = undefined;
12906        }
12907      }
12908
12909      if(typeof value === "function") {
12910        return value.apply(context);
12911      }
12912      if(value !== undefined) {
12913        return value;
12914      }
12915      // silently ignore unkown variables
12916      return "";
12917    },
12918
12919    // Utility methods
12920
12921    /* includes tag */
12922    includes: function(needle, haystack) {
12923      return haystack.indexOf(this.otag + needle) != -1;
12924    },
12925
12926    /*
12927      Does away with nasty characters
12928    */
12929    escape: function(s) {
12930      s = String(s === null ? "" : s);
12931      return s.replace(/&(?!\w+;)|["'<>\\]/g, function(s) {
12932        switch(s) {
12933        case "&": return "&amp;";
12934        case "\\": return "\\\\";
12935        case '"': return '&quot;';
12936        case "'": return '&#39;';
12937        case "<": return "&lt;";
12938        case ">": return "&gt;";
12939        default: return s;
12940        }
12941      });
12942    },
12943
12944    // by @langalex, support for arrays of strings
12945    create_context: function(_context) {
12946      if(this.is_object(_context)) {
12947        return _context;
12948      } else {
12949        var iterator = ".";
12950        if(this.pragmas["IMPLICIT-ITERATOR"]) {
12951          iterator = this.pragmas["IMPLICIT-ITERATOR"].iterator;
12952        }
12953        var ctx = {};
12954        ctx[iterator] = _context;
12955        return ctx;
12956      }
12957    },
12958
12959    is_object: function(a) {
12960      return a && typeof a == "object";
12961    },
12962
12963    is_array: function(a) {
12964      return Object.prototype.toString.call(a) === '[object Array]';
12965    },
12966
12967    /*
12968      Gets rid of leading and trailing whitespace
12969    */
12970    trim: function(s) {
12971      return s.replace(/^\s*|\s*$/g, "");
12972    },
12973
12974    /*
12975      Why, why, why? Because IE. Cry, cry cry.
12976    */
12977    map: function(array, fn) {
12978      if (typeof array.map == "function") {
12979        return array.map(fn);
12980      } else {
12981        var r = [];
12982        var l = array.length;
12983        for(var i = 0; i < l; i++) {
12984          r.push(fn(array[i]));
12985        }
12986        return r;
12987      }
12988    }
12989  };
12990
12991  return({
12992    name: "mustache.js",
12993    version: "0.3.1-dev",
12994
12995    /*
12996      Turns a template and view into HTML
12997    */
12998    to_html: function(template, view, partials, send_fun) {
12999      var renderer = new Renderer();
13000      if(send_fun) {
13001        renderer.send = send_fun;
13002      }
13003      renderer.render(template, view, partials);
13004      if(!send_fun) {
13005        return renderer.buffer.join("\n");
13006      }
13007    }
13008  });
13009}();
13010/* 
13011 * More info at: http://phpjs.org
13012 * 
13013 * This is version: 3.24
13014 * php.js is copyright 2011 Kevin van Zonneveld.
13015 * 
13016 * Portions copyright Brett Zamir (http://brett-zamir.me), Kevin van Zonneveld
13017 * (http://kevin.vanzonneveld.net), Onno Marsman, Theriault, Michael White
13018 * (http://getsprink.com), Waldo Malqui Silva, Paulo Freitas, Jonas Raoni
13019 * Soares Silva (http://www.jsfromhell.com), Jack, Philip Peterson, Ates Goral
13020 * (http://magnetiq.com), Legaev Andrey, Ratheous, Alex, Martijn Wieringa,
13021 * Nate, lmeyrick (https://sourceforge.net/projects/bcmath-js/), Enrique
13022 * Gonzalez, Philippe Baumann, Rafał Kukawski (http://blog.kukawski.pl),
13023 * Webtoolkit.info (http://www.webtoolkit.info/), Ole Vrijenhoek, Ash Searle
13024 * (http://hexmen.com/blog/), travc, Carlos R. L. Rodrigues
13025 * (http://www.jsfromhell.com), Jani Hartikainen, stag019, GeekFG
13026 * (http://geekfg.blogspot.com), WebDevHobo (http://webdevhobo.blogspot.com/),
13027 * Erkekjetter, pilus, Rafał Kukawski (http://blog.kukawski.pl/), Johnny Mast
13028 * (http://www.phpvrouwen.nl), T.Wild,
13029 * http://stackoverflow.com/questions/57803/how-to-convert-decimal-to-hex-in-javascript,
13030 * d3x, Michael Grier, Andrea Giammarchi (http://webreflection.blogspot.com),
13031 * marrtins, Mailfaker (http://www.weedem.fr/), Steve Hilder, gettimeofday,
13032 * mdsjack (http://www.mdsjack.bo.it), felix, majak, Steven Levithan
13033 * (http://blog.stevenlevithan.com), Mirek Slugen, Oleg Eremeev, Felix
13034 * Geisendoerfer (http://www.debuggable.com/felix), Martin
13035 * (http://www.erlenwiese.de/), gorthaur, Lars Fischer, Joris, AJ, Paul Smith,
13036 * Tim de Koning (http://www.kingsquare.nl), KELAN, Josh Fraser
13037 * (http://onlineaspect.com/2007/06/08/auto-detect-a-time-zone-with-javascript/),
13038 * Chris, Marc Palau, Kevin van Zonneveld (http://kevin.vanzonneveld.net/),
13039 * Arpad Ray (mailto:arpad@php.net), Breaking Par Consulting Inc
13040 * (http://www.breakingpar.com/bkp/home.nsf/0/87256B280015193F87256CFB006C45F7),
13041 * Nathan, Karol Kowalski, David, Dreamer, Diplom@t (http://difane.com/), Caio
13042 * Ariede (http://caioariede.com), Robin, Imgen Tata (http://www.myipdf.com/),
13043 * Pellentesque Malesuada, saulius, Aman Gupta, Sakimori, Tyler Akins
13044 * (http://rumkin.com), Thunder.m, Public Domain
13045 * (http://www.json.org/json2.js), Michael White, Kankrelune
13046 * (http://www.webfaktory.info/), Alfonso Jimenez
13047 * (http://www.alfonsojimenez.com), Frank Forte, vlado houba, Marco, Billy,
13048 * David James, madipta, noname, sankai, class_exists, Jalal Berrami, ger,
13049 * Itsacon (http://www.itsacon.net/), Scott Cariss, nobbler, Arno, Denny
13050 * Wardhana, ReverseSyntax, Mateusz "loonquawl" Zalega, Slawomir Kaniecki,
13051 * Francois, Fox, mktime, Douglas Crockford (http://javascript.crockford.com),
13052 * john (http://www.jd-tech.net), Oskar Larsson Högfeldt
13053 * (http://oskar-lh.name/), marc andreu, Nick Kolosov (http://sammy.ru), date,
13054 * Marc Jansen, Steve Clay, Olivier Louvignes (http://mg-crea.com/), Soren
13055 * Hansen, merabi, Subhasis Deb, josh, T0bsn, Tim Wiel, Brad Touesnard, MeEtc
13056 * (http://yass.meetcweb.com), Peter-Paul Koch
13057 * (http://www.quirksmode.org/js/beat.html), Pyerre, Jon Hohle, duncan, Bayron
13058 * Guevara, Adam Wallner (http://web2.bitbaro.hu/), paulo kuong, Gilbert,
13059 * Lincoln Ramsay, Thiago Mata (http://thiagomata.blog.com), Linuxworld,
13060 * lmeyrick (https://sourceforge.net/projects/bcmath-js/this.), djmix, Bryan
13061 * Elliott, David Randall, Sanjoy Roy, jmweb, Francesco, Stoyan Kyosev
13062 * (http://www.svest.org/), J A R, kenneth, T. Wild, Ole Vrijenhoek
13063 * (http://www.nervous.nl/), Raphael (Ao RUDLER), Shingo, LH, JB, nord_ua, jd,
13064 * JT, Thomas Beaucourt (http://www.webapp.fr), Ozh, XoraX
13065 * (http://www.xorax.info), EdorFaus, Eugene Bulkin (http://doubleaw.com/),
13066 * Der Simon (http://innerdom.sourceforge.net/), 0m3r, echo is bad,
13067 * FremyCompany, stensi, Kristof Coomans (SCK-CEN Belgian Nucleair Research
13068 * Centre), Devan Penner-Woelk, Pierre-Luc Paour, Martin Pool, Brant Messenger
13069 * (http://www.brantmessenger.com/), Kirk Strobeck, Saulo Vallory, Christoph,
13070 * Wagner B. Soares, Artur Tchernychev, Valentina De Rosa, Jason Wong
13071 * (http://carrot.org/), Daniel Esteban, strftime, Rick Waldron, Mick@el,
13072 * Anton Ongson, Bjorn Roesbeke (http://www.bjornroesbeke.be/), Simon Willison
13073 * (http://simonwillison.net), Gabriel Paderni, Philipp Lenssen, Marco van
13074 * Oort, Bug?, Blues (http://tech.bluesmoon.info/), Tomasz Wesolowski, rezna,
13075 * Eric Nagel, Evertjan Garretsen, Luke Godfrey, Pul, Bobby Drake, uestla,
13076 * Alan C, Ulrich, Zahlii, Yves Sucaet, sowberry, Norman "zEh" Fuchs, hitwork,
13077 * johnrembo, Brian Tafoya (http://www.premasolutions.com/), Nick Callen,
13078 * Steven Levithan (stevenlevithan.com), ejsanders, Scott Baker, Philippe
13079 * Jausions (http://pear.php.net/user/jausions), Aidan Lister
13080 * (http://aidanlister.com/), Rob, e-mike, HKM, ChaosNo1, metjay, strcasecmp,
13081 * strcmp, Taras Bogach, jpfle, Alexander Ermolaev
13082 * (http://snippets.dzone.com/user/AlexanderErmolaev), DxGx, kilops, Orlando,
13083 * dptr1988, Le Torbi, James (http://www.james-bell.co.uk/), Pedro Tainha
13084 * (http://www.pedrotainha.com), James, penutbutterjelly, Arnout Kazemier
13085 * (http://www.3rd-Eden.com), 3D-GRAF, daniel airton wermann
13086 * (http://wermann.com.br), jakes, Yannoo, FGFEmperor, gabriel paderni, Atli
13087 * Þór, Maximusya, Diogo Resende, Rival, Howard Yeend, Allan Jensen
13088 * (http://www.winternet.no), davook, Benjamin Lupton, baris ozdil, Greg
13089 * Frazier, Manish, Matt Bradley, Cord, fearphage
13090 * (http://http/my.opera.com/fearphage/), Matteo, Victor, taith, Tim de
13091 * Koning, Ryan W Tenney (http://ryan.10e.us), Tod Gentille, Alexander M
13092 * Beedie, Riddler (http://www.frontierwebdev.com/), Luis Salazar
13093 * (http://www.freaky-media.com/), Rafał Kukawski, T.J. Leahy, Luke Smith
13094 * (http://lucassmith.name), Kheang Hok Chin (http://www.distantia.ca/),
13095 * Russell Walker (http://www.nbill.co.uk/), Jamie Beck
13096 * (http://www.terabit.ca/), Garagoth, Andrej Pavlovic, Dino, Le Torbi
13097 * (http://www.letorbi.de/), Ben (http://benblume.co.uk/), DtTvB
13098 * (http://dt.in.th/2008-09-16.string-length-in-bytes.html), Michael, Chris
13099 * McMacken, setcookie, YUI Library:
13100 * http://developer.yahoo.com/yui/docs/YAHOO.util.DateLocale.html, Andreas,
13101 * Blues at http://hacks.bluesmoon.info/strftime/strftime.js, rem, Josep Sanz
13102 * (http://www.ws3.es/), Cagri Ekin, Lorenzo Pisani, incidence, Amirouche, Jay
13103 * Klehr, Amir Habibi (http://www.residence-mixte.com/), Tony, booeyOH, meo,
13104 * William, Greenseed, Yen-Wei Liu, Ben Bryan, Leslie Hoare, mk.keck
13105 * 
13106 * Dual licensed under the MIT (MIT-LICENSE.txt)
13107 * and GPL (GPL-LICENSE.txt) licenses.
13108 * 
13109 * Permission is hereby granted, free of charge, to any person obtaining a
13110 * copy of this software and associated documentation files (the
13111 * "Software"), to deal in the Software without restriction, including
13112 * without limitation the rights to use, copy, modify, merge, publish,
13113 * distribute, sublicense, and/or sell copies of the Software, and to
13114 * permit persons to whom the Software is furnished to do so, subject to
13115 * the following conditions:
13116 * 
13117 * The above copyright notice and this permission notice shall be included
13118 * in all copies or substantial portions of the Software.
13119 * 
13120 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
13121 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
13122 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
13123 * IN NO EVENT SHALL KEVIN VAN ZONNEVELD BE LIABLE FOR ANY CLAIM, DAMAGES
13124 * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
13125 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
13126 * OTHER DEALINGS IN THE SOFTWARE.
13127 */ 
13128
13129
13130// jslint.com configuration options. See: http://wiki.github.com/kvz/phpjs/jslint-options
13131/* global window */
13132/* jslint adsafe: false, bitwise: false, browser: false, cap: false, css: false, debug: false, devel: false, eqeqeq: true, evil: false, forin: false, fragment: false, immed: true, indent: 4, laxbreak: false, maxerr: 100, maxlen: 80, newcap: true, nomen: false, on: true, onevar: false, passfail: false, plusplus: false, regexp: false, rhino: false, safe: false, sidebar: false, strict: false, sub: false, undef: true, white: false, widget: false */
13133
13134// Our idea with CommonJS is that you can do the following:
13135// var php = require('php');
13136// php.md5('test');
13137var php = {};
13138
13139php.ini_set = function (varname, newvalue) {
13140    // http://kevin.vanzonneveld.net
13141    // +   original by: Brett Zamir (http://brett-zamir.me)
13142    // %        note 1: This will not set a global_value or access level for the ini item
13143    // *     example 1: ini_set('date.timezone', 'America/Chicago');
13144    // *     returns 1: 'Asia/Hong_Kong'
13145
13146    var oldval = '',
13147        that = this;
13148    this.php_js = this.php_js || {};
13149    this.php_js.ini = this.php_js.ini || {};
13150    this.php_js.ini[varname] = this.php_js.ini[varname] || {};
13151    oldval = this.php_js.ini[varname].local_value;
13152
13153    var _setArr = function (oldval) { // Although these are set individually, they are all accumulated
13154        if (typeof oldval === 'undefined') {
13155            that.php_js.ini[varname].local_value = [];
13156        }
13157        that.php_js.ini[varname].local_value.push(newvalue);
13158    };
13159
13160    switch (varname) {
13161    case 'extension':
13162        if (typeof this.dl === 'function') {
13163            this.dl(newvalue); // This function is only experimental in php.js
13164        }
13165        _setArr(oldval, newvalue);
13166        break;
13167    default:
13168        this.php_js.ini[varname].local_value = newvalue;
13169        break;
13170    }
13171    return oldval;
13172};
13173php.ini_get = function (varname) {
13174    // http://kevin.vanzonneveld.net
13175    // +   original by: Brett Zamir (http://brett-zamir.me)
13176    // %        note 1: The ini values must be set by ini_set or manually within an ini file
13177    // *     example 1: ini_get('date.timezone');
13178    // *     returns 1: 'Asia/Hong_Kong'
13179    if (this.php_js && this.php_js.ini && this.php_js.ini[varname] && this.php_js.ini[varname].local_value !== undefined) {
13180        if (this.php_js.ini[varname].local_value === null) {
13181            return '';
13182        }
13183        return this.php_js.ini[varname].local_value;
13184    }
13185    return '';
13186}
13187
13188php.ctype_digit = function (text) {
13189    // http://kevin.vanzonneveld.net
13190    // +   original by: Brett Zamir (http://brett-zamir.me)
13191    // -    depends on: setlocale
13192    // *     example 1: ctype_digit('150');
13193    // *     returns 1: true
13194    if (typeof text !== 'string') {
13195        return false;
13196    }
13197    // BEGIN REDUNDANT
13198    this.setlocale('LC_ALL', 0); // ensure setup of localization variables takes place
13199    // END REDUNDANT
13200    return text.search(this.php_js.locales[this.php_js.localeCategories.LC_CTYPE].LC_CTYPE.dg) !== -1;
13201};
13202php.gmmktime = function () {
13203    // http://kevin.vanzonneveld.net
13204    // +   original by: Brett Zamir (http://brett-zamir.me)
13205    // +   derived from: mktime
13206    // *     example 1: gmmktime(14, 10, 2, 2, 1, 2008);
13207    // *     returns 1: 1201875002
13208    // *     example 2: gmmktime(0, 0, -1, 1, 1, 1970);
13209    // *     returns 2: -1
13210    var d = new Date(),
13211        r = arguments,
13212        i = 0,
13213        e = ['Hours', 'Minutes', 'Seconds', 'Month', 'Date', 'FullYear'];
13214
13215    for (i = 0; i < e.length; i++) {
13216        if (typeof r[i] === 'undefined') {
13217            r[i] = d['getUTC' + e[i]]();
13218            r[i] += (i === 3); // +1 to fix JS months.
13219        } else {
13220            r[i] = parseInt(r[i], 10);
13221            if (isNaN(r[i])) {
13222                return false;
13223            }
13224        }
13225    }
13226
13227    // Map years 0-69 to 2000-2069 and years 70-100 to 1970-2000.
13228    r[5] += (r[5] >= 0 ? (r[5] <= 69 ? 2e3 : (r[5] <= 100 ? 1900 : 0)) : 0);
13229
13230    // Set year, month (-1 to fix JS months), and date.
13231    // !This must come before the call to setHours!
13232    d.setUTCFullYear(r[5], r[3] - 1, r[4]);
13233
13234    // Set hours, minutes, and seconds.
13235    d.setUTCHours(r[0], r[1], r[2]);
13236
13237    // Divide milliseconds by 1000 to return seconds and drop decimal.
13238    // Add 1 second if negative or it'll be off from PHP by 1 second.
13239    return (d.getTime() / 1e3 >> 0) - (d.getTime() < 0);
13240};
13241php.getdate = function (timestamp) {
13242    // http://kevin.vanzonneveld.net
13243    // +   original by: Paulo Freitas
13244    // +   input by: Alex
13245    // +   bugfixed by: Brett Zamir (http://brett-zamir.me)
13246    // *     example 1: getdate(1055901520);
13247    // *     returns 1: {'seconds': 40, 'minutes': 58, 'hours': 21, 'mday': 17, 'wday': 2, 'mon': 6, 'year': 2003, 'yday': 167, 'weekday': 'Tuesday', 'month': 'June', '0': 1055901520}
13248    var _w = ['Sun', 'Mon', 'Tues', 'Wednes', 'Thurs', 'Fri', 'Satur'];
13249    var _m = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
13250    var d = ((typeof(timestamp) == 'undefined') ? new Date() : // Not provided
13251    (typeof(timestamp) == 'object') ? new Date(timestamp) : // Javascript Date()
13252    new Date(timestamp * 1000) // UNIX timestamp (auto-convert to int)
13253    );
13254    var w = d.getDay();
13255    var m = d.getMonth();
13256    var y = d.getFullYear();
13257    var r = {};
13258
13259    r.seconds = d.getSeconds();
13260    r.minutes = d.getMinutes();
13261    r.hours = d.getHours();
13262    r.mday = d.getDate();
13263    r.wday = w;
13264    r.mon = m + 1;
13265    r.year = y;
13266    r.yday = Math.floor((d - (new Date(y, 0, 1))) / 86400000);
13267    r.weekday = _w[w] + 'day';
13268    r.month = _m[m];
13269    r['0'] = parseInt(d.getTime() / 1000, 10);
13270
13271    return r;
13272};
13273php.checkdate = function (m, d, y) {
13274    // Returns true(1) if it is a valid date in gregorian calendar  
13275    // 
13276    // version: 1103.1210
13277    // discuss at: http://phpjs.org/functions/checkdate
13278    // +   original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
13279    // +   improved by: Pyerre
13280    // +   improved by: Theriault
13281    // *     example 1: checkdate(12, 31, 2000);
13282    // *     returns 1: true
13283    // *     example 2: checkdate(2, 29, 2001);
13284    // *     returns 2: false
13285    // *     example 3: checkdate(3, 31, 2008);
13286    // *     returns 3: true
13287    // *     example 4: checkdate(1, 390, 2000);
13288    // *     returns 4: false
13289    return m > 0 && m < 13 && y > 0 && y < 32768 && d > 0 && d <= (new Date(y, m, 0)).getDate();
13290};
13291php.gmdate = function (format, timestamp) {
13292    // Format a GMT date/time  
13293    // 
13294    // version: 1103.1210
13295    // discuss at: http://phpjs.org/functions/gmdate
13296    // +   original by: Brett Zamir (http://brett-zamir.me)
13297    // +   input by: Alex
13298    // +   bugfixed by: Brett Zamir (http://brett-zamir.me)
13299    // -    depends on: date
13300    // *     example 1: gmdate('H:m:s \\m \\i\\s \\m\\o\\n\\t\\h', 1062402400); // Return will depend on your timezone
13301    // *     returns 1: '07:09:40 m is month'
13302    var dt = ((typeof(timestamp) == 'undefined') ? new Date() : // Not provided
13303    (typeof(timestamp) == 'object') ? new Date(timestamp) : // Javascript Date()
13304    new Date(timestamp * 1000) // UNIX timestamp (auto-convert to int)
13305    );
13306    timestamp = Date.parse(dt.toUTCString().slice(0, -4)) / 1000;
13307    return this.date(format, timestamp);
13308};
13309php.mt_rand = function (min, max) {
13310    // Returns a random number from Mersenne Twister  
13311    // 
13312    // version: 1103.1210
13313    // discuss at: http://phpjs.org/functions/mt_rand
13314    // +   original by: Onno Marsman
13315    // *     example 1: mt_rand(1, 1);
13316    // *     returns 1: 1
13317    var argc = arguments.length;
13318    if (argc === 0) {
13319        min = 0;
13320        max = 2147483647;
13321    } else if (argc === 1) {
13322        throw new Error('Warning: mt_rand() expects exactly 2 parameters, 1 given');
13323    }
13324    return Math.floor(Math.random() * (max - min + 1)) + min;
13325};
13326
13327php.abs = function (mixed_number) {
13328    // Return the absolute value of the number  
13329    // 
13330    // version: 1103.1210
13331    // discuss at: http://phpjs.org/functions/abs
13332    // +   original by: Waldo Malqui Silva
13333    // +   improved by: Karol Kowalski
13334    // +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
13335    // +   improved by: Jonas Raoni Soares Silva (http://www.jsfromhell.com)
13336    // *     example 1: \php.abs(4.2);
13337    // *     returns 1: 4.2
13338    // *     example 2: \php.abs(-4.2);
13339    // *     returns 2: 4.2
13340    // *     example 3: \php.abs(-5);
13341    // *     returns 3: 5
13342    // *     example 4: \php.abs('_argos');
13343    // *     returns 4: 0
13344    return Math.abs(mixed_number) || 0;
13345};
13346
13347php.addcslashes = function (str, charlist) {
13348    // Escapes all chars mentioned in charlist with backslash. It creates octal representations if asked to backslash characters with 8th bit set or with ASCII<32 (except '\n', '\r', '\t' etc...)  
13349    // 
13350    // version: 1103.1210
13351    // discuss at: http://phpjs.org/functions/addcslashes
13352    // +   original by: Brett Zamir (http://brett-zamir.me)
13353    // %  note 1: We show double backslashes in the return value example code below because a JavaScript string will not
13354    // %  note 1: render them as backslashes otherwise
13355    // *     example 1: \php.addcslashes('foo[ ]', 'A..z'); // Escape all ASCII within capital A to lower z range, including square brackets
13356    // *     returns 1: "\\f\\o\\o\\[ \\]"
13357    // *     example 2: \php.addcslashes("zoo['.']", 'z..A'); // Only escape z, period, and A here since not a lower-to-higher range
13358    // *     returns 2: "\\zoo['\\.']"
13359    // *     example 3: \php.addcslashes("@a\u0000\u0010\u00A9", "\0..\37!@\177..\377") == '\\@a\\000\\020\\302\\251'); // Escape as octals those specified and less than 32 (0x20) or greater than 126 (0x7E), but not otherwise
13360    // *     returns 3: true
13361    // *     example 4: \php.addcslashes("\u0020\u007E", "\40..\175") == '\\ ~'); // Those between 32 (0x20 or 040) and 126 (0x7E or 0176) decimal value will be backslashed if specified (not octalized)
13362    // *     returns 4: true
13363    // *     example 5: \php.addcslashes("\r\u0007\n", '\0..\37'); // Recognize C escape sequences if specified
13364    // *     returns 5: "\\r\\a\\n"
13365    // *     example 6: \php.addcslashes("\r\u0007\n", '\0'); // Do not recognize C escape sequences if not specified
13366    // *     returns 7: "\r\u0007\n"
13367    var target = '',
13368        chrs = [],
13369        i = 0,
13370        j = 0,
13371        c = '',
13372        next = '',
13373        rangeBegin = '',
13374        rangeEnd = '',
13375        chr = '',
13376        begin = 0,
13377        end = 0,
13378        octalLength = 0,
13379        postOctalPos = 0,
13380        cca = 0,
13381        escHexGrp = [],
13382        encoded = '',
13383        percentHex = /%([\dA-Fa-f]+)/g;
13384    var _pad = function (n, c) {
13385        if ((n = n + "").length < c) {
13386            return new Array(++c - n.length).join("0") + n;
13387        } else {
13388            return n;
13389        }
13390    };
13391
13392    for (i = 0; i < charlist.length; i++) {
13393        c = charlist.charAt(i);
13394        next = charlist.charAt(i + 1);
13395        if (c === '\\' && next && (/\d/).test(next)) { // Octal
13396            rangeBegin = charlist.slice(i + 1).match(/^\d+/)[0];
13397            octalLength = rangeBegin.length;
13398            postOctalPos = i + octalLength + 1;
13399            if (charlist.charAt(postOctalPos) + charlist.charAt(postOctalPos + 1) === '..') { // Octal begins range
13400                begin = rangeBegin.charCodeAt(0);
13401                if ((/\\\d/).test(charlist.charAt(postOctalPos + 2) + charlist.charAt(postOctalPos + 3))) { // Range ends with octal
13402                    rangeEnd = charlist.slice(postOctalPos + 3).match(/^\d+/)[0];
13403                    i += 1; // Skip range end backslash
13404                } else if (charlist.charAt(postOctalPos + 2)) { // Range ends with character
13405                    rangeEnd = charlist.charAt(postOctalPos + 2);
13406                } else {
13407                    throw 'Range with no end point';
13408                }
13409                end = rangeEnd.charCodeAt(0);
13410                if (end > begin) { // Treat as a range
13411                    for (j = begin; j <= end; j++) {
13412                        chrs.push(String.fromCharCode(j));
13413                    }
13414                } else { // Supposed to treat period, begin and end as individual characters only, not a range
13415                    chrs.push('.', rangeBegin, rangeEnd);
13416                }
13417                i += rangeEnd.length + 2; // Skip dots and range end (already skipped range end backslash if present)
13418            } else { // Octal is by itself
13419                chr = String.fromCharCode(parseInt(rangeBegin, 8));
13420                chrs.push(chr);
13421            }
13422            i += octalLength; // Skip range begin
13423        } else if (next + charlist.charAt(i + 2) === '..') { // Character begins range
13424            rangeBegin = c;
13425            begin = rangeBegin.charCodeAt(0);
13426            if ((/\\\d/).test(charlist.charAt(i + 3) + charlist.charAt(i + 4))) { // Range ends with octal
13427                rangeEnd = charlist.slice(i + 4).match(/^\d+/)[0];
13428                i += 1; // Skip range end backslash
13429            } else if (charlist.charAt(i + 3)) { // Range ends with character
13430                rangeEnd = charlist.charAt(i + 3);
13431            } else {
13432                throw 'Range with no end point';
13433            }
13434            end = rangeEnd.charCodeAt(0);
13435            if (end > begin) { // Treat as a range
13436                for (j = begin; j <= end; j++) {
13437                    chrs.push(String.fromCharCode(j));
13438                }
13439            } else { // Supposed to treat period, begin and end as individual characters only, not a range
13440                chrs.push('.', rangeBegin, rangeEnd);
13441            }
13442            i += rangeEnd.length + 2; // Skip dots and range end (already skipped range end backslash if present)
13443        } else { // Character is by itself
13444            chrs.push(c);
13445        }
13446    }
13447
13448    for (i = 0; i < str.length; i++) {
13449        c = str.charAt(i);
13450        if (chrs.indexOf(c) !== -1) {
13451            target += '\\';
13452            cca = c.charCodeAt(0);
13453            if (cca < 32 || cca > 126) { // Needs special escaping
13454                switch (c) {
13455                case '\n':
13456                    target += 'n';
13457                    break;
13458                case '\t':
13459                    target += 't';
13460                    break;
13461                case '\u000D':
13462                    target += 'r';
13463                    break;
13464                case '\u0007':
13465                    target += 'a';
13466                    break;
13467                case '\v':
13468                    target += 'v';
13469                    break;
13470                case '\b':
13471                    target += 'b';
13472                    break;
13473                case '\f':
13474                    target += 'f';
13475                    break;
13476                default:
13477                    //target += _pad(cca.toString(8), 3);break; // Sufficient for UTF-16
13478                    encoded = encodeURIComponent(c);
13479
13480                    // 3-length-padded UTF-8 octets
13481                    if ((escHexGrp = percentHex.exec(encoded)) !== null) {
13482                        target += _pad(parseInt(escHexGrp[1], 16).toString(8), 3); // already added a slash above
13483                    }
13484                    while ((escHexGrp = percentHex.exec(encoded)) !== null) {
13485                        target += '\\' + _pad(parseInt(escHexGrp[1], 16).toString(8), 3);
13486                    }
13487                    break;
13488                }
13489            } else { // Perform regular backslashed escaping
13490                target += c;
13491            }
13492        } else { // Just add the character unescaped
13493            target += c;
13494        }
13495    }
13496    return target;
13497};
13498
13499php.addslashes = function (str) {
13500    // Escapes single quote, double quotes and backslash characters in a string with backslashes  
13501    // 
13502    // version: 1103.1210
13503    // discuss at: http://phpjs.org/functions/addslashes
13504    // +   original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
13505    // +   improved by: Ates Goral (http://magnetiq.com)
13506    // +   improved by: marrtins
13507    // +   improved by: Nate
13508    // +   improved by: Onno Marsman
13509    // +   input by: Denny Wardhana
13510    // +   improved by: Brett Zamir (http://brett-zamir.me)
13511    // +   improved by: Oskar Larsson Högfeldt (http://oskar-lh.name/)
13512    // *     example 1: \php.addslashes("kevin's birthday");
13513    // *     returns 1: 'kevin\'s birthday'
13514    return (str + '').replace(/[\\"']/g, '\\$&').replace(/\u0000/g, '\\0');
13515};
13516
13517php.array_chunk = function (input, size) {
13518    // Split array into chunks  
13519    // 
13520    // version: 1103.1210
13521    // discuss at: http://phpjs.org/functions/array_chunk
13522    // +   original by: Carlos R. L. Rodrigues (http://www.jsfromhell.com)
13523    // *     example 1: \php.array_chunk(['Kevin', 'van', 'Zonneveld'], 2);
13524    // *     returns 1: {0 : {0: 'Kevin', 1: 'van'} , 1 : {0: 'Zonneveld'}}
13525    for (var x, i = 0, c = -1, l = input.length, n = []; i < l; i++) {
13526        (x = i % size) ? n[c][x] = input[i] : n[++c] = [input[i]];
13527    }
13528
13529    return n;
13530};
13531
13532php.array_combine = function (keys, values) {
13533    // Creates an array by using the elements of the first parameter as keys and the elements of the second as the corresponding values  
13534    // 
13535    // version: 1103.1210
13536    // discuss at: http://phpjs.org/functions/array_combine
13537    // +   original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
13538    // +   improved by: Brett Zamir (http://brett-zamir.me)
13539    // *     example 1: \php.array_combine([0,1,2], ['kevin','van','zonneveld']);
13540    // *     returns 1: {0: 'kevin', 1: 'van', 2: 'zonneveld'}
13541    var new_array = {},
13542        keycount = keys && keys.length,
13543        i = 0;
13544
13545    // input sanitation
13546    if (typeof keys !== 'object' || typeof values !== 'object' || // Only accept arrays or array-like objects
13547    typeof keycount !== 'number' || typeof values.length !== 'number' || !keycount) { // Require arrays to have a count
13548        return false;
13549    }
13550
13551    // number of elements does not match
13552    if (keycount != values.length) {
13553        return false;
13554    }
13555
13556    for (i = 0; i < keycount; i++) {
13557        new_array[keys[i]] = values[i];
13558    }
13559
13560    return new_array;
13561};
13562
13563php.array_diff = function () {
13564    // Returns the entries of arr1 that have values which are not present in any of the others arguments.  
13565    // 
13566    // version: 1103.1210
13567    // discuss at: http://phpjs.org/functions/array_diff
13568    // +   original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
13569    // +   improved by: Sanjoy Roy
13570    // +    revised by: Brett Zamir (http://brett-zamir.me)
13571    // *     example 1: \php.array_diff(['Kevin', 'van', 'Zonneveld'], ['van', 'Zonneveld']);
13572    // *     returns 1: {0:'Kevin'}
13573    var arr1 = arguments[0],
13574        retArr = {};
13575    var k1 = '',
13576        i = 1,
13577        k = '',
13578        arr = {};
13579
13580    arr1keys: for (k1 in arr1) {
13581        for (i = 1; i < arguments.length; i++) {
13582            arr = arguments[i];
13583            for (k in arr) {
13584                if (arr[k] === arr1[k1]) {
13585                    // If it reaches here, it was found in at least one array, so try next value
13586                    continue arr1keys;
13587                }
13588            }
13589            retArr[k1] = arr1[k1];
13590        }
13591    }
13592
13593    return retArr;
13594};
13595
13596php.array_fill = function (start_index, num, mixed_val) {
13597    // Create an array containing num elements starting with index start_key each initialized to val  
13598    // 
13599    // version: 1103.1210
13600    // discuss at: http://phpjs.org/functions/array_fill
13601    // +   original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
13602    // +   improved by: Waldo Malqui Silva
13603    // *     example 1: \php.array_fill(5, 6, 'banana');
13604    // *     returns 1: { 5: 'banana', 6: 'banana', 7: 'banana', 8: 'banana', 9: 'banana', 10: 'banana' }
13605    var key, tmp_arr = {};
13606
13607    if (!isNaN(start_index) && !isNaN(num)) {
13608        for (key = 0; key < num; key++) {
13609            tmp_arr[(key + start_index)] = mixed_val;
13610        }
13611    }
13612
13613    return tmp_arr;
13614};
13615
13616php.array_fill_keys = function (keys, value) {
13617    // Create an array using the elements of the first parameter as keys each initialized to val  
13618    // 
13619    // version: 1103.1210
13620    // discuss at: http://phpjs.org/functions/array_fill_keys
13621    // +   original by: Brett Zamir (http://brett-zamir.me)
13622    // +   bugfixed by: Brett Zamir (http://brett-zamir.me)
13623    // *     example 1: \php.keys = {'a': 'foo', 2: 5, 3: 10, 4: 'bar'}
13624    // *     example 1: \php.array_fill_keys(keys, 'banana')
13625    // *     returns 1: {"foo": "banana", 5: "banana", 10: "banana", "bar": "banana"}
13626    var retObj = {},
13627        key = '';
13628
13629    for (key in keys) {
13630        retObj[keys[key]] = value;
13631    }
13632
13633    return retObj;
13634};
13635
13636php.array_filter = function (arr, func) {
13637    // Filters elements from the array via the callback.  
13638    // 
13639    // version: 1103.1210
13640    // discuss at: http://phpjs.org/functions/array_filter
13641    // +   original by: Brett Zamir (http://brett-zamir.me)
13642    // %        note 1: Takes a function as an argument, not a function's name
13643    // *     example 1: \php.var odd = function (num) {return (num & 1);}; 
13644    // *     example 1: \php.array_filter({"a": 1, "b": 2, "c": 3, "d": 4, "e": 5}, odd);
13645    // *     returns 1: {"a": 1, "c": 3, "e": 5}
13646    // *     example 2: \php.var even = function (num) {return (!(num & 1));}
13647    // *     example 2: \php.array_filter([6, 7, 8, 9, 10, 11, 12], even);
13648    // *     returns 2: {0: 6, 2: 8, 4: 10, 6: 12} 
13649    var retObj = {},
13650        k;
13651
13652    for (k in arr) {
13653        if (func(arr[k])) {
13654            retObj[k] = arr[k];
13655        }
13656    }
13657
13658    return retObj;
13659};
13660
13661php.array_flip = function (trans) {
13662    // Return array with key <-> value flipped  
13663    // 
13664    // version: 1103.1210
13665    // discuss at: http://phpjs.org/functions/array_flip
13666    // +   original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
13667    // *     example 1: \php.array_flip( {a: 1, b: 1, c: 2} );
13668    // *     returns 1: {1: 'b', 2: 'c'}
13669    var key, tmp_ar = {};
13670
13671    for (key in trans) {
13672        tmp_ar[trans[key]] = key;
13673    }
13674
13675    return tmp_ar;
13676};
13677
13678php.array_intersect = function () {
13679    // Returns the entries of arr1 that have values which are present in all the other arguments  
13680    // 
13681    // version: 1103.1210
13682    // discuss at: http://phpjs.org/functions/array_intersect
13683    // +   original by: Brett Zamir (http://brett-zamir.me)
13684    // %        note 1: These only output associative arrays (would need to be
13685    // %        note 1: all numeric and counting from zero to be numeric)
13686    // *     example 1: $array1 = {'a' : 'green', 0:'red', 1: 'blue'};
13687    // *     example 1: $array2 = {'b' : 'green', 0:'yellow', 1:'red'};
13688    // *     example 1: $array3 = ['green', 'red'];
13689    // *     example 1: $result = array_intersect($array1, $array2, $array3);
13690    // *     returns 1: {0: 'red', a: 'green'}
13691    var arr1 = arguments[0],
13692        retArr = {};
13693    var k1 = '',
13694        arr = {},
13695        i = 0,
13696        k = '';
13697
13698    arr1keys: for (k1 in arr1) {
13699        arrs: for (i = 1; i < arguments.length; i++) {
13700            arr = arguments[i];
13701            for (k in arr) {
13702                if (arr[k] === arr1[k1]) {
13703                    if (i === arguments.length - 1) {
13704                        retArr[k1] = arr1[k1];
13705                    }
13706                    // If the innermost loop always leads at least once to an equal value, continue the loop until done
13707                    continue arrs;
13708                }
13709            }
13710            // If it reaches here, it wasn't found in at least one array, so try next value
13711            continue arr1keys;
13712        }
13713    }
13714
13715    return retArr;
13716};
13717
13718php.array_key_exists = function (key, search) {
13719    // Checks if the given key or index exists in the array  
13720    // 
13721    // version: 1103.1210
13722    // discuss at: http://phpjs.org/functions/array_key_exists
13723    // +   original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
13724    // +   improved by: Felix Geisendoerfer (http://www.debuggable.com/felix)
13725    // *     example 1: \php.array_key_exists('kevin', {'kevin': 'van Zonneveld'});
13726    // *     returns 1: true
13727    // input sanitation
13728    if (!search || (search.constructor !== Array && search.constructor !== Object)) {
13729        return false;
13730    }
13731
13732    return key in search;
13733};
13734
13735php.array_keys = function (input, search_value, argStrict) {
13736    // Return just the keys from the input array, optionally only for the specified search_value  
13737    // 
13738    // version: 1103.1210
13739    // discuss at: http://phpjs.org/functions/array_keys
13740    // +   original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
13741    // +      input by: Brett Zamir (http://brett-zamir.me)
13742    // +   bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
13743    // +   improved by: jd
13744    // +   improved by: Brett Zamir (http://brett-zamir.me)
13745    // *     example 1: \php.array_keys( {firstname: 'Kevin', surname: 'van Zonneveld'} );
13746    // *     returns 1: {0: 'firstname', 1: 'surname'}
13747    var search = typeof search_value !== 'undefined',
13748        tmp_arr = [],
13749        strict = !!argStrict,
13750        include = true,
13751        key = '';
13752
13753    for (key in input) {
13754        if (input.hasOwnProperty(key)) {
13755            include = true;
13756            if (search) {
13757                if (strict && input[key] !== search_value) {
13758                    include = false;
13759                }
13760                else if (input[key] != search_value) {
13761                    include = false;
13762                }
13763            }
13764
13765            if (include) {
13766                tmp_arr[tmp_arr.length] = key;
13767            }
13768        }
13769    }
13770
13771    return tmp_arr;
13772};
13773
13774php.array_map = function (callback) {
13775    // Applies the callback to the elements in given arrays.  
13776    // 
13777    // version: 1103.1210
13778    // discuss at: http://phpjs.org/functions/array_map
13779    // +   original by: Andrea Giammarchi (http://webreflection.blogspot.com)
13780    // +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
13781    // +   improved by: Brett Zamir (http://brett-zamir.me)
13782    // %        note 1: Takes a function as an argument, not a function's name
13783    // %        note 2: If the callback is a string, it can only work if the function name is in the global context
13784    // *     example 1: \php.array_map( function (a){return (a * a * a)}, [1, 2, 3, 4, 5] );
13785    // *     returns 1: [ 1, 8, 27, 64, 125 ]
13786    var argc = arguments.length,
13787        argv = arguments;
13788    var j = argv[1].length,
13789        i = 0,
13790        k = 1,
13791        m = 0;
13792    var tmp = [],
13793        tmp_ar = [];
13794
13795    while (i < j) {
13796        while (k < argc) {
13797            tmp[m++] = argv[k++][i];
13798        }
13799
13800        m = 0;
13801        k = 1;
13802
13803        if (callback) {
13804            if (typeof callback === 'string') {
13805                callback = this.window[callback];
13806            }
13807            tmp_ar[i++] = callback.apply(null, tmp);
13808        } else {
13809            tmp_ar[i++] = tmp;
13810        }
13811
13812        tmp = [];
13813    }
13814
13815    return tmp_ar;
13816};
13817
13818php.array_merge = function () {
13819    // Merges elements from passed arrays into one array  
13820    // 
13821    // version: 1103.1210
13822    // discuss at: http://phpjs.org/functions/array_merge
13823    // +   original by: Brett Zamir (http://brett-zamir.me)
13824    // +   bugfixed by: Nate
13825    // +   input by: josh
13826    // +   bugfixed by: Brett Zamir (http://brett-zamir.me)
13827    // *     example 1: \php.arr1 = {"color": "red", 0: 2, 1: 4}
13828    // *     example 1: \php.arr2 = {0: "a", 1: "b", "color": "green", "shape": "trapezoid", 2: 4}
13829    // *     example 1: \php.array_merge(arr1, arr2)
13830    // *     returns 1: {"color": "green", 0: 2, 1: 4, 2: "a", 3: "b", "shape": "trapezoid", 4: 4}
13831    // *     example 2: \php.arr1 = []
13832    // *     example 2: \php.arr2 = {1: "data"}
13833    // *     example 2: \php.array_merge(arr1, arr2)
13834    // *     returns 2: {0: "data"}
13835    var args = Array.prototype.slice.call(arguments),
13836        retObj = {},
13837        k, j = 0,
13838        i = 0,
13839        retArr = true;
13840
13841    for (i = 0; i < args.length; i++) {
13842        if (!(args[i] instanceof Array)) {
13843            retArr = false;
13844            break;
13845        }
13846    }
13847
13848    if (retArr) {
13849        retArr = [];
13850        for (i = 0; i < args.length; i++) {
13851            retArr = retArr.concat(args[i]);
13852        }
13853        return retArr;
13854    }
13855    var ct = 0;
13856
13857    for (i = 0, ct = 0; i < args.length; i++) {
13858        if (args[i] instanceof Array) {
13859            for (j = 0; j < args[i].length; j++) {
13860                retObj[ct++] = args[i][j];
13861            }
13862        } else {
13863            for (k in args[i]) {
13864                if (args[i].hasOwnProperty(k)) {
13865                    if (parseInt(k, 10) + '' === k) {
13866                        retObj[ct++] = args[i][k];
13867                    } else {
13868                        retObj[k] = args[i][k];
13869                    }
13870                }
13871            }
13872        }
13873    }
13874    return retObj;
13875};
13876
13877php.array_merge_recursive = function (arr1, arr2) {
13878    // Recursively merges elements from passed arrays into one array  
13879    // 
13880    // version: 1103.1210
13881    // discuss at: http://phpjs.org/functions/array_merge_recursive
13882    // +   original by: Subhasis Deb
13883    // +      input by: Brett Zamir (http://brett-zamir.me)
13884    // +   bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
13885    // -    depends on: array_merge
13886    // *     example 1: \php.arr1 = {'color': {'favourite': 'read'}, 0: 5}
13887    // *     example 1: \php.arr2 = {0: 10, 'color': {'favorite': 'green', 0: 'blue'}}
13888    // *     example 1: \php.array_merge_recursive(arr1, arr2)
13889    // *     returns 1: {'color': {'favorite': {0: 'red', 1: 'green'}, 0: 'blue'}, 1: 5, 1: 10}
13890    var idx = '';
13891
13892    if ((arr1 && (arr1 instanceof Array)) && (arr2 && (arr2 instanceof Array))) {
13893        for (idx in arr2) {
13894            arr1.push(arr2[idx]);
13895        }
13896    } else if ((arr1 && (arr1 instanceof Object)) && (arr2 && (arr2 instanceof Object))) {
13897        for (idx in arr2) {
13898            if (idx in arr1) {
13899                if (typeof arr1[idx] == 'object' && typeof arr2 == 'object') {
13900                    arr1[idx] = this.array_merge(arr1[idx], arr2[idx]);
13901                } else {
13902                    arr1[idx] = arr2[idx];
13903                }
13904            } else {
13905                arr1[idx] = arr2[idx];
13906            }
13907        }
13908    }
13909
13910    return arr1;
13911};
13912
13913php.array_pop = function (inputArr) {
13914    // Pops an element off the end of the array  
13915    // 
13916    // version: 1103.1210
13917    // discuss at: http://phpjs.org/functions/array_pop
13918    // +   original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
13919    // +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
13920    // +      input by: Brett Zamir (http://brett-zamir.me)
13921    // +   bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
13922    // +   bugfixed by: Brett Zamir (http://brett-zamir.me)
13923    // +   input by: Theriault
13924    // %        note 1: While IE (and other browsers) support iterating an object's
13925    // %        note 1: own properties in order, if one attempts to add back properties
13926    // %        note 1: in IE, they may end up in their former position due to their position
13927    // %        note 1: being retained. So use of this function with "associative arrays"
13928    // %        note 1: (objects) may lead to unexpected behavior in an IE environment if
13929    // %        note 1: you add back properties with the same keys that you removed
13930