Upgrade to ExtJS 4.0.7 - Released 10/19/2011
[extjs.git] / builds / ext-foundation-dev.js
1 /*
2
3 This file is part of Ext JS 4
4
5 Copyright (c) 2011 Sencha Inc
6
7 Contact:  http://www.sencha.com/contact
8
9 GNU General Public License Usage
10 This file may be used under the terms of the GNU General Public License version 3.0 as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file.  Please review the following information to ensure the GNU General Public License version 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
11
12 If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
13
14 */
15 /**
16  * @class Ext
17  * @singleton
18  */
19 (function() {
20     var global = this,
21         objectPrototype = Object.prototype,
22         toString = objectPrototype.toString,
23         enumerables = true,
24         enumerablesTest = { toString: 1 },
25         i;
26
27     if (typeof Ext === 'undefined') {
28         global.Ext = {};
29     }
30
31     Ext.global = global;
32
33     for (i in enumerablesTest) {
34         enumerables = null;
35     }
36
37     if (enumerables) {
38         enumerables = ['hasOwnProperty', 'valueOf', 'isPrototypeOf', 'propertyIsEnumerable',
39                        'toLocaleString', 'toString', 'constructor'];
40     }
41
42     /**
43      * An array containing extra enumerables for old browsers
44      * @property {String[]}
45      */
46     Ext.enumerables = enumerables;
47
48     /**
49      * Copies all the properties of config to the specified object.
50      * Note that if recursive merging and cloning without referencing the original objects / arrays is needed, use
51      * {@link Ext.Object#merge} instead.
52      * @param {Object} object The receiver of the properties
53      * @param {Object} config The source of the properties
54      * @param {Object} defaults A different object that will also be applied for default values
55      * @return {Object} returns obj
56      */
57     Ext.apply = function(object, config, defaults) {
58         if (defaults) {
59             Ext.apply(object, defaults);
60         }
61
62         if (object && config && typeof config === 'object') {
63             var i, j, k;
64
65             for (i in config) {
66                 object[i] = config[i];
67             }
68
69             if (enumerables) {
70                 for (j = enumerables.length; j--;) {
71                     k = enumerables[j];
72                     if (config.hasOwnProperty(k)) {
73                         object[k] = config[k];
74                     }
75                 }
76             }
77         }
78
79         return object;
80     };
81
82     Ext.buildSettings = Ext.apply({
83         baseCSSPrefix: 'x-',
84         scopeResetCSS: false
85     }, Ext.buildSettings || {});
86
87     Ext.apply(Ext, {
88         /**
89          * A reusable empty function
90          */
91         emptyFn: function() {},
92
93         baseCSSPrefix: Ext.buildSettings.baseCSSPrefix,
94
95         /**
96          * Copies all the properties of config to object if they don't already exist.
97          * @param {Object} object The receiver of the properties
98          * @param {Object} config The source of the properties
99          * @return {Object} returns obj
100          */
101         applyIf: function(object, config) {
102             var property;
103
104             if (object) {
105                 for (property in config) {
106                     if (object[property] === undefined) {
107                         object[property] = config[property];
108                     }
109                 }
110             }
111
112             return object;
113         },
114
115         /**
116          * Iterates either an array or an object. This method delegates to
117          * {@link Ext.Array#each Ext.Array.each} if the given value is iterable, and {@link Ext.Object#each Ext.Object.each} otherwise.
118          *
119          * @param {Object/Array} object The object or array to be iterated.
120          * @param {Function} fn The function to be called for each iteration. See and {@link Ext.Array#each Ext.Array.each} and
121          * {@link Ext.Object#each Ext.Object.each} for detailed lists of arguments passed to this function depending on the given object
122          * type that is being iterated.
123          * @param {Object} scope (Optional) The scope (`this` reference) in which the specified function is executed.
124          * Defaults to the object being iterated itself.
125          * @markdown
126          */
127         iterate: function(object, fn, scope) {
128             if (Ext.isEmpty(object)) {
129                 return;
130             }
131
132             if (scope === undefined) {
133                 scope = object;
134             }
135
136             if (Ext.isIterable(object)) {
137                 Ext.Array.each.call(Ext.Array, object, fn, scope);
138             }
139             else {
140                 Ext.Object.each.call(Ext.Object, object, fn, scope);
141             }
142         }
143     });
144
145     Ext.apply(Ext, {
146
147         /**
148          * This method deprecated. Use {@link Ext#define Ext.define} instead.
149          * @method
150          * @param {Function} superclass
151          * @param {Object} overrides
152          * @return {Function} The subclass constructor from the <tt>overrides</tt> parameter, or a generated one if not provided.
153          * @deprecated 4.0.0 Use {@link Ext#define Ext.define} instead
154          */
155         extend: function() {
156             // inline overrides
157             var objectConstructor = objectPrototype.constructor,
158                 inlineOverrides = function(o) {
159                 for (var m in o) {
160                     if (!o.hasOwnProperty(m)) {
161                         continue;
162                     }
163                     this[m] = o[m];
164                 }
165             };
166
167             return function(subclass, superclass, overrides) {
168                 // First we check if the user passed in just the superClass with overrides
169                 if (Ext.isObject(superclass)) {
170                     overrides = superclass;
171                     superclass = subclass;
172                     subclass = overrides.constructor !== objectConstructor ? overrides.constructor : function() {
173                         superclass.apply(this, arguments);
174                     };
175                 }
176
177                 if (!superclass) {
178                     Ext.Error.raise({
179                         sourceClass: 'Ext',
180                         sourceMethod: 'extend',
181                         msg: 'Attempting to extend from a class which has not been loaded on the page.'
182                     });
183                 }
184
185                 // We create a new temporary class
186                 var F = function() {},
187                     subclassProto, superclassProto = superclass.prototype;
188
189                 F.prototype = superclassProto;
190                 subclassProto = subclass.prototype = new F();
191                 subclassProto.constructor = subclass;
192                 subclass.superclass = superclassProto;
193
194                 if (superclassProto.constructor === objectConstructor) {
195                     superclassProto.constructor = superclass;
196                 }
197
198                 subclass.override = function(overrides) {
199                     Ext.override(subclass, overrides);
200                 };
201
202                 subclassProto.override = inlineOverrides;
203                 subclassProto.proto = subclassProto;
204
205                 subclass.override(overrides);
206                 subclass.extend = function(o) {
207                     return Ext.extend(subclass, o);
208                 };
209
210                 return subclass;
211             };
212         }(),
213
214         /**
215          * Proxy to {@link Ext.Base#override}. Please refer {@link Ext.Base#override} for further details.
216
217     Ext.define('My.cool.Class', {
218         sayHi: function() {
219             alert('Hi!');
220         }
221     }
222
223     Ext.override(My.cool.Class, {
224         sayHi: function() {
225             alert('About to say...');
226
227             this.callOverridden();
228         }
229     });
230
231     var cool = new My.cool.Class();
232     cool.sayHi(); // alerts 'About to say...'
233                   // alerts 'Hi!'
234
235          * Please note that `this.callOverridden()` only works if the class was previously
236          * created with {@link Ext#define)
237          *
238          * @param {Object} cls The class to override
239          * @param {Object} overrides The list of functions to add to origClass. This should be specified as an object literal
240          * containing one or more methods.
241          * @method override
242          * @markdown
243          */
244         override: function(cls, overrides) {
245             if (cls.prototype.$className) {
246                 return cls.override(overrides);
247             }
248             else {
249                 Ext.apply(cls.prototype, overrides);
250             }
251         }
252     });
253
254     // A full set of static methods to do type checking
255     Ext.apply(Ext, {
256
257         /**
258          * Returns the given value itself if it's not empty, as described in {@link Ext#isEmpty}; returns the default
259          * value (second argument) otherwise.
260          *
261          * @param {Object} value The value to test
262          * @param {Object} defaultValue The value to return if the original value is empty
263          * @param {Boolean} allowBlank (optional) true to allow zero length strings to qualify as non-empty (defaults to false)
264          * @return {Object} value, if non-empty, else defaultValue
265          */
266         valueFrom: function(value, defaultValue, allowBlank){
267             return Ext.isEmpty(value, allowBlank) ? defaultValue : value;
268         },
269
270         /**
271          * Returns the type of the given variable in string format. List of possible values are:
272          *
273          * - `undefined`: If the given value is `undefined`
274          * - `null`: If the given value is `null`
275          * - `string`: If the given value is a string
276          * - `number`: If the given value is a number
277          * - `boolean`: If the given value is a boolean value
278          * - `date`: If the given value is a `Date` object
279          * - `function`: If the given value is a function reference
280          * - `object`: If the given value is an object
281          * - `array`: If the given value is an array
282          * - `regexp`: If the given value is a regular expression
283          * - `element`: If the given value is a DOM Element
284          * - `textnode`: If the given value is a DOM text node and contains something other than whitespace
285          * - `whitespace`: If the given value is a DOM text node and contains only whitespace
286          *
287          * @param {Object} value
288          * @return {String}
289          * @markdown
290          */
291         typeOf: function(value) {
292             if (value === null) {
293                 return 'null';
294             }
295
296             var type = typeof value;
297
298             if (type === 'undefined' || type === 'string' || type === 'number' || type === 'boolean') {
299                 return type;
300             }
301
302             var typeToString = toString.call(value);
303
304             switch(typeToString) {
305                 case '[object Array]':
306                     return 'array';
307                 case '[object Date]':
308                     return 'date';
309                 case '[object Boolean]':
310                     return 'boolean';
311                 case '[object Number]':
312                     return 'number';
313                 case '[object RegExp]':
314                     return 'regexp';
315             }
316
317             if (type === 'function') {
318                 return 'function';
319             }
320
321             if (type === 'object') {
322                 if (value.nodeType !== undefined) {
323                     if (value.nodeType === 3) {
324                         return (/\S/).test(value.nodeValue) ? 'textnode' : 'whitespace';
325                     }
326                     else {
327                         return 'element';
328                     }
329                 }
330
331                 return 'object';
332             }
333
334             Ext.Error.raise({
335                 sourceClass: 'Ext',
336                 sourceMethod: 'typeOf',
337                 msg: 'Failed to determine the type of the specified value "' + value + '". This is most likely a bug.'
338             });
339         },
340
341         /**
342          * Returns true if the passed value is empty, false otherwise. The value is deemed to be empty if it is either:
343          *
344          * - `null`
345          * - `undefined`
346          * - a zero-length array
347          * - a zero-length string (Unless the `allowEmptyString` parameter is set to `true`)
348          *
349          * @param {Object} value The value to test
350          * @param {Boolean} allowEmptyString (optional) true to allow empty strings (defaults to false)
351          * @return {Boolean}
352          * @markdown
353          */
354         isEmpty: function(value, allowEmptyString) {
355             return (value === null) || (value === undefined) || (!allowEmptyString ? value === '' : false) || (Ext.isArray(value) && value.length === 0);
356         },
357
358         /**
359          * Returns true if the passed value is a JavaScript Array, false otherwise.
360          *
361          * @param {Object} target The target to test
362          * @return {Boolean}
363          * @method
364          */
365         isArray: ('isArray' in Array) ? Array.isArray : function(value) {
366             return toString.call(value) === '[object Array]';
367         },
368
369         /**
370          * Returns true if the passed value is a JavaScript Date object, false otherwise.
371          * @param {Object} object The object to test
372          * @return {Boolean}
373          */
374         isDate: function(value) {
375             return toString.call(value) === '[object Date]';
376         },
377
378         /**
379          * Returns true if the passed value is a JavaScript Object, false otherwise.
380          * @param {Object} value The value to test
381          * @return {Boolean}
382          * @method
383          */
384         isObject: (toString.call(null) === '[object Object]') ?
385         function(value) {
386             // check ownerDocument here as well to exclude DOM nodes
387             return value !== null && value !== undefined && toString.call(value) === '[object Object]' && value.ownerDocument === undefined;
388         } :
389         function(value) {
390             return toString.call(value) === '[object Object]';
391         },
392
393         /**
394          * Returns true if the passed value is a JavaScript 'primitive', a string, number or boolean.
395          * @param {Object} value The value to test
396          * @return {Boolean}
397          */
398         isPrimitive: function(value) {
399             var type = typeof value;
400
401             return type === 'string' || type === 'number' || type === 'boolean';
402         },
403
404         /**
405          * Returns true if the passed value is a JavaScript Function, false otherwise.
406          * @param {Object} value The value to test
407          * @return {Boolean}
408          * @method
409          */
410         isFunction:
411         // Safari 3.x and 4.x returns 'function' for typeof <NodeList>, hence we need to fall back to using
412         // Object.prorotype.toString (slower)
413         (typeof document !== 'undefined' && typeof document.getElementsByTagName('body') === 'function') ? function(value) {
414             return toString.call(value) === '[object Function]';
415         } : function(value) {
416             return typeof value === 'function';
417         },
418
419         /**
420          * Returns true if the passed value is a number. Returns false for non-finite numbers.
421          * @param {Object} value The value to test
422          * @return {Boolean}
423          */
424         isNumber: function(value) {
425             return typeof value === 'number' && isFinite(value);
426         },
427
428         /**
429          * Validates that a value is numeric.
430          * @param {Object} value Examples: 1, '1', '2.34'
431          * @return {Boolean} True if numeric, false otherwise
432          */
433         isNumeric: function(value) {
434             return !isNaN(parseFloat(value)) && isFinite(value);
435         },
436
437         /**
438          * Returns true if the passed value is a string.
439          * @param {Object} value The value to test
440          * @return {Boolean}
441          */
442         isString: function(value) {
443             return typeof value === 'string';
444         },
445
446         /**
447          * Returns true if the passed value is a boolean.
448          *
449          * @param {Object} value The value to test
450          * @return {Boolean}
451          */
452         isBoolean: function(value) {
453             return typeof value === 'boolean';
454         },
455
456         /**
457          * Returns true if the passed value is an HTMLElement
458          * @param {Object} value The value to test
459          * @return {Boolean}
460          */
461         isElement: function(value) {
462             return value ? value.nodeType === 1 : false;
463         },
464
465         /**
466          * Returns true if the passed value is a TextNode
467          * @param {Object} value The value to test
468          * @return {Boolean}
469          */
470         isTextNode: function(value) {
471             return value ? value.nodeName === "#text" : false;
472         },
473
474         /**
475          * Returns true if the passed value is defined.
476          * @param {Object} value The value to test
477          * @return {Boolean}
478          */
479         isDefined: function(value) {
480             return typeof value !== 'undefined';
481         },
482
483         /**
484          * Returns true if the passed value is iterable, false otherwise
485          * @param {Object} value The value to test
486          * @return {Boolean}
487          */
488         isIterable: function(value) {
489             return (value && typeof value !== 'string') ? value.length !== undefined : false;
490         }
491     });
492
493     Ext.apply(Ext, {
494
495         /**
496          * Clone almost any type of variable including array, object, DOM nodes and Date without keeping the old reference
497          * @param {Object} item The variable to clone
498          * @return {Object} clone
499          */
500         clone: function(item) {
501             if (item === null || item === undefined) {
502                 return item;
503             }
504
505             // DOM nodes
506             // TODO proxy this to Ext.Element.clone to handle automatic id attribute changing
507             // recursively
508             if (item.nodeType && item.cloneNode) {
509                 return item.cloneNode(true);
510             }
511
512             var type = toString.call(item);
513
514             // Date
515             if (type === '[object Date]') {
516                 return new Date(item.getTime());
517             }
518
519             var i, j, k, clone, key;
520
521             // Array
522             if (type === '[object Array]') {
523                 i = item.length;
524
525                 clone = [];
526
527                 while (i--) {
528                     clone[i] = Ext.clone(item[i]);
529                 }
530             }
531             // Object
532             else if (type === '[object Object]' && item.constructor === Object) {
533                 clone = {};
534
535                 for (key in item) {
536                     clone[key] = Ext.clone(item[key]);
537                 }
538
539                 if (enumerables) {
540                     for (j = enumerables.length; j--;) {
541                         k = enumerables[j];
542                         clone[k] = item[k];
543                     }
544                 }
545             }
546
547             return clone || item;
548         },
549
550         /**
551          * @private
552          * Generate a unique reference of Ext in the global scope, useful for sandboxing
553          */
554         getUniqueGlobalNamespace: function() {
555             var uniqueGlobalNamespace = this.uniqueGlobalNamespace;
556
557             if (uniqueGlobalNamespace === undefined) {
558                 var i = 0;
559
560                 do {
561                     uniqueGlobalNamespace = 'ExtBox' + (++i);
562                 } while (Ext.global[uniqueGlobalNamespace] !== undefined);
563
564                 Ext.global[uniqueGlobalNamespace] = Ext;
565                 this.uniqueGlobalNamespace = uniqueGlobalNamespace;
566             }
567
568             return uniqueGlobalNamespace;
569         },
570
571         /**
572          * @private
573          */
574         functionFactory: function() {
575             var args = Array.prototype.slice.call(arguments);
576
577             if (args.length > 0) {
578                 args[args.length - 1] = 'var Ext=window.' + this.getUniqueGlobalNamespace() + ';' +
579                     args[args.length - 1];
580             }
581
582             return Function.prototype.constructor.apply(Function.prototype, args);
583         }
584     });
585
586     /**
587      * Old alias to {@link Ext#typeOf}
588      * @deprecated 4.0.0 Use {@link Ext#typeOf} instead
589      * @method
590      * @alias Ext#typeOf
591      */
592     Ext.type = Ext.typeOf;
593
594 })();
595
596 /**
597  * @author Jacky Nguyen <jacky@sencha.com>
598  * @docauthor Jacky Nguyen <jacky@sencha.com>
599  * @class Ext.Version
600  *
601  * A utility class that wrap around a string version number and provide convenient
602  * method to perform comparison. See also: {@link Ext.Version#compare compare}. Example:
603
604     var version = new Ext.Version('1.0.2beta');
605     console.log("Version is " + version); // Version is 1.0.2beta
606
607     console.log(version.getMajor()); // 1
608     console.log(version.getMinor()); // 0
609     console.log(version.getPatch()); // 2
610     console.log(version.getBuild()); // 0
611     console.log(version.getRelease()); // beta
612
613     console.log(version.isGreaterThan('1.0.1')); // True
614     console.log(version.isGreaterThan('1.0.2alpha')); // True
615     console.log(version.isGreaterThan('1.0.2RC')); // False
616     console.log(version.isGreaterThan('1.0.2')); // False
617     console.log(version.isLessThan('1.0.2')); // True
618
619     console.log(version.match(1.0)); // True
620     console.log(version.match('1.0.2')); // True
621
622  * @markdown
623  */
624 (function() {
625
626 // Current core version
627 var version = '4.0.7', Version;
628     Ext.Version = Version = Ext.extend(Object, {
629
630         /**
631          * @param {String/Number} version The version number in the follow standard format: major[.minor[.patch[.build[release]]]]
632          * Examples: 1.0 or 1.2.3beta or 1.2.3.4RC
633          * @return {Ext.Version} this
634          */
635         constructor: function(version) {
636             var parts, releaseStartIndex;
637
638             if (version instanceof Version) {
639                 return version;
640             }
641
642             this.version = this.shortVersion = String(version).toLowerCase().replace(/_/g, '.').replace(/[\-+]/g, '');
643
644             releaseStartIndex = this.version.search(/([^\d\.])/);
645
646             if (releaseStartIndex !== -1) {
647                 this.release = this.version.substr(releaseStartIndex, version.length);
648                 this.shortVersion = this.version.substr(0, releaseStartIndex);
649             }
650
651             this.shortVersion = this.shortVersion.replace(/[^\d]/g, '');
652
653             parts = this.version.split('.');
654
655             this.major = parseInt(parts.shift() || 0, 10);
656             this.minor = parseInt(parts.shift() || 0, 10);
657             this.patch = parseInt(parts.shift() || 0, 10);
658             this.build = parseInt(parts.shift() || 0, 10);
659
660             return this;
661         },
662
663         /**
664          * Override the native toString method
665          * @private
666          * @return {String} version
667          */
668         toString: function() {
669             return this.version;
670         },
671
672         /**
673          * Override the native valueOf method
674          * @private
675          * @return {String} version
676          */
677         valueOf: function() {
678             return this.version;
679         },
680
681         /**
682          * Returns the major component value
683          * @return {Number} major
684          */
685         getMajor: function() {
686             return this.major || 0;
687         },
688
689         /**
690          * Returns the minor component value
691          * @return {Number} minor
692          */
693         getMinor: function() {
694             return this.minor || 0;
695         },
696
697         /**
698          * Returns the patch component value
699          * @return {Number} patch
700          */
701         getPatch: function() {
702             return this.patch || 0;
703         },
704
705         /**
706          * Returns the build component value
707          * @return {Number} build
708          */
709         getBuild: function() {
710             return this.build || 0;
711         },
712
713         /**
714          * Returns the release component value
715          * @return {Number} release
716          */
717         getRelease: function() {
718             return this.release || '';
719         },
720
721         /**
722          * Returns whether this version if greater than the supplied argument
723          * @param {String/Number} target The version to compare with
724          * @return {Boolean} True if this version if greater than the target, false otherwise
725          */
726         isGreaterThan: function(target) {
727             return Version.compare(this.version, target) === 1;
728         },
729
730         /**
731          * Returns whether this version if smaller than the supplied argument
732          * @param {String/Number} target The version to compare with
733          * @return {Boolean} True if this version if smaller than the target, false otherwise
734          */
735         isLessThan: function(target) {
736             return Version.compare(this.version, target) === -1;
737         },
738
739         /**
740          * Returns whether this version equals to the supplied argument
741          * @param {String/Number} target The version to compare with
742          * @return {Boolean} True if this version equals to the target, false otherwise
743          */
744         equals: function(target) {
745             return Version.compare(this.version, target) === 0;
746         },
747
748         /**
749          * Returns whether this version matches the supplied argument. Example:
750          * <pre><code>
751          * var version = new Ext.Version('1.0.2beta');
752          * console.log(version.match(1)); // True
753          * console.log(version.match(1.0)); // True
754          * console.log(version.match('1.0.2')); // True
755          * console.log(version.match('1.0.2RC')); // False
756          * </code></pre>
757          * @param {String/Number} target The version to compare with
758          * @return {Boolean} True if this version matches the target, false otherwise
759          */
760         match: function(target) {
761             target = String(target);
762             return this.version.substr(0, target.length) === target;
763         },
764
765         /**
766          * Returns this format: [major, minor, patch, build, release]. Useful for comparison
767          * @return {Number[]}
768          */
769         toArray: function() {
770             return [this.getMajor(), this.getMinor(), this.getPatch(), this.getBuild(), this.getRelease()];
771         },
772
773         /**
774          * Returns shortVersion version without dots and release
775          * @return {String}
776          */
777         getShortVersion: function() {
778             return this.shortVersion;
779         }
780     });
781
782     Ext.apply(Version, {
783         // @private
784         releaseValueMap: {
785             'dev': -6,
786             'alpha': -5,
787             'a': -5,
788             'beta': -4,
789             'b': -4,
790             'rc': -3,
791             '#': -2,
792             'p': -1,
793             'pl': -1
794         },
795
796         /**
797          * Converts a version component to a comparable value
798          *
799          * @static
800          * @param {Object} value The value to convert
801          * @return {Object}
802          */
803         getComponentValue: function(value) {
804             return !value ? 0 : (isNaN(value) ? this.releaseValueMap[value] || value : parseInt(value, 10));
805         },
806
807         /**
808          * Compare 2 specified versions, starting from left to right. If a part contains special version strings,
809          * they are handled in the following order:
810          * 'dev' < 'alpha' = 'a' < 'beta' = 'b' < 'RC' = 'rc' < '#' < 'pl' = 'p' < 'anything else'
811          *
812          * @static
813          * @param {String} current The current version to compare to
814          * @param {String} target The target version to compare to
815          * @return {Number} Returns -1 if the current version is smaller than the target version, 1 if greater, and 0 if they're equivalent
816          */
817         compare: function(current, target) {
818             var currentValue, targetValue, i;
819
820             current = new Version(current).toArray();
821             target = new Version(target).toArray();
822
823             for (i = 0; i < Math.max(current.length, target.length); i++) {
824                 currentValue = this.getComponentValue(current[i]);
825                 targetValue = this.getComponentValue(target[i]);
826
827                 if (currentValue < targetValue) {
828                     return -1;
829                 } else if (currentValue > targetValue) {
830                     return 1;
831                 }
832             }
833
834             return 0;
835         }
836     });
837
838     Ext.apply(Ext, {
839         /**
840          * @private
841          */
842         versions: {},
843
844         /**
845          * @private
846          */
847         lastRegisteredVersion: null,
848
849         /**
850          * Set version number for the given package name.
851          *
852          * @param {String} packageName The package name, for example: 'core', 'touch', 'extjs'
853          * @param {String/Ext.Version} version The version, for example: '1.2.3alpha', '2.4.0-dev'
854          * @return {Ext}
855          */
856         setVersion: function(packageName, version) {
857             Ext.versions[packageName] = new Version(version);
858             Ext.lastRegisteredVersion = Ext.versions[packageName];
859
860             return this;
861         },
862
863         /**
864          * Get the version number of the supplied package name; will return the last registered version
865          * (last Ext.setVersion call) if there's no package name given.
866          *
867          * @param {String} packageName (Optional) The package name, for example: 'core', 'touch', 'extjs'
868          * @return {Ext.Version} The version
869          */
870         getVersion: function(packageName) {
871             if (packageName === undefined) {
872                 return Ext.lastRegisteredVersion;
873             }
874
875             return Ext.versions[packageName];
876         },
877
878         /**
879          * Create a closure for deprecated code.
880          *
881     // This means Ext.oldMethod is only supported in 4.0.0beta and older.
882     // If Ext.getVersion('extjs') returns a version that is later than '4.0.0beta', for example '4.0.0RC',
883     // the closure will not be invoked
884     Ext.deprecate('extjs', '4.0.0beta', function() {
885         Ext.oldMethod = Ext.newMethod;
886
887         ...
888     });
889
890          * @param {String} packageName The package name
891          * @param {String} since The last version before it's deprecated
892          * @param {Function} closure The callback function to be executed with the specified version is less than the current version
893          * @param {Object} scope The execution scope (<tt>this</tt>) if the closure
894          * @markdown
895          */
896         deprecate: function(packageName, since, closure, scope) {
897             if (Version.compare(Ext.getVersion(packageName), since) < 1) {
898                 closure.call(scope);
899             }
900         }
901     }); // End Versioning
902
903     Ext.setVersion('core', version);
904
905 })();
906
907 /**
908  * @class Ext.String
909  *
910  * A collection of useful static methods to deal with strings
911  * @singleton
912  */
913
914 Ext.String = {
915     trimRegex: /^[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u2028\u2029\u202f\u205f\u3000]+|[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u2028\u2029\u202f\u205f\u3000]+$/g,
916     escapeRe: /('|\\)/g,
917     formatRe: /\{(\d+)\}/g,
918     escapeRegexRe: /([-.*+?^${}()|[\]\/\\])/g,
919
920     /**
921      * Convert certain characters (&, <, >, and ") to their HTML character equivalents for literal display in web pages.
922      * @param {String} value The string to encode
923      * @return {String} The encoded text
924      * @method
925      */
926     htmlEncode: (function() {
927         var entities = {
928             '&': '&amp;',
929             '>': '&gt;',
930             '<': '&lt;',
931             '"': '&quot;'
932         }, keys = [], p, regex;
933         
934         for (p in entities) {
935             keys.push(p);
936         }
937         
938         regex = new RegExp('(' + keys.join('|') + ')', 'g');
939         
940         return function(value) {
941             return (!value) ? value : String(value).replace(regex, function(match, capture) {
942                 return entities[capture];    
943             });
944         };
945     })(),
946
947     /**
948      * Convert certain characters (&, <, >, and ") from their HTML character equivalents.
949      * @param {String} value The string to decode
950      * @return {String} The decoded text
951      * @method
952      */
953     htmlDecode: (function() {
954         var entities = {
955             '&amp;': '&',
956             '&gt;': '>',
957             '&lt;': '<',
958             '&quot;': '"'
959         }, keys = [], p, regex;
960         
961         for (p in entities) {
962             keys.push(p);
963         }
964         
965         regex = new RegExp('(' + keys.join('|') + '|&#[0-9]{1,5};' + ')', 'g');
966         
967         return function(value) {
968             return (!value) ? value : String(value).replace(regex, function(match, capture) {
969                 if (capture in entities) {
970                     return entities[capture];
971                 } else {
972                     return String.fromCharCode(parseInt(capture.substr(2), 10));
973                 }
974             });
975         };
976     })(),
977
978     /**
979      * Appends content to the query string of a URL, handling logic for whether to place
980      * a question mark or ampersand.
981      * @param {String} url The URL to append to.
982      * @param {String} string The content to append to the URL.
983      * @return (String) The resulting URL
984      */
985     urlAppend : function(url, string) {
986         if (!Ext.isEmpty(string)) {
987             return url + (url.indexOf('?') === -1 ? '?' : '&') + string;
988         }
989
990         return url;
991     },
992
993     /**
994      * Trims whitespace from either end of a string, leaving spaces within the string intact.  Example:
995      * @example
996 var s = '  foo bar  ';
997 alert('-' + s + '-');         //alerts "- foo bar -"
998 alert('-' + Ext.String.trim(s) + '-');  //alerts "-foo bar-"
999
1000      * @param {String} string The string to escape
1001      * @return {String} The trimmed string
1002      */
1003     trim: function(string) {
1004         return string.replace(Ext.String.trimRegex, "");
1005     },
1006
1007     /**
1008      * Capitalize the given string
1009      * @param {String} string
1010      * @return {String}
1011      */
1012     capitalize: function(string) {
1013         return string.charAt(0).toUpperCase() + string.substr(1);
1014     },
1015
1016     /**
1017      * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
1018      * @param {String} value The string to truncate
1019      * @param {Number} length The maximum length to allow before truncating
1020      * @param {Boolean} word True to try to find a common word break
1021      * @return {String} The converted text
1022      */
1023     ellipsis: function(value, len, word) {
1024         if (value && value.length > len) {
1025             if (word) {
1026                 var vs = value.substr(0, len - 2),
1027                 index = Math.max(vs.lastIndexOf(' '), vs.lastIndexOf('.'), vs.lastIndexOf('!'), vs.lastIndexOf('?'));
1028                 if (index !== -1 && index >= (len - 15)) {
1029                     return vs.substr(0, index) + "...";
1030                 }
1031             }
1032             return value.substr(0, len - 3) + "...";
1033         }
1034         return value;
1035     },
1036
1037     /**
1038      * Escapes the passed string for use in a regular expression
1039      * @param {String} string
1040      * @return {String}
1041      */
1042     escapeRegex: function(string) {
1043         return string.replace(Ext.String.escapeRegexRe, "\\$1");
1044     },
1045
1046     /**
1047      * Escapes the passed string for ' and \
1048      * @param {String} string The string to escape
1049      * @return {String} The escaped string
1050      */
1051     escape: function(string) {
1052         return string.replace(Ext.String.escapeRe, "\\$1");
1053     },
1054
1055     /**
1056      * Utility function that allows you to easily switch a string between two alternating values.  The passed value
1057      * is compared to the current string, and if they are equal, the other value that was passed in is returned.  If
1058      * they are already different, the first value passed in is returned.  Note that this method returns the new value
1059      * but does not change the current string.
1060      * <pre><code>
1061     // alternate sort directions
1062     sort = Ext.String.toggle(sort, 'ASC', 'DESC');
1063
1064     // instead of conditional logic:
1065     sort = (sort == 'ASC' ? 'DESC' : 'ASC');
1066        </code></pre>
1067      * @param {String} string The current string
1068      * @param {String} value The value to compare to the current string
1069      * @param {String} other The new value to use if the string already equals the first value passed in
1070      * @return {String} The new value
1071      */
1072     toggle: function(string, value, other) {
1073         return string === value ? other : value;
1074     },
1075
1076     /**
1077      * Pads the left side of a string with a specified character.  This is especially useful
1078      * for normalizing number and date strings.  Example usage:
1079      *
1080      * <pre><code>
1081 var s = Ext.String.leftPad('123', 5, '0');
1082 // s now contains the string: '00123'
1083        </code></pre>
1084      * @param {String} string The original string
1085      * @param {Number} size The total length of the output string
1086      * @param {String} character (optional) The character with which to pad the original string (defaults to empty string " ")
1087      * @return {String} The padded string
1088      */
1089     leftPad: function(string, size, character) {
1090         var result = String(string);
1091         character = character || " ";
1092         while (result.length < size) {
1093             result = character + result;
1094         }
1095         return result;
1096     },
1097
1098     /**
1099      * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens.  Each
1100      * token must be unique, and must increment in the format {0}, {1}, etc.  Example usage:
1101      * <pre><code>
1102 var cls = 'my-class', text = 'Some text';
1103 var s = Ext.String.format('&lt;div class="{0}">{1}&lt;/div>', cls, text);
1104 // s now contains the string: '&lt;div class="my-class">Some text&lt;/div>'
1105        </code></pre>
1106      * @param {String} string The tokenized string to be formatted
1107      * @param {String} value1 The value to replace token {0}
1108      * @param {String} value2 Etc...
1109      * @return {String} The formatted string
1110      */
1111     format: function(format) {
1112         var args = Ext.Array.toArray(arguments, 1);
1113         return format.replace(Ext.String.formatRe, function(m, i) {
1114             return args[i];
1115         });
1116     },
1117
1118     /**
1119      * Returns a string with a specified number of repititions a given string pattern.
1120      * The pattern be separated by a different string.
1121      *
1122      *      var s = Ext.String.repeat('---', 4); // = '------------'
1123      *      var t = Ext.String.repeat('--', 3, '/'); // = '--/--/--'
1124      *
1125      * @param {String} pattern The pattern to repeat.
1126      * @param {Number} count The number of times to repeat the pattern (may be 0).
1127      * @param {String} sep An option string to separate each pattern.
1128      */
1129     repeat: function(pattern, count, sep) {
1130         for (var buf = [], i = count; i--; ) {
1131             buf.push(pattern);
1132         }
1133         return buf.join(sep || '');
1134     }
1135 };
1136
1137 /**
1138  * @class Ext.Number
1139  *
1140  * A collection of useful static methods to deal with numbers
1141  * @singleton
1142  */
1143
1144 (function() {
1145
1146 var isToFixedBroken = (0.9).toFixed() !== '1';
1147
1148 Ext.Number = {
1149     /**
1150      * Checks whether or not the passed number is within a desired range.  If the number is already within the
1151      * range it is returned, otherwise the min or max value is returned depending on which side of the range is
1152      * exceeded. Note that this method returns the constrained value but does not change the current number.
1153      * @param {Number} number The number to check
1154      * @param {Number} min The minimum number in the range
1155      * @param {Number} max The maximum number in the range
1156      * @return {Number} The constrained value if outside the range, otherwise the current value
1157      */
1158     constrain: function(number, min, max) {
1159         number = parseFloat(number);
1160
1161         if (!isNaN(min)) {
1162             number = Math.max(number, min);
1163         }
1164         if (!isNaN(max)) {
1165             number = Math.min(number, max);
1166         }
1167         return number;
1168     },
1169
1170     /**
1171      * Snaps the passed number between stopping points based upon a passed increment value.
1172      * @param {Number} value The unsnapped value.
1173      * @param {Number} increment The increment by which the value must move.
1174      * @param {Number} minValue The minimum value to which the returned value must be constrained. Overrides the increment..
1175      * @param {Number} maxValue The maximum value to which the returned value must be constrained. Overrides the increment..
1176      * @return {Number} The value of the nearest snap target.
1177      */
1178     snap : function(value, increment, minValue, maxValue) {
1179         var newValue = value,
1180             m;
1181
1182         if (!(increment && value)) {
1183             return value;
1184         }
1185         m = value % increment;
1186         if (m !== 0) {
1187             newValue -= m;
1188             if (m * 2 >= increment) {
1189                 newValue += increment;
1190             } else if (m * 2 < -increment) {
1191                 newValue -= increment;
1192             }
1193         }
1194         return Ext.Number.constrain(newValue, minValue,  maxValue);
1195     },
1196
1197     /**
1198      * Formats a number using fixed-point notation
1199      * @param {Number} value The number to format
1200      * @param {Number} precision The number of digits to show after the decimal point
1201      */
1202     toFixed: function(value, precision) {
1203         if (isToFixedBroken) {
1204             precision = precision || 0;
1205             var pow = Math.pow(10, precision);
1206             return (Math.round(value * pow) / pow).toFixed(precision);
1207         }
1208
1209         return value.toFixed(precision);
1210     },
1211
1212     /**
1213      * Validate that a value is numeric and convert it to a number if necessary. Returns the specified default value if
1214      * it is not.
1215
1216 Ext.Number.from('1.23', 1); // returns 1.23
1217 Ext.Number.from('abc', 1); // returns 1
1218
1219      * @param {Object} value
1220      * @param {Number} defaultValue The value to return if the original value is non-numeric
1221      * @return {Number} value, if numeric, defaultValue otherwise
1222      */
1223     from: function(value, defaultValue) {
1224         if (isFinite(value)) {
1225             value = parseFloat(value);
1226         }
1227
1228         return !isNaN(value) ? value : defaultValue;
1229     }
1230 };
1231
1232 })();
1233
1234 /**
1235  * @deprecated 4.0.0 Please use {@link Ext.Number#from} instead.
1236  * @member Ext
1237  * @method num
1238  * @alias Ext.Number#from
1239  */
1240 Ext.num = function() {
1241     return Ext.Number.from.apply(this, arguments);
1242 };
1243 /**
1244  * @class Ext.Array
1245  * @singleton
1246  * @author Jacky Nguyen <jacky@sencha.com>
1247  * @docauthor Jacky Nguyen <jacky@sencha.com>
1248  *
1249  * A set of useful static methods to deal with arrays; provide missing methods for older browsers.
1250  */
1251 (function() {
1252
1253     var arrayPrototype = Array.prototype,
1254         slice = arrayPrototype.slice,
1255         supportsSplice = function () {
1256             var array = [],
1257                 lengthBefore,
1258                 j = 20;
1259
1260             if (!array.splice) {
1261                 return false;
1262             }
1263
1264             // This detects a bug in IE8 splice method:
1265             // see http://social.msdn.microsoft.com/Forums/en-US/iewebdevelopment/thread/6e946d03-e09f-4b22-a4dd-cd5e276bf05a/
1266
1267             while (j--) {
1268                 array.push("A");
1269             }
1270
1271             array.splice(15, 0, "F", "F", "F", "F", "F","F","F","F","F","F","F","F","F","F","F","F","F","F","F","F","F");
1272
1273             lengthBefore = array.length; //41
1274             array.splice(13, 0, "XXX"); // add one element
1275
1276             if (lengthBefore+1 != array.length) {
1277                 return false;
1278             }
1279             // end IE8 bug
1280
1281             return true;
1282         }(),
1283         supportsForEach = 'forEach' in arrayPrototype,
1284         supportsMap = 'map' in arrayPrototype,
1285         supportsIndexOf = 'indexOf' in arrayPrototype,
1286         supportsEvery = 'every' in arrayPrototype,
1287         supportsSome = 'some' in arrayPrototype,
1288         supportsFilter = 'filter' in arrayPrototype,
1289         supportsSort = function() {
1290             var a = [1,2,3,4,5].sort(function(){ return 0; });
1291             return a[0] === 1 && a[1] === 2 && a[2] === 3 && a[3] === 4 && a[4] === 5;
1292         }(),
1293         supportsSliceOnNodeList = true,
1294         ExtArray;
1295
1296     try {
1297         // IE 6 - 8 will throw an error when using Array.prototype.slice on NodeList
1298         if (typeof document !== 'undefined') {
1299             slice.call(document.getElementsByTagName('body'));
1300         }
1301     } catch (e) {
1302         supportsSliceOnNodeList = false;
1303     }
1304
1305     function fixArrayIndex (array, index) {
1306         return (index < 0) ? Math.max(0, array.length + index)
1307                            : Math.min(array.length, index);
1308     }
1309
1310     /*
1311     Does the same work as splice, but with a slightly more convenient signature. The splice
1312     method has bugs in IE8, so this is the implementation we use on that platform.
1313
1314     The rippling of items in the array can be tricky. Consider two use cases:
1315
1316                   index=2
1317                   removeCount=2
1318                  /=====\
1319         +---+---+---+---+---+---+---+---+
1320         | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
1321         +---+---+---+---+---+---+---+---+
1322                          /  \/  \/  \/  \
1323                         /   /\  /\  /\   \
1324                        /   /  \/  \/  \   +--------------------------+
1325                       /   /   /\  /\   +--------------------------+   \
1326                      /   /   /  \/  +--------------------------+   \   \
1327                     /   /   /   /+--------------------------+   \   \   \
1328                    /   /   /   /                             \   \   \   \
1329                   v   v   v   v                               v   v   v   v
1330         +---+---+---+---+---+---+       +---+---+---+---+---+---+---+---+---+
1331         | 0 | 1 | 4 | 5 | 6 | 7 |       | 0 | 1 | a | b | c | 4 | 5 | 6 | 7 |
1332         +---+---+---+---+---+---+       +---+---+---+---+---+---+---+---+---+
1333         A                               B        \=========/
1334                                                  insert=[a,b,c]
1335
1336     In case A, it is obvious that copying of [4,5,6,7] must be left-to-right so
1337     that we don't end up with [0,1,6,7,6,7]. In case B, we have the opposite; we
1338     must go right-to-left or else we would end up with [0,1,a,b,c,4,4,4,4].
1339     */
1340     function replaceSim (array, index, removeCount, insert) {
1341         var add = insert ? insert.length : 0,
1342             length = array.length,
1343             pos = fixArrayIndex(array, index);
1344
1345         // we try to use Array.push when we can for efficiency...
1346         if (pos === length) {
1347             if (add) {
1348                 array.push.apply(array, insert);
1349             }
1350         } else {
1351             var remove = Math.min(removeCount, length - pos),
1352                 tailOldPos = pos + remove,
1353                 tailNewPos = tailOldPos + add - remove,
1354                 tailCount = length - tailOldPos,
1355                 lengthAfterRemove = length - remove,
1356                 i;
1357
1358             if (tailNewPos < tailOldPos) { // case A
1359                 for (i = 0; i < tailCount; ++i) {
1360                     array[tailNewPos+i] = array[tailOldPos+i];
1361                 }
1362             } else if (tailNewPos > tailOldPos) { // case B
1363                 for (i = tailCount; i--; ) {
1364                     array[tailNewPos+i] = array[tailOldPos+i];
1365                 }
1366             } // else, add == remove (nothing to do)
1367
1368             if (add && pos === lengthAfterRemove) {
1369                 array.length = lengthAfterRemove; // truncate array
1370                 array.push.apply(array, insert);
1371             } else {
1372                 array.length = lengthAfterRemove + add; // reserves space
1373                 for (i = 0; i < add; ++i) {
1374                     array[pos+i] = insert[i];
1375                 }
1376             }
1377         }
1378
1379         return array;
1380     }
1381
1382     function replaceNative (array, index, removeCount, insert) {
1383         if (insert && insert.length) {
1384             if (index < array.length) {
1385                 array.splice.apply(array, [index, removeCount].concat(insert));
1386             } else {
1387                 array.push.apply(array, insert);
1388             }
1389         } else {
1390             array.splice(index, removeCount);
1391         }
1392         return array;
1393     }
1394
1395     function eraseSim (array, index, removeCount) {
1396         return replaceSim(array, index, removeCount);
1397     }
1398
1399     function eraseNative (array, index, removeCount) {
1400         array.splice(index, removeCount);
1401         return array;
1402     }
1403
1404     function spliceSim (array, index, removeCount) {
1405         var pos = fixArrayIndex(array, index),
1406             removed = array.slice(index, fixArrayIndex(array, pos+removeCount));
1407
1408         if (arguments.length < 4) {
1409             replaceSim(array, pos, removeCount);
1410         } else {
1411             replaceSim(array, pos, removeCount, slice.call(arguments, 3));
1412         }
1413
1414         return removed;
1415     }
1416
1417     function spliceNative (array) {
1418         return array.splice.apply(array, slice.call(arguments, 1));
1419     }
1420
1421     var erase = supportsSplice ? eraseNative : eraseSim,
1422         replace = supportsSplice ? replaceNative : replaceSim,
1423         splice = supportsSplice ? spliceNative : spliceSim;
1424
1425     // NOTE: from here on, use erase, replace or splice (not native methods)...
1426
1427     ExtArray = Ext.Array = {
1428         /**
1429          * Iterates an array or an iterable value and invoke the given callback function for each item.
1430          *
1431          *     var countries = ['Vietnam', 'Singapore', 'United States', 'Russia'];
1432          *
1433          *     Ext.Array.each(countries, function(name, index, countriesItSelf) {
1434          *         console.log(name);
1435          *     });
1436          *
1437          *     var sum = function() {
1438          *         var sum = 0;
1439          *
1440          *         Ext.Array.each(arguments, function(value) {
1441          *             sum += value;
1442          *         });
1443          *
1444          *         return sum;
1445          *     };
1446          *
1447          *     sum(1, 2, 3); // returns 6
1448          *
1449          * The iteration can be stopped by returning false in the function callback.
1450          *
1451          *     Ext.Array.each(countries, function(name, index, countriesItSelf) {
1452          *         if (name === 'Singapore') {
1453          *             return false; // break here
1454          *         }
1455          *     });
1456          *
1457          * {@link Ext#each Ext.each} is alias for {@link Ext.Array#each Ext.Array.each}
1458          *
1459          * @param {Array/NodeList/Object} iterable The value to be iterated. If this
1460          * argument is not iterable, the callback function is called once.
1461          * @param {Function} fn The callback function. If it returns false, the iteration stops and this method returns
1462          * the current `index`.
1463          * @param {Object} fn.item The item at the current `index` in the passed `array`
1464          * @param {Number} fn.index The current `index` within the `array`
1465          * @param {Array} fn.allItems The `array` itself which was passed as the first argument
1466          * @param {Boolean} fn.return Return false to stop iteration.
1467          * @param {Object} scope (Optional) The scope (`this` reference) in which the specified function is executed.
1468          * @param {Boolean} reverse (Optional) Reverse the iteration order (loop from the end to the beginning)
1469          * Defaults false
1470          * @return {Boolean} See description for the `fn` parameter.
1471          */
1472         each: function(array, fn, scope, reverse) {
1473             array = ExtArray.from(array);
1474
1475             var i,
1476                 ln = array.length;
1477
1478             if (reverse !== true) {
1479                 for (i = 0; i < ln; i++) {
1480                     if (fn.call(scope || array[i], array[i], i, array) === false) {
1481                         return i;
1482                     }
1483                 }
1484             }
1485             else {
1486                 for (i = ln - 1; i > -1; i--) {
1487                     if (fn.call(scope || array[i], array[i], i, array) === false) {
1488                         return i;
1489                     }
1490                 }
1491             }
1492
1493             return true;
1494         },
1495
1496         /**
1497          * Iterates an array and invoke the given callback function for each item. Note that this will simply
1498          * delegate to the native Array.prototype.forEach method if supported. It doesn't support stopping the
1499          * iteration by returning false in the callback function like {@link Ext.Array#each}. However, performance
1500          * could be much better in modern browsers comparing with {@link Ext.Array#each}
1501          *
1502          * @param {Array} array The array to iterate
1503          * @param {Function} fn The callback function.
1504          * @param {Object} fn.item The item at the current `index` in the passed `array`
1505          * @param {Number} fn.index The current `index` within the `array`
1506          * @param {Array}  fn.allItems The `array` itself which was passed as the first argument
1507          * @param {Object} scope (Optional) The execution scope (`this`) in which the specified function is executed.
1508          */
1509         forEach: function(array, fn, scope) {
1510             if (supportsForEach) {
1511                 return array.forEach(fn, scope);
1512             }
1513
1514             var i = 0,
1515                 ln = array.length;
1516
1517             for (; i < ln; i++) {
1518                 fn.call(scope, array[i], i, array);
1519             }
1520         },
1521
1522         /**
1523          * Get the index of the provided `item` in the given `array`, a supplement for the
1524          * missing arrayPrototype.indexOf in Internet Explorer.
1525          *
1526          * @param {Array} array The array to check
1527          * @param {Object} item The item to look for
1528          * @param {Number} from (Optional) The index at which to begin the search
1529          * @return {Number} The index of item in the array (or -1 if it is not found)
1530          */
1531         indexOf: function(array, item, from) {
1532             if (supportsIndexOf) {
1533                 return array.indexOf(item, from);
1534             }
1535
1536             var i, length = array.length;
1537
1538             for (i = (from < 0) ? Math.max(0, length + from) : from || 0; i < length; i++) {
1539                 if (array[i] === item) {
1540                     return i;
1541                 }
1542             }
1543
1544             return -1;
1545         },
1546
1547         /**
1548          * Checks whether or not the given `array` contains the specified `item`
1549          *
1550          * @param {Array} array The array to check
1551          * @param {Object} item The item to look for
1552          * @return {Boolean} True if the array contains the item, false otherwise
1553          */
1554         contains: function(array, item) {
1555             if (supportsIndexOf) {
1556                 return array.indexOf(item) !== -1;
1557             }
1558
1559             var i, ln;
1560
1561             for (i = 0, ln = array.length; i < ln; i++) {
1562                 if (array[i] === item) {
1563                     return true;
1564                 }
1565             }
1566
1567             return false;
1568         },
1569
1570         /**
1571          * Converts any iterable (numeric indices and a length property) into a true array.
1572          *
1573          *     function test() {
1574          *         var args = Ext.Array.toArray(arguments),
1575          *             fromSecondToLastArgs = Ext.Array.toArray(arguments, 1);
1576          *
1577          *         alert(args.join(' '));
1578          *         alert(fromSecondToLastArgs.join(' '));
1579          *     }
1580          *
1581          *     test('just', 'testing', 'here'); // alerts 'just testing here';
1582          *                                      // alerts 'testing here';
1583          *
1584          *     Ext.Array.toArray(document.getElementsByTagName('div')); // will convert the NodeList into an array
1585          *     Ext.Array.toArray('splitted'); // returns ['s', 'p', 'l', 'i', 't', 't', 'e', 'd']
1586          *     Ext.Array.toArray('splitted', 0, 3); // returns ['s', 'p', 'l', 'i']
1587          *
1588          * {@link Ext#toArray Ext.toArray} is alias for {@link Ext.Array#toArray Ext.Array.toArray}
1589          *
1590          * @param {Object} iterable the iterable object to be turned into a true Array.
1591          * @param {Number} start (Optional) a zero-based index that specifies the start of extraction. Defaults to 0
1592          * @param {Number} end (Optional) a zero-based index that specifies the end of extraction. Defaults to the last
1593          * index of the iterable value
1594          * @return {Array} array
1595          */
1596         toArray: function(iterable, start, end){
1597             if (!iterable || !iterable.length) {
1598                 return [];
1599             }
1600
1601             if (typeof iterable === 'string') {
1602                 iterable = iterable.split('');
1603             }
1604
1605             if (supportsSliceOnNodeList) {
1606                 return slice.call(iterable, start || 0, end || iterable.length);
1607             }
1608
1609             var array = [],
1610                 i;
1611
1612             start = start || 0;
1613             end = end ? ((end < 0) ? iterable.length + end : end) : iterable.length;
1614
1615             for (i = start; i < end; i++) {
1616                 array.push(iterable[i]);
1617             }
1618
1619             return array;
1620         },
1621
1622         /**
1623          * Plucks the value of a property from each item in the Array. Example:
1624          *
1625          *     Ext.Array.pluck(Ext.query("p"), "className"); // [el1.className, el2.className, ..., elN.className]
1626          *
1627          * @param {Array/NodeList} array The Array of items to pluck the value from.
1628          * @param {String} propertyName The property name to pluck from each element.
1629          * @return {Array} The value from each item in the Array.
1630          */
1631         pluck: function(array, propertyName) {
1632             var ret = [],
1633                 i, ln, item;
1634
1635             for (i = 0, ln = array.length; i < ln; i++) {
1636                 item = array[i];
1637
1638                 ret.push(item[propertyName]);
1639             }
1640
1641             return ret;
1642         },
1643
1644         /**
1645          * Creates a new array with the results of calling a provided function on every element in this array.
1646          *
1647          * @param {Array} array
1648          * @param {Function} fn Callback function for each item
1649          * @param {Object} scope Callback function scope
1650          * @return {Array} results
1651          */
1652         map: function(array, fn, scope) {
1653             if (supportsMap) {
1654                 return array.map(fn, scope);
1655             }
1656
1657             var results = [],
1658                 i = 0,
1659                 len = array.length;
1660
1661             for (; i < len; i++) {
1662                 results[i] = fn.call(scope, array[i], i, array);
1663             }
1664
1665             return results;
1666         },
1667
1668         /**
1669          * Executes the specified function for each array element until the function returns a falsy value.
1670          * If such an item is found, the function will return false immediately.
1671          * Otherwise, it will return true.
1672          *
1673          * @param {Array} array
1674          * @param {Function} fn Callback function for each item
1675          * @param {Object} scope Callback function scope
1676          * @return {Boolean} True if no false value is returned by the callback function.
1677          */
1678         every: function(array, fn, scope) {
1679             if (!fn) {
1680                 Ext.Error.raise('Ext.Array.every must have a callback function passed as second argument.');
1681             }
1682             if (supportsEvery) {
1683                 return array.every(fn, scope);
1684             }
1685
1686             var i = 0,
1687                 ln = array.length;
1688
1689             for (; i < ln; ++i) {
1690                 if (!fn.call(scope, array[i], i, array)) {
1691                     return false;
1692                 }
1693             }
1694
1695             return true;
1696         },
1697
1698         /**
1699          * Executes the specified function for each array element until the function returns a truthy value.
1700          * If such an item is found, the function will return true immediately. Otherwise, it will return false.
1701          *
1702          * @param {Array} array
1703          * @param {Function} fn Callback function for each item
1704          * @param {Object} scope Callback function scope
1705          * @return {Boolean} True if the callback function returns a truthy value.
1706          */
1707         some: function(array, fn, scope) {
1708             if (!fn) {
1709                 Ext.Error.raise('Ext.Array.some must have a callback function passed as second argument.');
1710             }
1711             if (supportsSome) {
1712                 return array.some(fn, scope);
1713             }
1714
1715             var i = 0,
1716                 ln = array.length;
1717
1718             for (; i < ln; ++i) {
1719                 if (fn.call(scope, array[i], i, array)) {
1720                     return true;
1721                 }
1722             }
1723
1724             return false;
1725         },
1726
1727         /**
1728          * Filter through an array and remove empty item as defined in {@link Ext#isEmpty Ext.isEmpty}
1729          *
1730          * See {@link Ext.Array#filter}
1731          *
1732          * @param {Array} array
1733          * @return {Array} results
1734          */
1735         clean: function(array) {
1736             var results = [],
1737                 i = 0,
1738                 ln = array.length,
1739                 item;
1740
1741             for (; i < ln; i++) {
1742                 item = array[i];
1743
1744                 if (!Ext.isEmpty(item)) {
1745                     results.push(item);
1746                 }
1747             }
1748
1749             return results;
1750         },
1751
1752         /**
1753          * Returns a new array with unique items
1754          *
1755          * @param {Array} array
1756          * @return {Array} results
1757          */
1758         unique: function(array) {
1759             var clone = [],
1760                 i = 0,
1761                 ln = array.length,
1762                 item;
1763
1764             for (; i < ln; i++) {
1765                 item = array[i];
1766
1767                 if (ExtArray.indexOf(clone, item) === -1) {
1768                     clone.push(item);
1769                 }
1770             }
1771
1772             return clone;
1773         },
1774
1775         /**
1776          * Creates a new array with all of the elements of this array for which
1777          * the provided filtering function returns true.
1778          *
1779          * @param {Array} array
1780          * @param {Function} fn Callback function for each item
1781          * @param {Object} scope Callback function scope
1782          * @return {Array} results
1783          */
1784         filter: function(array, fn, scope) {
1785             if (supportsFilter) {
1786                 return array.filter(fn, scope);
1787             }
1788
1789             var results = [],
1790                 i = 0,
1791                 ln = array.length;
1792
1793             for (; i < ln; i++) {
1794                 if (fn.call(scope, array[i], i, array)) {
1795                     results.push(array[i]);
1796                 }
1797             }
1798
1799             return results;
1800         },
1801
1802         /**
1803          * Converts a value to an array if it's not already an array; returns:
1804          *
1805          * - An empty array if given value is `undefined` or `null`
1806          * - Itself if given value is already an array
1807          * - An array copy if given value is {@link Ext#isIterable iterable} (arguments, NodeList and alike)
1808          * - An array with one item which is the given value, otherwise
1809          *
1810          * @param {Object} value The value to convert to an array if it's not already is an array
1811          * @param {Boolean} newReference (Optional) True to clone the given array and return a new reference if necessary,
1812          * defaults to false
1813          * @return {Array} array
1814          */
1815         from: function(value, newReference) {
1816             if (value === undefined || value === null) {
1817                 return [];
1818             }
1819
1820             if (Ext.isArray(value)) {
1821                 return (newReference) ? slice.call(value) : value;
1822             }
1823
1824             if (value && value.length !== undefined && typeof value !== 'string') {
1825                 return Ext.toArray(value);
1826             }
1827
1828             return [value];
1829         },
1830
1831         /**
1832          * Removes the specified item from the array if it exists
1833          *
1834          * @param {Array} array The array
1835          * @param {Object} item The item to remove
1836          * @return {Array} The passed array itself
1837          */
1838         remove: function(array, item) {
1839             var index = ExtArray.indexOf(array, item);
1840
1841             if (index !== -1) {
1842                 erase(array, index, 1);
1843             }
1844
1845             return array;
1846         },
1847
1848         /**
1849          * Push an item into the array only if the array doesn't contain it yet
1850          *
1851          * @param {Array} array The array
1852          * @param {Object} item The item to include
1853          */
1854         include: function(array, item) {
1855             if (!ExtArray.contains(array, item)) {
1856                 array.push(item);
1857             }
1858         },
1859
1860         /**
1861          * Clone a flat array without referencing the previous one. Note that this is different
1862          * from Ext.clone since it doesn't handle recursive cloning. It's simply a convenient, easy-to-remember method
1863          * for Array.prototype.slice.call(array)
1864          *
1865          * @param {Array} array The array
1866          * @return {Array} The clone array
1867          */
1868         clone: function(array) {
1869             return slice.call(array);
1870         },
1871
1872         /**
1873          * Merge multiple arrays into one with unique items.
1874          *
1875          * {@link Ext.Array#union} is alias for {@link Ext.Array#merge}
1876          *
1877          * @param {Array} array1
1878          * @param {Array} array2
1879          * @param {Array} etc
1880          * @return {Array} merged
1881          */
1882         merge: function() {
1883             var args = slice.call(arguments),
1884                 array = [],
1885                 i, ln;
1886
1887             for (i = 0, ln = args.length; i < ln; i++) {
1888                 array = array.concat(args[i]);
1889             }
1890
1891             return ExtArray.unique(array);
1892         },
1893
1894         /**
1895          * Merge multiple arrays into one with unique items that exist in all of the arrays.
1896          *
1897          * @param {Array} array1
1898          * @param {Array} array2
1899          * @param {Array} etc
1900          * @return {Array} intersect
1901          */
1902         intersect: function() {
1903             var intersect = [],
1904                 arrays = slice.call(arguments),
1905                 i, j, k, minArray, array, x, y, ln, arraysLn, arrayLn;
1906
1907             if (!arrays.length) {
1908                 return intersect;
1909             }
1910
1911             // Find the smallest array
1912             for (i = x = 0,ln = arrays.length; i < ln,array = arrays[i]; i++) {
1913                 if (!minArray || array.length < minArray.length) {
1914                     minArray = array;
1915                     x = i;
1916                 }
1917             }
1918
1919             minArray = ExtArray.unique(minArray);
1920             erase(arrays, x, 1);
1921
1922             // Use the smallest unique'd array as the anchor loop. If the other array(s) do contain
1923             // an item in the small array, we're likely to find it before reaching the end
1924             // of the inner loop and can terminate the search early.
1925             for (i = 0,ln = minArray.length; i < ln,x = minArray[i]; i++) {
1926                 var count = 0;
1927
1928                 for (j = 0,arraysLn = arrays.length; j < arraysLn,array = arrays[j]; j++) {
1929                     for (k = 0,arrayLn = array.length; k < arrayLn,y = array[k]; k++) {
1930                         if (x === y) {
1931                             count++;
1932                             break;
1933                         }
1934                     }
1935                 }
1936
1937                 if (count === arraysLn) {
1938                     intersect.push(x);
1939                 }
1940             }
1941
1942             return intersect;
1943         },
1944
1945         /**
1946          * Perform a set difference A-B by subtracting all items in array B from array A.
1947          *
1948          * @param {Array} arrayA
1949          * @param {Array} arrayB
1950          * @return {Array} difference
1951          */
1952         difference: function(arrayA, arrayB) {
1953             var clone = slice.call(arrayA),
1954                 ln = clone.length,
1955                 i, j, lnB;
1956
1957             for (i = 0,lnB = arrayB.length; i < lnB; i++) {
1958                 for (j = 0; j < ln; j++) {
1959                     if (clone[j] === arrayB[i]) {
1960                         erase(clone, j, 1);
1961                         j--;
1962                         ln--;
1963                     }
1964                 }
1965             }
1966
1967             return clone;
1968         },
1969
1970         /**
1971          * Returns a shallow copy of a part of an array. This is equivalent to the native
1972          * call "Array.prototype.slice.call(array, begin, end)". This is often used when "array"
1973          * is "arguments" since the arguments object does not supply a slice method but can
1974          * be the context object to Array.prototype.slice.
1975          *
1976          * @param {Array} array The array (or arguments object).
1977          * @param {Number} begin The index at which to begin. Negative values are offsets from
1978          * the end of the array.
1979          * @param {Number} end The index at which to end. The copied items do not include
1980          * end. Negative values are offsets from the end of the array. If end is omitted,
1981          * all items up to the end of the array are copied.
1982          * @return {Array} The copied piece of the array.
1983          */
1984         // Note: IE6 will return [] on slice.call(x, undefined).
1985         slice: ([1,2].slice(1, undefined).length ?
1986             function (array, begin, end) {
1987                 return slice.call(array, begin, end);
1988             } :
1989             // at least IE6 uses arguments.length for variadic signature
1990             function (array, begin, end) {
1991                 // After tested for IE 6, the one below is of the best performance
1992                 // see http://jsperf.com/slice-fix
1993                 if (typeof begin === 'undefined') {
1994                     return slice.call(array);
1995                 }
1996                 if (typeof end === 'undefined') {
1997                     return slice.call(array, begin);
1998                 }
1999                 return slice.call(array, begin, end);
2000             }
2001         ),
2002
2003         /**
2004          * Sorts the elements of an Array.
2005          * By default, this method sorts the elements alphabetically and ascending.
2006          *
2007          * @param {Array} array The array to sort.
2008          * @param {Function} sortFn (optional) The comparison function.
2009          * @return {Array} The sorted array.
2010          */
2011         sort: function(array, sortFn) {
2012             if (supportsSort) {
2013                 if (sortFn) {
2014                     return array.sort(sortFn);
2015                 } else {
2016                     return array.sort();
2017                 }
2018             }
2019
2020             var length = array.length,
2021                 i = 0,
2022                 comparison,
2023                 j, min, tmp;
2024
2025             for (; i < length; i++) {
2026                 min = i;
2027                 for (j = i + 1; j < length; j++) {
2028                     if (sortFn) {
2029                         comparison = sortFn(array[j], array[min]);
2030                         if (comparison < 0) {
2031                             min = j;
2032                         }
2033                     } else if (array[j] < array[min]) {
2034                         min = j;
2035                     }
2036                 }
2037                 if (min !== i) {
2038                     tmp = array[i];
2039                     array[i] = array[min];
2040                     array[min] = tmp;
2041                 }
2042             }
2043
2044             return array;
2045         },
2046
2047         /**
2048          * Recursively flattens into 1-d Array. Injects Arrays inline.
2049          *
2050          * @param {Array} array The array to flatten
2051          * @return {Array} The 1-d array.
2052          */
2053         flatten: function(array) {
2054             var worker = [];
2055
2056             function rFlatten(a) {
2057                 var i, ln, v;
2058
2059                 for (i = 0, ln = a.length; i < ln; i++) {
2060                     v = a[i];
2061
2062                     if (Ext.isArray(v)) {
2063                         rFlatten(v);
2064                     } else {
2065                         worker.push(v);
2066                     }
2067                 }
2068
2069                 return worker;
2070             }
2071
2072             return rFlatten(array);
2073         },
2074
2075         /**
2076          * Returns the minimum value in the Array.
2077          *
2078          * @param {Array/NodeList} array The Array from which to select the minimum value.
2079          * @param {Function} comparisonFn (optional) a function to perform the comparision which determines minimization.
2080          * If omitted the "<" operator will be used. Note: gt = 1; eq = 0; lt = -1
2081          * @return {Object} minValue The minimum value
2082          */
2083         min: function(array, comparisonFn) {
2084             var min = array[0],
2085                 i, ln, item;
2086
2087             for (i = 0, ln = array.length; i < ln; i++) {
2088                 item = array[i];
2089
2090                 if (comparisonFn) {
2091                     if (comparisonFn(min, item) === 1) {
2092                         min = item;
2093                     }
2094                 }
2095                 else {
2096                     if (item < min) {
2097                         min = item;
2098                     }
2099                 }
2100             }
2101
2102             return min;
2103         },
2104
2105         /**
2106          * Returns the maximum value in the Array.
2107          *
2108          * @param {Array/NodeList} array The Array from which to select the maximum value.
2109          * @param {Function} comparisonFn (optional) a function to perform the comparision which determines maximization.
2110          * If omitted the ">" operator will be used. Note: gt = 1; eq = 0; lt = -1
2111          * @return {Object} maxValue The maximum value
2112          */
2113         max: function(array, comparisonFn) {
2114             var max = array[0],
2115                 i, ln, item;
2116
2117             for (i = 0, ln = array.length; i < ln; i++) {
2118                 item = array[i];
2119
2120                 if (comparisonFn) {
2121                     if (comparisonFn(max, item) === -1) {
2122                         max = item;
2123                     }
2124                 }
2125                 else {
2126                     if (item > max) {
2127                         max = item;
2128                     }
2129                 }
2130             }
2131
2132             return max;
2133         },
2134
2135         /**
2136          * Calculates the mean of all items in the array.
2137          *
2138          * @param {Array} array The Array to calculate the mean value of.
2139          * @return {Number} The mean.
2140          */
2141         mean: function(array) {
2142             return array.length > 0 ? ExtArray.sum(array) / array.length : undefined;
2143         },
2144
2145         /**
2146          * Calculates the sum of all items in the given array.
2147          *
2148          * @param {Array} array The Array to calculate the sum value of.
2149          * @return {Number} The sum.
2150          */
2151         sum: function(array) {
2152             var sum = 0,
2153                 i, ln, item;
2154
2155             for (i = 0,ln = array.length; i < ln; i++) {
2156                 item = array[i];
2157
2158                 sum += item;
2159             }
2160
2161             return sum;
2162         },
2163
2164         _replaceSim: replaceSim, // for unit testing
2165         _spliceSim: spliceSim,
2166
2167         /**
2168          * Removes items from an array. This is functionally equivalent to the splice method
2169          * of Array, but works around bugs in IE8's splice method and does not copy the
2170          * removed elements in order to return them (because very often they are ignored).
2171          *
2172          * @param {Array} array The Array on which to replace.
2173          * @param {Number} index The index in the array at which to operate.
2174          * @param {Number} removeCount The number of items to remove at index.
2175          * @return {Array} The array passed.
2176          * @method
2177          */
2178         erase: erase,
2179
2180         /**
2181          * Inserts items in to an array.
2182          *
2183          * @param {Array} array The Array on which to replace.
2184          * @param {Number} index The index in the array at which to operate.
2185          * @param {Array} items The array of items to insert at index.
2186          * @return {Array} The array passed.
2187          */
2188         insert: function (array, index, items) {
2189             return replace(array, index, 0, items);
2190         },
2191
2192         /**
2193          * Replaces items in an array. This is functionally equivalent to the splice method
2194          * of Array, but works around bugs in IE8's splice method and is often more convenient
2195          * to call because it accepts an array of items to insert rather than use a variadic
2196          * argument list.
2197          *
2198          * @param {Array} array The Array on which to replace.
2199          * @param {Number} index The index in the array at which to operate.
2200          * @param {Number} removeCount The number of items to remove at index (can be 0).
2201          * @param {Array} insert (optional) An array of items to insert at index.
2202          * @return {Array} The array passed.
2203          * @method
2204          */
2205         replace: replace,
2206
2207         /**
2208          * Replaces items in an array. This is equivalent to the splice method of Array, but
2209          * works around bugs in IE8's splice method. The signature is exactly the same as the
2210          * splice method except that the array is the first argument. All arguments following
2211          * removeCount are inserted in the array at index.
2212          *
2213          * @param {Array} array The Array on which to replace.
2214          * @param {Number} index The index in the array at which to operate.
2215          * @param {Number} removeCount The number of items to remove at index (can be 0).
2216          * @return {Array} An array containing the removed items.
2217          * @method
2218          */
2219         splice: splice
2220     };
2221
2222     /**
2223      * @method
2224      * @member Ext
2225      * @alias Ext.Array#each
2226      */
2227     Ext.each = ExtArray.each;
2228
2229     /**
2230      * @method
2231      * @member Ext.Array
2232      * @alias Ext.Array#merge
2233      */
2234     ExtArray.union = ExtArray.merge;
2235
2236     /**
2237      * Old alias to {@link Ext.Array#min}
2238      * @deprecated 4.0.0 Use {@link Ext.Array#min} instead
2239      * @method
2240      * @member Ext
2241      * @alias Ext.Array#min
2242      */
2243     Ext.min = ExtArray.min;
2244
2245     /**
2246      * Old alias to {@link Ext.Array#max}
2247      * @deprecated 4.0.0 Use {@link Ext.Array#max} instead
2248      * @method
2249      * @member Ext
2250      * @alias Ext.Array#max
2251      */
2252     Ext.max = ExtArray.max;
2253
2254     /**
2255      * Old alias to {@link Ext.Array#sum}
2256      * @deprecated 4.0.0 Use {@link Ext.Array#sum} instead
2257      * @method
2258      * @member Ext
2259      * @alias Ext.Array#sum
2260      */
2261     Ext.sum = ExtArray.sum;
2262
2263     /**
2264      * Old alias to {@link Ext.Array#mean}
2265      * @deprecated 4.0.0 Use {@link Ext.Array#mean} instead
2266      * @method
2267      * @member Ext
2268      * @alias Ext.Array#mean
2269      */
2270     Ext.mean = ExtArray.mean;
2271
2272     /**
2273      * Old alias to {@link Ext.Array#flatten}
2274      * @deprecated 4.0.0 Use {@link Ext.Array#flatten} instead
2275      * @method
2276      * @member Ext
2277      * @alias Ext.Array#flatten
2278      */
2279     Ext.flatten = ExtArray.flatten;
2280
2281     /**
2282      * Old alias to {@link Ext.Array#clean}
2283      * @deprecated 4.0.0 Use {@link Ext.Array#clean} instead
2284      * @method
2285      * @member Ext
2286      * @alias Ext.Array#clean
2287      */
2288     Ext.clean = ExtArray.clean;
2289
2290     /**
2291      * Old alias to {@link Ext.Array#unique}
2292      * @deprecated 4.0.0 Use {@link Ext.Array#unique} instead
2293      * @method
2294      * @member Ext
2295      * @alias Ext.Array#unique
2296      */
2297     Ext.unique = ExtArray.unique;
2298
2299     /**
2300      * Old alias to {@link Ext.Array#pluck Ext.Array.pluck}
2301      * @deprecated 4.0.0 Use {@link Ext.Array#pluck Ext.Array.pluck} instead
2302      * @method
2303      * @member Ext
2304      * @alias Ext.Array#pluck
2305      */
2306     Ext.pluck = ExtArray.pluck;
2307
2308     /**
2309      * @method
2310      * @member Ext
2311      * @alias Ext.Array#toArray
2312      */
2313     Ext.toArray = function() {
2314         return ExtArray.toArray.apply(ExtArray, arguments);
2315     };
2316 })();
2317
2318 /**
2319  * @class Ext.Function
2320  *
2321  * A collection of useful static methods to deal with function callbacks
2322  * @singleton
2323  */
2324 Ext.Function = {
2325
2326     /**
2327      * A very commonly used method throughout the framework. It acts as a wrapper around another method
2328      * which originally accepts 2 arguments for `name` and `value`.
2329      * The wrapped function then allows "flexible" value setting of either:
2330      *
2331      * - `name` and `value` as 2 arguments
2332      * - one single object argument with multiple key - value pairs
2333      *
2334      * For example:
2335      *
2336      *     var setValue = Ext.Function.flexSetter(function(name, value) {
2337      *         this[name] = value;
2338      *     });
2339      *
2340      *     // Afterwards
2341      *     // Setting a single name - value
2342      *     setValue('name1', 'value1');
2343      *
2344      *     // Settings multiple name - value pairs
2345      *     setValue({
2346      *         name1: 'value1',
2347      *         name2: 'value2',
2348      *         name3: 'value3'
2349      *     });
2350      *
2351      * @param {Function} setter
2352      * @returns {Function} flexSetter
2353      */
2354     flexSetter: function(fn) {
2355         return function(a, b) {
2356             var k, i;
2357
2358             if (a === null) {
2359                 return this;
2360             }
2361
2362             if (typeof a !== 'string') {
2363                 for (k in a) {
2364                     if (a.hasOwnProperty(k)) {
2365                         fn.call(this, k, a[k]);
2366                     }
2367                 }
2368
2369                 if (Ext.enumerables) {
2370                     for (i = Ext.enumerables.length; i--;) {
2371                         k = Ext.enumerables[i];
2372                         if (a.hasOwnProperty(k)) {
2373                             fn.call(this, k, a[k]);
2374                         }
2375                     }
2376                 }
2377             } else {
2378                 fn.call(this, a, b);
2379             }
2380
2381             return this;
2382         };
2383     },
2384
2385     /**
2386      * Create a new function from the provided `fn`, change `this` to the provided scope, optionally
2387      * overrides arguments for the call. (Defaults to the arguments passed by the caller)
2388      *
2389      * {@link Ext#bind Ext.bind} is alias for {@link Ext.Function#bind Ext.Function.bind}
2390      *
2391      * @param {Function} fn The function to delegate.
2392      * @param {Object} scope (optional) The scope (`this` reference) in which the function is executed.
2393      * **If omitted, defaults to the browser window.**
2394      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
2395      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
2396      * if a number the args are inserted at the specified position
2397      * @return {Function} The new function
2398      */
2399     bind: function(fn, scope, args, appendArgs) {
2400         if (arguments.length === 2) {
2401             return function() {
2402                 return fn.apply(scope, arguments);
2403             }
2404         }
2405
2406         var method = fn,
2407             slice = Array.prototype.slice;
2408
2409         return function() {
2410             var callArgs = args || arguments;
2411
2412             if (appendArgs === true) {
2413                 callArgs = slice.call(arguments, 0);
2414                 callArgs = callArgs.concat(args);
2415             }
2416             else if (typeof appendArgs == 'number') {
2417                 callArgs = slice.call(arguments, 0); // copy arguments first
2418                 Ext.Array.insert(callArgs, appendArgs, args);
2419             }
2420
2421             return method.apply(scope || window, callArgs);
2422         };
2423     },
2424
2425     /**
2426      * Create a new function from the provided `fn`, the arguments of which are pre-set to `args`.
2427      * New arguments passed to the newly created callback when it's invoked are appended after the pre-set ones.
2428      * This is especially useful when creating callbacks.
2429      *
2430      * For example:
2431      *
2432      *     var originalFunction = function(){
2433      *         alert(Ext.Array.from(arguments).join(' '));
2434      *     };
2435      *
2436      *     var callback = Ext.Function.pass(originalFunction, ['Hello', 'World']);
2437      *
2438      *     callback(); // alerts 'Hello World'
2439      *     callback('by Me'); // alerts 'Hello World by Me'
2440      *
2441      * {@link Ext#pass Ext.pass} is alias for {@link Ext.Function#pass Ext.Function.pass}
2442      *
2443      * @param {Function} fn The original function
2444      * @param {Array} args The arguments to pass to new callback
2445      * @param {Object} scope (optional) The scope (`this` reference) in which the function is executed.
2446      * @return {Function} The new callback function
2447      */
2448     pass: function(fn, args, scope) {
2449         if (args) {
2450             args = Ext.Array.from(args);
2451         }
2452
2453         return function() {
2454             return fn.apply(scope, args.concat(Ext.Array.toArray(arguments)));
2455         };
2456     },
2457
2458     /**
2459      * Create an alias to the provided method property with name `methodName` of `object`.
2460      * Note that the execution scope will still be bound to the provided `object` itself.
2461      *
2462      * @param {Object/Function} object
2463      * @param {String} methodName
2464      * @return {Function} aliasFn
2465      */
2466     alias: function(object, methodName) {
2467         return function() {
2468             return object[methodName].apply(object, arguments);
2469         };
2470     },
2471
2472     /**
2473      * Creates an interceptor function. The passed function is called before the original one. If it returns false,
2474      * the original one is not called. The resulting function returns the results of the original function.
2475      * The passed function is called with the parameters of the original function. Example usage:
2476      *
2477      *     var sayHi = function(name){
2478      *         alert('Hi, ' + name);
2479      *     }
2480      *
2481      *     sayHi('Fred'); // alerts "Hi, Fred"
2482      *
2483      *     // create a new function that validates input without
2484      *     // directly modifying the original function:
2485      *     var sayHiToFriend = Ext.Function.createInterceptor(sayHi, function(name){
2486      *         return name == 'Brian';
2487      *     });
2488      *
2489      *     sayHiToFriend('Fred');  // no alert
2490      *     sayHiToFriend('Brian'); // alerts "Hi, Brian"
2491      *
2492      * @param {Function} origFn The original function.
2493      * @param {Function} newFn The function to call before the original
2494      * @param {Object} scope (optional) The scope (`this` reference) in which the passed function is executed.
2495      * **If omitted, defaults to the scope in which the original function is called or the browser window.**
2496      * @param {Object} returnValue (optional) The value to return if the passed function return false (defaults to null).
2497      * @return {Function} The new function
2498      */
2499     createInterceptor: function(origFn, newFn, scope, returnValue) {
2500         var method = origFn;
2501         if (!Ext.isFunction(newFn)) {
2502             return origFn;
2503         }
2504         else {
2505             return function() {
2506                 var me = this,
2507                     args = arguments;
2508                 newFn.target = me;
2509                 newFn.method = origFn;
2510                 return (newFn.apply(scope || me || window, args) !== false) ? origFn.apply(me || window, args) : returnValue || null;
2511             };
2512         }
2513     },
2514
2515     /**
2516      * Creates a delegate (callback) which, when called, executes after a specific delay.
2517      *
2518      * @param {Function} fn The function which will be called on a delay when the returned function is called.
2519      * Optionally, a replacement (or additional) argument list may be specified.
2520      * @param {Number} delay The number of milliseconds to defer execution by whenever called.
2521      * @param {Object} scope (optional) The scope (`this` reference) used by the function at execution time.
2522      * @param {Array} args (optional) Override arguments for the call. (Defaults to the arguments passed by the caller)
2523      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
2524      * if a number the args are inserted at the specified position.
2525      * @return {Function} A function which, when called, executes the original function after the specified delay.
2526      */
2527     createDelayed: function(fn, delay, scope, args, appendArgs) {
2528         if (scope || args) {
2529             fn = Ext.Function.bind(fn, scope, args, appendArgs);
2530         }
2531         return function() {
2532             var me = this;
2533             setTimeout(function() {
2534                 fn.apply(me, arguments);
2535             }, delay);
2536         };
2537     },
2538
2539     /**
2540      * Calls this function after the number of millseconds specified, optionally in a specific scope. Example usage:
2541      *
2542      *     var sayHi = function(name){
2543      *         alert('Hi, ' + name);
2544      *     }
2545      *
2546      *     // executes immediately:
2547      *     sayHi('Fred');
2548      *
2549      *     // executes after 2 seconds:
2550      *     Ext.Function.defer(sayHi, 2000, this, ['Fred']);
2551      *
2552      *     // this syntax is sometimes useful for deferring
2553      *     // execution of an anonymous function:
2554      *     Ext.Function.defer(function(){
2555      *         alert('Anonymous');
2556      *     }, 100);
2557      *
2558      * {@link Ext#defer Ext.defer} is alias for {@link Ext.Function#defer Ext.Function.defer}
2559      *
2560      * @param {Function} fn The function to defer.
2561      * @param {Number} millis The number of milliseconds for the setTimeout call
2562      * (if less than or equal to 0 the function is executed immediately)
2563      * @param {Object} scope (optional) The scope (`this` reference) in which the function is executed.
2564      * **If omitted, defaults to the browser window.**
2565      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
2566      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
2567      * if a number the args are inserted at the specified position
2568      * @return {Number} The timeout id that can be used with clearTimeout
2569      */
2570     defer: function(fn, millis, obj, args, appendArgs) {
2571         fn = Ext.Function.bind(fn, obj, args, appendArgs);
2572         if (millis > 0) {
2573             return setTimeout(fn, millis);
2574         }
2575         fn();
2576         return 0;
2577     },
2578
2579     /**
2580      * Create a combined function call sequence of the original function + the passed function.
2581      * The resulting function returns the results of the original function.
2582      * The passed function is called with the parameters of the original function. Example usage:
2583      *
2584      *     var sayHi = function(name){
2585      *         alert('Hi, ' + name);
2586      *     }
2587      *
2588      *     sayHi('Fred'); // alerts "Hi, Fred"
2589      *
2590      *     var sayGoodbye = Ext.Function.createSequence(sayHi, function(name){
2591      *         alert('Bye, ' + name);
2592      *     });
2593      *
2594      *     sayGoodbye('Fred'); // both alerts show
2595      *
2596      * @param {Function} origFn The original function.
2597      * @param {Function} newFn The function to sequence
2598      * @param {Object} scope (optional) The scope (`this` reference) in which the passed function is executed.
2599      * If omitted, defaults to the scope in which the original function is called or the browser window.
2600      * @return {Function} The new function
2601      */
2602     createSequence: function(origFn, newFn, scope) {
2603         if (!Ext.isFunction(newFn)) {
2604             return origFn;
2605         }
2606         else {
2607             return function() {
2608                 var retval = origFn.apply(this || window, arguments);
2609                 newFn.apply(scope || this || window, arguments);
2610                 return retval;
2611             };
2612         }
2613     },
2614
2615     /**
2616      * Creates a delegate function, optionally with a bound scope which, when called, buffers
2617      * the execution of the passed function for the configured number of milliseconds.
2618      * If called again within that period, the impending invocation will be canceled, and the
2619      * timeout period will begin again.
2620      *
2621      * @param {Function} fn The function to invoke on a buffered timer.
2622      * @param {Number} buffer The number of milliseconds by which to buffer the invocation of the
2623      * function.
2624      * @param {Object} scope (optional) The scope (`this` reference) in which
2625      * the passed function is executed. If omitted, defaults to the scope specified by the caller.
2626      * @param {Array} args (optional) Override arguments for the call. Defaults to the arguments
2627      * passed by the caller.
2628      * @return {Function} A function which invokes the passed function after buffering for the specified time.
2629      */
2630     createBuffered: function(fn, buffer, scope, args) {
2631         return function(){
2632             var timerId;
2633             return function() {
2634                 var me = this;
2635                 if (timerId) {
2636                     clearTimeout(timerId);
2637                     timerId = null;
2638                 }
2639                 timerId = setTimeout(function(){
2640                     fn.apply(scope || me, args || arguments);
2641                 }, buffer);
2642             };
2643         }();
2644     },
2645
2646     /**
2647      * Creates a throttled version of the passed function which, when called repeatedly and
2648      * rapidly, invokes the passed function only after a certain interval has elapsed since the
2649      * previous invocation.
2650      *
2651      * This is useful for wrapping functions which may be called repeatedly, such as
2652      * a handler of a mouse move event when the processing is expensive.
2653      *
2654      * @param {Function} fn The function to execute at a regular time interval.
2655      * @param {Number} interval The interval **in milliseconds** on which the passed function is executed.
2656      * @param {Object} scope (optional) The scope (`this` reference) in which
2657      * the passed function is executed. If omitted, defaults to the scope specified by the caller.
2658      * @returns {Function} A function which invokes the passed function at the specified interval.
2659      */
2660     createThrottled: function(fn, interval, scope) {
2661         var lastCallTime, elapsed, lastArgs, timer, execute = function() {
2662             fn.apply(scope || this, lastArgs);
2663             lastCallTime = new Date().getTime();
2664         };
2665
2666         return function() {
2667             elapsed = new Date().getTime() - lastCallTime;
2668             lastArgs = arguments;
2669
2670             clearTimeout(timer);
2671             if (!lastCallTime || (elapsed >= interval)) {
2672                 execute();
2673             } else {
2674                 timer = setTimeout(execute, interval - elapsed);
2675             }
2676         };
2677     },
2678
2679     /**
2680      * Adds behavior to an existing method that is executed before the
2681      * original behavior of the function.  For example:
2682      * 
2683      *     var soup = {
2684      *         contents: [],
2685      *         add: function(ingredient) {
2686      *             this.contents.push(ingredient);
2687      *         }
2688      *     };
2689      *     Ext.Function.interceptBefore(soup, "add", function(ingredient){
2690      *         if (!this.contents.length && ingredient !== "water") {
2691      *             // Always add water to start with
2692      *             this.contents.push("water");
2693      *         }
2694      *     });
2695      *     soup.add("onions");
2696      *     soup.add("salt");
2697      *     soup.contents; // will contain: water, onions, salt
2698      * 
2699      * @param {Object} object The target object
2700      * @param {String} methodName Name of the method to override
2701      * @param {Function} fn Function with the new behavior.  It will
2702      * be called with the same arguments as the original method.  The
2703      * return value of this function will be the return value of the
2704      * new method.
2705      * @return {Function} The new function just created.
2706      */
2707     interceptBefore: function(object, methodName, fn) {
2708         var method = object[methodName] || Ext.emptyFn;
2709
2710         return object[methodName] = function() {
2711             var ret = fn.apply(this, arguments);
2712             method.apply(this, arguments);
2713
2714             return ret;
2715         };
2716     },
2717
2718     /**
2719      * Adds behavior to an existing method that is executed after the
2720      * original behavior of the function.  For example:
2721      * 
2722      *     var soup = {
2723      *         contents: [],
2724      *         add: function(ingredient) {
2725      *             this.contents.push(ingredient);
2726      *         }
2727      *     };
2728      *     Ext.Function.interceptAfter(soup, "add", function(ingredient){
2729      *         // Always add a bit of extra salt
2730      *         this.contents.push("salt");
2731      *     });
2732      *     soup.add("water");
2733      *     soup.add("onions");
2734      *     soup.contents; // will contain: water, salt, onions, salt
2735      * 
2736      * @param {Object} object The target object
2737      * @param {String} methodName Name of the method to override
2738      * @param {Function} fn Function with the new behavior.  It will
2739      * be called with the same arguments as the original method.  The
2740      * return value of this function will be the return value of the
2741      * new method.
2742      * @return {Function} The new function just created.
2743      */
2744     interceptAfter: function(object, methodName, fn) {
2745         var method = object[methodName] || Ext.emptyFn;
2746
2747         return object[methodName] = function() {
2748             method.apply(this, arguments);
2749             return fn.apply(this, arguments);
2750         };
2751     }
2752 };
2753
2754 /**
2755  * @method
2756  * @member Ext
2757  * @alias Ext.Function#defer
2758  */
2759 Ext.defer = Ext.Function.alias(Ext.Function, 'defer');
2760
2761 /**
2762  * @method
2763  * @member Ext
2764  * @alias Ext.Function#pass
2765  */
2766 Ext.pass = Ext.Function.alias(Ext.Function, 'pass');
2767
2768 /**
2769  * @method
2770  * @member Ext
2771  * @alias Ext.Function#bind
2772  */
2773 Ext.bind = Ext.Function.alias(Ext.Function, 'bind');
2774
2775 /**
2776  * @author Jacky Nguyen <jacky@sencha.com>
2777  * @docauthor Jacky Nguyen <jacky@sencha.com>
2778  * @class Ext.Object
2779  *
2780  * A collection of useful static methods to deal with objects.
2781  *
2782  * @singleton
2783  */
2784
2785 (function() {
2786
2787 var ExtObject = Ext.Object = {
2788
2789     /**
2790      * Converts a `name` - `value` pair to an array of objects with support for nested structures. Useful to construct
2791      * query strings. For example:
2792      *
2793      *     var objects = Ext.Object.toQueryObjects('hobbies', ['reading', 'cooking', 'swimming']);
2794      *
2795      *     // objects then equals:
2796      *     [
2797      *         { name: 'hobbies', value: 'reading' },
2798      *         { name: 'hobbies', value: 'cooking' },
2799      *         { name: 'hobbies', value: 'swimming' },
2800      *     ];
2801      *
2802      *     var objects = Ext.Object.toQueryObjects('dateOfBirth', {
2803      *         day: 3,
2804      *         month: 8,
2805      *         year: 1987,
2806      *         extra: {
2807      *             hour: 4
2808      *             minute: 30
2809      *         }
2810      *     }, true); // Recursive
2811      *
2812      *     // objects then equals:
2813      *     [
2814      *         { name: 'dateOfBirth[day]', value: 3 },
2815      *         { name: 'dateOfBirth[month]', value: 8 },
2816      *         { name: 'dateOfBirth[year]', value: 1987 },
2817      *         { name: 'dateOfBirth[extra][hour]', value: 4 },
2818      *         { name: 'dateOfBirth[extra][minute]', value: 30 },
2819      *     ];
2820      *
2821      * @param {String} name
2822      * @param {Object/Array} value
2823      * @param {Boolean} [recursive=false] True to traverse object recursively
2824      * @return {Array}
2825      */
2826     toQueryObjects: function(name, value, recursive) {
2827         var self = ExtObject.toQueryObjects,
2828             objects = [],
2829             i, ln;
2830
2831         if (Ext.isArray(value)) {
2832             for (i = 0, ln = value.length; i < ln; i++) {
2833                 if (recursive) {
2834                     objects = objects.concat(self(name + '[' + i + ']', value[i], true));
2835                 }
2836                 else {
2837                     objects.push({
2838                         name: name,
2839                         value: value[i]
2840                     });
2841                 }
2842             }
2843         }
2844         else if (Ext.isObject(value)) {
2845             for (i in value) {
2846                 if (value.hasOwnProperty(i)) {
2847                     if (recursive) {
2848                         objects = objects.concat(self(name + '[' + i + ']', value[i], true));
2849                     }
2850                     else {
2851                         objects.push({
2852                             name: name,
2853                             value: value[i]
2854                         });
2855                     }
2856                 }
2857             }
2858         }
2859         else {
2860             objects.push({
2861                 name: name,
2862                 value: value
2863             });
2864         }
2865
2866         return objects;
2867     },
2868
2869     /**
2870      * Takes an object and converts it to an encoded query string.
2871      *
2872      * Non-recursive:
2873      *
2874      *     Ext.Object.toQueryString({foo: 1, bar: 2}); // returns "foo=1&bar=2"
2875      *     Ext.Object.toQueryString({foo: null, bar: 2}); // returns "foo=&bar=2"
2876      *     Ext.Object.toQueryString({'some price': '$300'}); // returns "some%20price=%24300"
2877      *     Ext.Object.toQueryString({date: new Date(2011, 0, 1)}); // returns "date=%222011-01-01T00%3A00%3A00%22"
2878      *     Ext.Object.toQueryString({colors: ['red', 'green', 'blue']}); // returns "colors=red&colors=green&colors=blue"
2879      *
2880      * Recursive:
2881      *
2882      *     Ext.Object.toQueryString({
2883      *         username: 'Jacky',
2884      *         dateOfBirth: {
2885      *             day: 1,
2886      *             month: 2,
2887      *             year: 1911
2888      *         },
2889      *         hobbies: ['coding', 'eating', 'sleeping', ['nested', 'stuff']]
2890      *     }, true); // returns the following string (broken down and url-decoded for ease of reading purpose):
2891      *     // username=Jacky
2892      *     //    &dateOfBirth[day]=1&dateOfBirth[month]=2&dateOfBirth[year]=1911
2893      *     //    &hobbies[0]=coding&hobbies[1]=eating&hobbies[2]=sleeping&hobbies[3][0]=nested&hobbies[3][1]=stuff
2894      *
2895      * @param {Object} object The object to encode
2896      * @param {Boolean} [recursive=false] Whether or not to interpret the object in recursive format.
2897      * (PHP / Ruby on Rails servers and similar).
2898      * @return {String} queryString
2899      */
2900     toQueryString: function(object, recursive) {
2901         var paramObjects = [],
2902             params = [],
2903             i, j, ln, paramObject, value;
2904
2905         for (i in object) {
2906             if (object.hasOwnProperty(i)) {
2907                 paramObjects = paramObjects.concat(ExtObject.toQueryObjects(i, object[i], recursive));
2908             }
2909         }
2910
2911         for (j = 0, ln = paramObjects.length; j < ln; j++) {
2912             paramObject = paramObjects[j];
2913             value = paramObject.value;
2914
2915             if (Ext.isEmpty(value)) {
2916                 value = '';
2917             }
2918             else if (Ext.isDate(value)) {
2919                 value = Ext.Date.toString(value);
2920             }
2921
2922             params.push(encodeURIComponent(paramObject.name) + '=' + encodeURIComponent(String(value)));
2923         }
2924
2925         return params.join('&');
2926     },
2927
2928     /**
2929      * Converts a query string back into an object.
2930      *
2931      * Non-recursive:
2932      *
2933      *     Ext.Object.fromQueryString(foo=1&bar=2); // returns {foo: 1, bar: 2}
2934      *     Ext.Object.fromQueryString(foo=&bar=2); // returns {foo: null, bar: 2}
2935      *     Ext.Object.fromQueryString(some%20price=%24300); // returns {'some price': '$300'}
2936      *     Ext.Object.fromQueryString(colors=red&colors=green&colors=blue); // returns {colors: ['red', 'green', 'blue']}
2937      *
2938      * Recursive:
2939      *
2940      *       Ext.Object.fromQueryString("username=Jacky&dateOfBirth[day]=1&dateOfBirth[month]=2&dateOfBirth[year]=1911&hobbies[0]=coding&hobbies[1]=eating&hobbies[2]=sleeping&hobbies[3][0]=nested&hobbies[3][1]=stuff", true);
2941      *     // returns
2942      *     {
2943      *         username: 'Jacky',
2944      *         dateOfBirth: {
2945      *             day: '1',
2946      *             month: '2',
2947      *             year: '1911'
2948      *         },
2949      *         hobbies: ['coding', 'eating', 'sleeping', ['nested', 'stuff']]
2950      *     }
2951      *
2952      * @param {String} queryString The query string to decode
2953      * @param {Boolean} [recursive=false] Whether or not to recursively decode the string. This format is supported by
2954      * PHP / Ruby on Rails servers and similar.
2955      * @return {Object}
2956      */
2957     fromQueryString: function(queryString, recursive) {
2958         var parts = queryString.replace(/^\?/, '').split('&'),
2959             object = {},
2960             temp, components, name, value, i, ln,
2961             part, j, subLn, matchedKeys, matchedName,
2962             keys, key, nextKey;
2963
2964         for (i = 0, ln = parts.length; i < ln; i++) {
2965             part = parts[i];
2966
2967             if (part.length > 0) {
2968                 components = part.split('=');
2969                 name = decodeURIComponent(components[0]);
2970                 value = (components[1] !== undefined) ? decodeURIComponent(components[1]) : '';
2971
2972                 if (!recursive) {
2973                     if (object.hasOwnProperty(name)) {
2974                         if (!Ext.isArray(object[name])) {
2975                             object[name] = [object[name]];
2976                         }
2977
2978                         object[name].push(value);
2979                     }
2980                     else {
2981                         object[name] = value;
2982                     }
2983                 }
2984                 else {
2985                     matchedKeys = name.match(/(\[):?([^\]]*)\]/g);
2986                     matchedName = name.match(/^([^\[]+)/);
2987
2988                     if (!matchedName) {
2989                         Ext.Error.raise({
2990                             sourceClass: "Ext.Object",
2991                             sourceMethod: "fromQueryString",
2992                             queryString: queryString,
2993                             recursive: recursive,
2994                             msg: 'Malformed query string given, failed parsing name from "' + part + '"'
2995                         });
2996                     }
2997
2998                     name = matchedName[0];
2999                     keys = [];
3000
3001                     if (matchedKeys === null) {
3002                         object[name] = value;
3003                         continue;
3004                     }
3005
3006                     for (j = 0, subLn = matchedKeys.length; j < subLn; j++) {
3007                         key = matchedKeys[j];
3008                         key = (key.length === 2) ? '' : key.substring(1, key.length - 1);
3009                         keys.push(key);
3010                     }
3011
3012                     keys.unshift(name);
3013
3014                     temp = object;
3015
3016                     for (j = 0, subLn = keys.length; j < subLn; j++) {
3017                         key = keys[j];
3018
3019                         if (j === subLn - 1) {
3020                             if (Ext.isArray(temp) && key === '') {
3021                                 temp.push(value);
3022                             }
3023                             else {
3024                                 temp[key] = value;
3025                             }
3026                         }
3027                         else {
3028                             if (temp[key] === undefined || typeof temp[key] === 'string') {
3029                                 nextKey = keys[j+1];
3030
3031                                 temp[key] = (Ext.isNumeric(nextKey) || nextKey === '') ? [] : {};
3032                             }
3033
3034                             temp = temp[key];
3035                         }
3036                     }
3037                 }
3038             }
3039         }
3040
3041         return object;
3042     },
3043
3044     /**
3045      * Iterates through an object and invokes the given callback function for each iteration.
3046      * The iteration can be stopped by returning `false` in the callback function. For example:
3047      *
3048      *     var person = {
3049      *         name: 'Jacky'
3050      *         hairColor: 'black'
3051      *         loves: ['food', 'sleeping', 'wife']
3052      *     };
3053      *
3054      *     Ext.Object.each(person, function(key, value, myself) {
3055      *         console.log(key + ":" + value);
3056      *
3057      *         if (key === 'hairColor') {
3058      *             return false; // stop the iteration
3059      *         }
3060      *     });
3061      *
3062      * @param {Object} object The object to iterate
3063      * @param {Function} fn The callback function.
3064      * @param {String} fn.key
3065      * @param {Object} fn.value
3066      * @param {Object} fn.object The object itself
3067      * @param {Object} [scope] The execution scope (`this`) of the callback function
3068      */
3069     each: function(object, fn, scope) {
3070         for (var property in object) {
3071             if (object.hasOwnProperty(property)) {
3072                 if (fn.call(scope || object, property, object[property], object) === false) {
3073                     return;
3074                 }
3075             }
3076         }
3077     },
3078
3079     /**
3080      * Merges any number of objects recursively without referencing them or their children.
3081      *
3082      *     var extjs = {
3083      *         companyName: 'Ext JS',
3084      *         products: ['Ext JS', 'Ext GWT', 'Ext Designer'],
3085      *         isSuperCool: true
3086      *         office: {
3087      *             size: 2000,
3088      *             location: 'Palo Alto',
3089      *             isFun: true
3090      *         }
3091      *     };
3092      *
3093      *     var newStuff = {
3094      *         companyName: 'Sencha Inc.',
3095      *         products: ['Ext JS', 'Ext GWT', 'Ext Designer', 'Sencha Touch', 'Sencha Animator'],
3096      *         office: {
3097      *             size: 40000,
3098      *             location: 'Redwood City'
3099      *         }
3100      *     };
3101      *
3102      *     var sencha = Ext.Object.merge(extjs, newStuff);
3103      *
3104      *     // extjs and sencha then equals to
3105      *     {
3106      *         companyName: 'Sencha Inc.',
3107      *         products: ['Ext JS', 'Ext GWT', 'Ext Designer', 'Sencha Touch', 'Sencha Animator'],
3108      *         isSuperCool: true
3109      *         office: {
3110      *             size: 30000,
3111      *             location: 'Redwood City'
3112      *             isFun: true
3113      *         }
3114      *     }
3115      *
3116      * @param {Object...} object Any number of objects to merge.
3117      * @return {Object} merged The object that is created as a result of merging all the objects passed in.
3118      */
3119     merge: function(source, key, value) {
3120         if (typeof key === 'string') {
3121             if (value && value.constructor === Object) {
3122                 if (source[key] && source[key].constructor === Object) {
3123                     ExtObject.merge(source[key], value);
3124                 }
3125                 else {
3126                     source[key] = Ext.clone(value);
3127                 }
3128             }
3129             else {
3130                 source[key] = value;
3131             }
3132
3133             return source;
3134         }
3135
3136         var i = 1,
3137             ln = arguments.length,
3138             object, property;
3139
3140         for (; i < ln; i++) {
3141             object = arguments[i];
3142
3143             for (property in object) {
3144                 if (object.hasOwnProperty(property)) {
3145                     ExtObject.merge(source, property, object[property]);
3146                 }
3147             }
3148         }
3149
3150         return source;
3151     },
3152
3153     /**
3154      * Returns the first matching key corresponding to the given value.
3155      * If no matching value is found, null is returned.
3156      *
3157      *     var person = {
3158      *         name: 'Jacky',
3159      *         loves: 'food'
3160      *     };
3161      *
3162      *     alert(Ext.Object.getKey(person, 'food')); // alerts 'loves'
3163      *
3164      * @param {Object} object
3165      * @param {Object} value The value to find
3166      */
3167     getKey: function(object, value) {
3168         for (var property in object) {
3169             if (object.hasOwnProperty(property) && object[property] === value) {
3170                 return property;
3171             }
3172         }
3173
3174         return null;
3175     },
3176
3177     /**
3178      * Gets all values of the given object as an array.
3179      *
3180      *     var values = Ext.Object.getValues({
3181      *         name: 'Jacky',
3182      *         loves: 'food'
3183      *     }); // ['Jacky', 'food']
3184      *
3185      * @param {Object} object
3186      * @return {Array} An array of values from the object
3187      */
3188     getValues: function(object) {
3189         var values = [],
3190             property;
3191
3192         for (property in object) {
3193             if (object.hasOwnProperty(property)) {
3194                 values.push(object[property]);
3195             }
3196         }
3197
3198         return values;
3199     },
3200
3201     /**
3202      * Gets all keys of the given object as an array.
3203      *
3204      *     var values = Ext.Object.getKeys({
3205      *         name: 'Jacky',
3206      *         loves: 'food'
3207      *     }); // ['name', 'loves']
3208      *
3209      * @param {Object} object
3210      * @return {String[]} An array of keys from the object
3211      * @method
3212      */
3213     getKeys: ('keys' in Object.prototype) ? Object.keys : function(object) {
3214         var keys = [],
3215             property;
3216
3217         for (property in object) {
3218             if (object.hasOwnProperty(property)) {
3219                 keys.push(property);
3220             }
3221         }
3222
3223         return keys;
3224     },
3225
3226     /**
3227      * Gets the total number of this object's own properties
3228      *
3229      *     var size = Ext.Object.getSize({
3230      *         name: 'Jacky',
3231      *         loves: 'food'
3232      *     }); // size equals 2
3233      *
3234      * @param {Object} object
3235      * @return {Number} size
3236      */
3237     getSize: function(object) {
3238         var size = 0,
3239             property;
3240
3241         for (property in object) {
3242             if (object.hasOwnProperty(property)) {
3243                 size++;
3244             }
3245         }
3246
3247         return size;
3248     }
3249 };
3250
3251
3252 /**
3253  * A convenient alias method for {@link Ext.Object#merge}.
3254  *
3255  * @member Ext
3256  * @method merge
3257  * @alias Ext.Object#merge
3258  */
3259 Ext.merge = Ext.Object.merge;
3260
3261 /**
3262  * Alias for {@link Ext.Object#toQueryString}.
3263  *
3264  * @member Ext
3265  * @method urlEncode
3266  * @alias Ext.Object#toQueryString
3267  * @deprecated 4.0.0 Use {@link Ext.Object#toQueryString} instead
3268  */
3269 Ext.urlEncode = function() {
3270     var args = Ext.Array.from(arguments),
3271         prefix = '';
3272
3273     // Support for the old `pre` argument
3274     if ((typeof args[1] === 'string')) {
3275         prefix = args[1] + '&';
3276         args[1] = false;
3277     }
3278
3279     return prefix + Ext.Object.toQueryString.apply(Ext.Object, args);
3280 };
3281
3282 /**
3283  * Alias for {@link Ext.Object#fromQueryString}.
3284  *
3285  * @member Ext
3286  * @method urlDecode
3287  * @alias Ext.Object#fromQueryString
3288  * @deprecated 4.0.0 Use {@link Ext.Object#fromQueryString} instead
3289  */
3290 Ext.urlDecode = function() {
3291     return Ext.Object.fromQueryString.apply(Ext.Object, arguments);
3292 };
3293
3294 })();
3295
3296 /**
3297  * @class Ext.Date
3298  * A set of useful static methods to deal with date
3299  * Note that if Ext.Date is required and loaded, it will copy all methods / properties to
3300  * this object for convenience
3301  *
3302  * The date parsing and formatting syntax contains a subset of
3303  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
3304  * supported will provide results equivalent to their PHP versions.
3305  *
3306  * The following is a list of all currently supported formats:
3307  * <pre class="">
3308 Format  Description                                                               Example returned values
3309 ------  -----------------------------------------------------------------------   -----------------------
3310   d     Day of the month, 2 digits with leading zeros                             01 to 31
3311   D     A short textual representation of the day of the week                     Mon to Sun
3312   j     Day of the month without leading zeros                                    1 to 31
3313   l     A full textual representation of the day of the week                      Sunday to Saturday
3314   N     ISO-8601 numeric representation of the day of the week                    1 (for Monday) through 7 (for Sunday)
3315   S     English ordinal suffix for the day of the month, 2 characters             st, nd, rd or th. Works well with j
3316   w     Numeric representation of the day of the week                             0 (for Sunday) to 6 (for Saturday)
3317   z     The day of the year (starting from 0)                                     0 to 364 (365 in leap years)
3318   W     ISO-8601 week number of year, weeks starting on Monday                    01 to 53
3319   F     A full textual representation of a month, such as January or March        January to December
3320   m     Numeric representation of a month, with leading zeros                     01 to 12
3321   M     A short textual representation of a month                                 Jan to Dec
3322   n     Numeric representation of a month, without leading zeros                  1 to 12
3323   t     Number of days in the given month                                         28 to 31
3324   L     Whether it&#39;s a leap year                                                  1 if it is a leap year, 0 otherwise.
3325   o     ISO-8601 year number (identical to (Y), but if the ISO week number (W)    Examples: 1998 or 2004
3326         belongs to the previous or next year, that year is used instead)
3327   Y     A full numeric representation of a year, 4 digits                         Examples: 1999 or 2003
3328   y     A two digit representation of a year                                      Examples: 99 or 03
3329   a     Lowercase Ante meridiem and Post meridiem                                 am or pm
3330   A     Uppercase Ante meridiem and Post meridiem                                 AM or PM
3331   g     12-hour format of an hour without leading zeros                           1 to 12
3332   G     24-hour format of an hour without leading zeros                           0 to 23
3333   h     12-hour format of an hour with leading zeros                              01 to 12
3334   H     24-hour format of an hour with leading zeros                              00 to 23
3335   i     Minutes, with leading zeros                                               00 to 59
3336   s     Seconds, with leading zeros                                               00 to 59
3337   u     Decimal fraction of a second                                              Examples:
3338         (minimum 1 digit, arbitrary number of digits allowed)                     001 (i.e. 0.001s) or
3339                                                                                   100 (i.e. 0.100s) or
3340                                                                                   999 (i.e. 0.999s) or
3341                                                                                   999876543210 (i.e. 0.999876543210s)
3342   O     Difference to Greenwich time (GMT) in hours and minutes                   Example: +1030
3343   P     Difference to Greenwich time (GMT) with colon between hours and minutes   Example: -08:00
3344   T     Timezone abbreviation of the machine running the code                     Examples: EST, MDT, PDT ...
3345   Z     Timezone offset in seconds (negative if west of UTC, positive if east)    -43200 to 50400
3346   c     ISO 8601 date
3347         Notes:                                                                    Examples:
3348         1) If unspecified, the month / day defaults to the current month / day,   1991 or
3349            the time defaults to midnight, while the timezone defaults to the      1992-10 or
3350            browser's timezone. If a time is specified, it must include both hours 1993-09-20 or
3351            and minutes. The "T" delimiter, seconds, milliseconds and timezone     1994-08-19T16:20+01:00 or
3352            are optional.                                                          1995-07-18T17:21:28-02:00 or
3353         2) The decimal fraction of a second, if specified, must contain at        1996-06-17T18:22:29.98765+03:00 or
3354            least 1 digit (there is no limit to the maximum number                 1997-05-16T19:23:30,12345-0400 or
3355            of digits allowed), and may be delimited by either a '.' or a ','      1998-04-15T20:24:31.2468Z or
3356         Refer to the examples on the right for the various levels of              1999-03-14T20:24:32Z or
3357         date-time granularity which are supported, or see                         2000-02-13T21:25:33
3358         http://www.w3.org/TR/NOTE-datetime for more info.                         2001-01-12 22:26:34
3359   U     Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT)                1193432466 or -2138434463
3360   MS    Microsoft AJAX serialized dates                                           \/Date(1238606590509)\/ (i.e. UTC milliseconds since epoch) or
3361                                                                                   \/Date(1238606590509+0800)\/
3362 </pre>
3363  *
3364  * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
3365  * <pre><code>
3366 // Sample date:
3367 // 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
3368
3369 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
3370 console.log(Ext.Date.format(dt, 'Y-m-d'));                          // 2007-01-10
3371 console.log(Ext.Date.format(dt, 'F j, Y, g:i a'));                  // January 10, 2007, 3:05 pm
3372 console.log(Ext.Date.format(dt, 'l, \\t\\he jS \\of F Y h:i:s A')); // Wednesday, the 10th of January 2007 03:05:01 PM
3373 </code></pre>
3374  *
3375  * Here are some standard date/time patterns that you might find helpful.  They
3376  * are not part of the source of Ext.Date, but to use them you can simply copy this
3377  * block of code into any script that is included after Ext.Date and they will also become
3378  * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
3379  * <pre><code>
3380 Ext.Date.patterns = {
3381     ISO8601Long:"Y-m-d H:i:s",
3382     ISO8601Short:"Y-m-d",
3383     ShortDate: "n/j/Y",
3384     LongDate: "l, F d, Y",
3385     FullDateTime: "l, F d, Y g:i:s A",
3386     MonthDay: "F d",
3387     ShortTime: "g:i A",
3388     LongTime: "g:i:s A",
3389     SortableDateTime: "Y-m-d\\TH:i:s",
3390     UniversalSortableDateTime: "Y-m-d H:i:sO",
3391     YearMonth: "F, Y"
3392 };
3393 </code></pre>
3394  *
3395  * Example usage:
3396  * <pre><code>
3397 var dt = new Date();
3398 console.log(Ext.Date.format(dt, Ext.Date.patterns.ShortDate));
3399 </code></pre>
3400  * <p>Developer-written, custom formats may be used by supplying both a formatting and a parsing function
3401  * which perform to specialized requirements. The functions are stored in {@link #parseFunctions} and {@link #formatFunctions}.</p>
3402  * @singleton
3403  */
3404
3405 /*
3406  * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
3407  * (see http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/)
3408  * They generate precompiled functions from format patterns instead of parsing and
3409  * processing each pattern every time a date is formatted. These functions are available
3410  * on every Date object.
3411  */
3412
3413 (function() {
3414
3415 // create private copy of Ext's Ext.util.Format.format() method
3416 // - to remove unnecessary dependency
3417 // - to resolve namespace conflict with MS-Ajax's implementation
3418 function xf(format) {
3419     var args = Array.prototype.slice.call(arguments, 1);
3420     return format.replace(/\{(\d+)\}/g, function(m, i) {
3421         return args[i];
3422     });
3423 }
3424
3425 Ext.Date = {
3426     /**
3427      * Returns the current timestamp
3428      * @return {Date} The current timestamp
3429      * @method
3430      */
3431     now: Date.now || function() {
3432         return +new Date();
3433     },
3434
3435     /**
3436      * @private
3437      * Private for now
3438      */
3439     toString: function(date) {
3440         var pad = Ext.String.leftPad;
3441
3442         return date.getFullYear() + "-"
3443             + pad(date.getMonth() + 1, 2, '0') + "-"
3444             + pad(date.getDate(), 2, '0') + "T"
3445             + pad(date.getHours(), 2, '0') + ":"
3446             + pad(date.getMinutes(), 2, '0') + ":"
3447             + pad(date.getSeconds(), 2, '0');
3448     },
3449
3450     /**
3451      * Returns the number of milliseconds between two dates
3452      * @param {Date} dateA The first date
3453      * @param {Date} dateB (optional) The second date, defaults to now
3454      * @return {Number} The difference in milliseconds
3455      */
3456     getElapsed: function(dateA, dateB) {
3457         return Math.abs(dateA - (dateB || new Date()));
3458     },
3459
3460     /**
3461      * Global flag which determines if strict date parsing should be used.
3462      * Strict date parsing will not roll-over invalid dates, which is the
3463      * default behaviour of javascript Date objects.
3464      * (see {@link #parse} for more information)
3465      * Defaults to <tt>false</tt>.
3466      * @type Boolean
3467     */
3468     useStrict: false,
3469
3470     // private
3471     formatCodeToRegex: function(character, currentGroup) {
3472         // Note: currentGroup - position in regex result array (see notes for Ext.Date.parseCodes below)
3473         var p = utilDate.parseCodes[character];
3474
3475         if (p) {
3476           p = typeof p == 'function'? p() : p;
3477           utilDate.parseCodes[character] = p; // reassign function result to prevent repeated execution
3478         }
3479
3480         return p ? Ext.applyIf({
3481           c: p.c ? xf(p.c, currentGroup || "{0}") : p.c
3482         }, p) : {
3483             g: 0,
3484             c: null,
3485             s: Ext.String.escapeRegex(character) // treat unrecognised characters as literals
3486         };
3487     },
3488
3489     /**
3490      * <p>An object hash in which each property is a date parsing function. The property name is the
3491      * format string which that function parses.</p>
3492      * <p>This object is automatically populated with date parsing functions as
3493      * date formats are requested for Ext standard formatting strings.</p>
3494      * <p>Custom parsing functions may be inserted into this object, keyed by a name which from then on
3495      * may be used as a format string to {@link #parse}.<p>
3496      * <p>Example:</p><pre><code>
3497 Ext.Date.parseFunctions['x-date-format'] = myDateParser;
3498 </code></pre>
3499      * <p>A parsing function should return a Date object, and is passed the following parameters:<div class="mdetail-params"><ul>
3500      * <li><code>date</code> : String<div class="sub-desc">The date string to parse.</div></li>
3501      * <li><code>strict</code> : Boolean<div class="sub-desc">True to validate date strings while parsing
3502      * (i.e. prevent javascript Date "rollover") (The default must be false).
3503      * Invalid date strings should return null when parsed.</div></li>
3504      * </ul></div></p>
3505      * <p>To enable Dates to also be <i>formatted</i> according to that format, a corresponding
3506      * formatting function must be placed into the {@link #formatFunctions} property.
3507      * @property parseFunctions
3508      * @type Object
3509      */
3510     parseFunctions: {
3511         "MS": function(input, strict) {
3512             // note: the timezone offset is ignored since the MS Ajax server sends
3513             // a UTC milliseconds-since-Unix-epoch value (negative values are allowed)
3514             var re = new RegExp('\\/Date\\(([-+])?(\\d+)(?:[+-]\\d{4})?\\)\\/');
3515             var r = (input || '').match(re);
3516             return r? new Date(((r[1] || '') + r[2]) * 1) : null;
3517         }
3518     },
3519     parseRegexes: [],
3520
3521     /**
3522      * <p>An object hash in which each property is a date formatting function. The property name is the
3523      * format string which corresponds to the produced formatted date string.</p>
3524      * <p>This object is automatically populated with date formatting functions as
3525      * date formats are requested for Ext standard formatting strings.</p>
3526      * <p>Custom formatting functions may be inserted into this object, keyed by a name which from then on
3527      * may be used as a format string to {@link #format}. Example:</p><pre><code>
3528 Ext.Date.formatFunctions['x-date-format'] = myDateFormatter;
3529 </code></pre>
3530      * <p>A formatting function should return a string representation of the passed Date object, and is passed the following parameters:<div class="mdetail-params"><ul>
3531      * <li><code>date</code> : Date<div class="sub-desc">The Date to format.</div></li>
3532      * </ul></div></p>
3533      * <p>To enable date strings to also be <i>parsed</i> according to that format, a corresponding
3534      * parsing function must be placed into the {@link #parseFunctions} property.
3535      * @property formatFunctions
3536      * @type Object
3537      */
3538     formatFunctions: {
3539         "MS": function() {
3540             // UTC milliseconds since Unix epoch (MS-AJAX serialized date format (MRSF))
3541             return '\\/Date(' + this.getTime() + ')\\/';
3542         }
3543     },
3544
3545     y2kYear : 50,
3546
3547     /**
3548      * Date interval constant
3549      * @type String
3550      */
3551     MILLI : "ms",
3552
3553     /**
3554      * Date interval constant
3555      * @type String
3556      */
3557     SECOND : "s",
3558
3559     /**
3560      * Date interval constant
3561      * @type String
3562      */
3563     MINUTE : "mi",
3564
3565     /** Date interval constant
3566      * @type String
3567      */
3568     HOUR : "h",
3569
3570     /**
3571      * Date interval constant
3572      * @type String
3573      */
3574     DAY : "d",
3575
3576     /**
3577      * Date interval constant
3578      * @type String
3579      */
3580     MONTH : "mo",
3581
3582     /**
3583      * Date interval constant
3584      * @type String
3585      */
3586     YEAR : "y",
3587
3588     /**
3589      * <p>An object hash containing default date values used during date parsing.</p>
3590      * <p>The following properties are available:<div class="mdetail-params"><ul>
3591      * <li><code>y</code> : Number<div class="sub-desc">The default year value. (defaults to undefined)</div></li>
3592      * <li><code>m</code> : Number<div class="sub-desc">The default 1-based month value. (defaults to undefined)</div></li>
3593      * <li><code>d</code> : Number<div class="sub-desc">The default day value. (defaults to undefined)</div></li>
3594      * <li><code>h</code> : Number<div class="sub-desc">The default hour value. (defaults to undefined)</div></li>
3595      * <li><code>i</code> : Number<div class="sub-desc">The default minute value. (defaults to undefined)</div></li>
3596      * <li><code>s</code> : Number<div class="sub-desc">The default second value. (defaults to undefined)</div></li>
3597      * <li><code>ms</code> : Number<div class="sub-desc">The default millisecond value. (defaults to undefined)</div></li>
3598      * </ul></div></p>
3599      * <p>Override these properties to customize the default date values used by the {@link #parse} method.</p>
3600      * <p><b>Note: In countries which experience Daylight Saving Time (i.e. DST), the <tt>h</tt>, <tt>i</tt>, <tt>s</tt>
3601      * and <tt>ms</tt> properties may coincide with the exact time in which DST takes effect.
3602      * It is the responsiblity of the developer to account for this.</b></p>
3603      * Example Usage:
3604      * <pre><code>
3605 // set default day value to the first day of the month
3606 Ext.Date.defaults.d = 1;
3607
3608 // parse a February date string containing only year and month values.
3609 // setting the default day value to 1 prevents weird date rollover issues
3610 // when attempting to parse the following date string on, for example, March 31st 2009.
3611 Ext.Date.parse('2009-02', 'Y-m'); // returns a Date object representing February 1st 2009
3612 </code></pre>
3613      * @property defaults
3614      * @type Object
3615      */
3616     defaults: {},
3617
3618     /**
3619      * @property {String[]} dayNames
3620      * An array of textual day names.
3621      * Override these values for international dates.
3622      * Example:
3623      * <pre><code>
3624 Ext.Date.dayNames = [
3625     'SundayInYourLang',
3626     'MondayInYourLang',
3627     ...
3628 ];
3629 </code></pre>
3630      */
3631     dayNames : [
3632         "Sunday",
3633         "Monday",
3634         "Tuesday",
3635         "Wednesday",
3636         "Thursday",
3637         "Friday",
3638         "Saturday"
3639     ],
3640
3641     /**
3642      * @property {String[]} monthNames
3643      * An array of textual month names.
3644      * Override these values for international dates.
3645      * Example:
3646      * <pre><code>
3647 Ext.Date.monthNames = [
3648     'JanInYourLang',
3649     'FebInYourLang',
3650     ...
3651 ];
3652 </code></pre>
3653      */
3654     monthNames : [
3655         "January",
3656         "February",
3657         "March",
3658         "April",
3659         "May",
3660         "June",
3661         "July",
3662         "August",
3663         "September",
3664         "October",
3665         "November",
3666         "December"
3667     ],
3668
3669     /**
3670      * @property {Object} monthNumbers
3671      * An object hash of zero-based javascript month numbers (with short month names as keys. note: keys are case-sensitive).
3672      * Override these values for international dates.
3673      * Example:
3674      * <pre><code>
3675 Ext.Date.monthNumbers = {
3676     'ShortJanNameInYourLang':0,
3677     'ShortFebNameInYourLang':1,
3678     ...
3679 };
3680 </code></pre>
3681      */
3682     monthNumbers : {
3683         Jan:0,
3684         Feb:1,
3685         Mar:2,
3686         Apr:3,
3687         May:4,
3688         Jun:5,
3689         Jul:6,
3690         Aug:7,
3691         Sep:8,
3692         Oct:9,
3693         Nov:10,
3694         Dec:11
3695     },
3696     /**
3697      * @property {String} defaultFormat
3698      * <p>The date format string that the {@link Ext.util.Format#dateRenderer}
3699      * and {@link Ext.util.Format#date} functions use.  See {@link Ext.Date} for details.</p>
3700      * <p>This may be overridden in a locale file.</p>
3701      */
3702     defaultFormat : "m/d/Y",
3703     /**
3704      * Get the short month name for the given month number.
3705      * Override this function for international dates.
3706      * @param {Number} month A zero-based javascript month number.
3707      * @return {String} The short month name.
3708      */
3709     getShortMonthName : function(month) {
3710         return utilDate.monthNames[month].substring(0, 3);
3711     },
3712
3713     /**
3714      * Get the short day name for the given day number.
3715      * Override this function for international dates.
3716      * @param {Number} day A zero-based javascript day number.
3717      * @return {String} The short day name.
3718      */
3719     getShortDayName : function(day) {
3720         return utilDate.dayNames[day].substring(0, 3);
3721     },
3722
3723     /**
3724      * Get the zero-based javascript month number for the given short/full month name.
3725      * Override this function for international dates.
3726      * @param {String} name The short/full month name.
3727      * @return {Number} The zero-based javascript month number.
3728      */
3729     getMonthNumber : function(name) {
3730         // handle camel casing for english month names (since the keys for the Ext.Date.monthNumbers hash are case sensitive)
3731         return utilDate.monthNumbers[name.substring(0, 1).toUpperCase() + name.substring(1, 3).toLowerCase()];
3732     },
3733
3734     /**
3735      * Checks if the specified format contains hour information
3736      * @param {String} format The format to check
3737      * @return {Boolean} True if the format contains hour information
3738      * @method
3739      */
3740     formatContainsHourInfo : (function(){
3741         var stripEscapeRe = /(\\.)/g,
3742             hourInfoRe = /([gGhHisucUOPZ]|MS)/;
3743         return function(format){
3744             return hourInfoRe.test(format.replace(stripEscapeRe, ''));
3745         };
3746     })(),
3747
3748     /**
3749      * Checks if the specified format contains information about
3750      * anything other than the time.
3751      * @param {String} format The format to check
3752      * @return {Boolean} True if the format contains information about
3753      * date/day information.
3754      * @method
3755      */
3756     formatContainsDateInfo : (function(){
3757         var stripEscapeRe = /(\\.)/g,
3758             dateInfoRe = /([djzmnYycU]|MS)/;
3759
3760         return function(format){
3761             return dateInfoRe.test(format.replace(stripEscapeRe, ''));
3762         };
3763     })(),
3764
3765     /**
3766      * The base format-code to formatting-function hashmap used by the {@link #format} method.
3767      * Formatting functions are strings (or functions which return strings) which
3768      * will return the appropriate value when evaluated in the context of the Date object
3769      * from which the {@link #format} method is called.
3770      * Add to / override these mappings for custom date formatting.
3771      * Note: Ext.Date.format() treats characters as literals if an appropriate mapping cannot be found.
3772      * Example:
3773      * <pre><code>
3774 Ext.Date.formatCodes.x = "Ext.util.Format.leftPad(this.getDate(), 2, '0')";
3775 console.log(Ext.Date.format(new Date(), 'X'); // returns the current day of the month
3776 </code></pre>
3777      * @type Object
3778      */
3779     formatCodes : {
3780         d: "Ext.String.leftPad(this.getDate(), 2, '0')",
3781         D: "Ext.Date.getShortDayName(this.getDay())", // get localised short day name
3782         j: "this.getDate()",
3783         l: "Ext.Date.dayNames[this.getDay()]",
3784         N: "(this.getDay() ? this.getDay() : 7)",
3785         S: "Ext.Date.getSuffix(this)",
3786         w: "this.getDay()",
3787         z: "Ext.Date.getDayOfYear(this)",
3788         W: "Ext.String.leftPad(Ext.Date.getWeekOfYear(this), 2, '0')",
3789         F: "Ext.Date.monthNames[this.getMonth()]",
3790         m: "Ext.String.leftPad(this.getMonth() + 1, 2, '0')",
3791         M: "Ext.Date.getShortMonthName(this.getMonth())", // get localised short month name
3792         n: "(this.getMonth() + 1)",
3793         t: "Ext.Date.getDaysInMonth(this)",
3794         L: "(Ext.Date.isLeapYear(this) ? 1 : 0)",
3795         o: "(this.getFullYear() + (Ext.Date.getWeekOfYear(this) == 1 && this.getMonth() > 0 ? +1 : (Ext.Date.getWeekOfYear(this) >= 52 && this.getMonth() < 11 ? -1 : 0)))",
3796         Y: "Ext.String.leftPad(this.getFullYear(), 4, '0')",
3797         y: "('' + this.getFullYear()).substring(2, 4)",
3798         a: "(this.getHours() < 12 ? 'am' : 'pm')",
3799         A: "(this.getHours() < 12 ? 'AM' : 'PM')",
3800         g: "((this.getHours() % 12) ? this.getHours() % 12 : 12)",
3801         G: "this.getHours()",
3802         h: "Ext.String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0')",
3803         H: "Ext.String.leftPad(this.getHours(), 2, '0')",
3804         i: "Ext.String.leftPad(this.getMinutes(), 2, '0')",
3805         s: "Ext.String.leftPad(this.getSeconds(), 2, '0')",
3806         u: "Ext.String.leftPad(this.getMilliseconds(), 3, '0')",
3807         O: "Ext.Date.getGMTOffset(this)",
3808         P: "Ext.Date.getGMTOffset(this, true)",
3809         T: "Ext.Date.getTimezone(this)",
3810         Z: "(this.getTimezoneOffset() * -60)",
3811
3812         c: function() { // ISO-8601 -- GMT format
3813             for (var c = "Y-m-dTH:i:sP", code = [], i = 0, l = c.length; i < l; ++i) {
3814                 var e = c.charAt(i);
3815                 code.push(e == "T" ? "'T'" : utilDate.getFormatCode(e)); // treat T as a character literal
3816             }
3817             return code.join(" + ");
3818         },
3819         /*
3820         c: function() { // ISO-8601 -- UTC format
3821             return [
3822               "this.getUTCFullYear()", "'-'",
3823               "Ext.util.Format.leftPad(this.getUTCMonth() + 1, 2, '0')", "'-'",
3824               "Ext.util.Format.leftPad(this.getUTCDate(), 2, '0')",
3825               "'T'",
3826               "Ext.util.Format.leftPad(this.getUTCHours(), 2, '0')", "':'",
3827               "Ext.util.Format.leftPad(this.getUTCMinutes(), 2, '0')", "':'",
3828               "Ext.util.Format.leftPad(this.getUTCSeconds(), 2, '0')",
3829               "'Z'"
3830             ].join(" + ");
3831         },
3832         */
3833
3834         U: "Math.round(this.getTime() / 1000)"
3835     },
3836
3837     /**
3838      * Checks if the passed Date parameters will cause a javascript Date "rollover".
3839      * @param {Number} year 4-digit year
3840      * @param {Number} month 1-based month-of-year
3841      * @param {Number} day Day of month
3842      * @param {Number} hour (optional) Hour
3843      * @param {Number} minute (optional) Minute
3844      * @param {Number} second (optional) Second
3845      * @param {Number} millisecond (optional) Millisecond
3846      * @return {Boolean} true if the passed parameters do not cause a Date "rollover", false otherwise.
3847      */
3848     isValid : function(y, m, d, h, i, s, ms) {
3849         // setup defaults
3850         h = h || 0;
3851         i = i || 0;
3852         s = s || 0;
3853         ms = ms || 0;
3854
3855         // Special handling for year < 100
3856         var dt = utilDate.add(new Date(y < 100 ? 100 : y, m - 1, d, h, i, s, ms), utilDate.YEAR, y < 100 ? y - 100 : 0);
3857
3858         return y == dt.getFullYear() &&
3859             m == dt.getMonth() + 1 &&
3860             d == dt.getDate() &&
3861             h == dt.getHours() &&
3862             i == dt.getMinutes() &&
3863             s == dt.getSeconds() &&
3864             ms == dt.getMilliseconds();
3865     },
3866
3867     /**
3868      * Parses the passed string using the specified date format.
3869      * Note that this function expects normal calendar dates, meaning that months are 1-based (i.e. 1 = January).
3870      * The {@link #defaults} hash will be used for any date value (i.e. year, month, day, hour, minute, second or millisecond)
3871      * which cannot be found in the passed string. If a corresponding default date value has not been specified in the {@link #defaults} hash,
3872      * the current date's year, month, day or DST-adjusted zero-hour time value will be used instead.
3873      * Keep in mind that the input date string must precisely match the specified format string
3874      * in order for the parse operation to be successful (failed parse operations return a null value).
3875      * <p>Example:</p><pre><code>
3876 //dt = Fri May 25 2007 (current date)
3877 var dt = new Date();
3878
3879 //dt = Thu May 25 2006 (today&#39;s month/day in 2006)
3880 dt = Ext.Date.parse("2006", "Y");
3881
3882 //dt = Sun Jan 15 2006 (all date parts specified)
3883 dt = Ext.Date.parse("2006-01-15", "Y-m-d");
3884
3885 //dt = Sun Jan 15 2006 15:20:01
3886 dt = Ext.Date.parse("2006-01-15 3:20:01 PM", "Y-m-d g:i:s A");
3887
3888 // attempt to parse Sun Feb 29 2006 03:20:01 in strict mode
3889 dt = Ext.Date.parse("2006-02-29 03:20:01", "Y-m-d H:i:s", true); // returns null
3890 </code></pre>
3891      * @param {String} input The raw date string.
3892      * @param {String} format The expected date string format.
3893      * @param {Boolean} strict (optional) True to validate date strings while parsing (i.e. prevents javascript Date "rollover")
3894                         (defaults to false). Invalid date strings will return null when parsed.
3895      * @return {Date} The parsed Date.
3896      */
3897     parse : function(input, format, strict) {
3898         var p = utilDate.parseFunctions;
3899         if (p[format] == null) {
3900             utilDate.createParser(format);
3901         }
3902         return p[format](input, Ext.isDefined(strict) ? strict : utilDate.useStrict);
3903     },
3904
3905     // Backwards compat
3906     parseDate: function(input, format, strict){
3907         return utilDate.parse(input, format, strict);
3908     },
3909
3910
3911     // private
3912     getFormatCode : function(character) {
3913         var f = utilDate.formatCodes[character];
3914
3915         if (f) {
3916           f = typeof f == 'function'? f() : f;
3917           utilDate.formatCodes[character] = f; // reassign function result to prevent repeated execution
3918         }
3919
3920         // note: unknown characters are treated as literals
3921         return f || ("'" + Ext.String.escape(character) + "'");
3922     },
3923
3924     // private
3925     createFormat : function(format) {
3926         var code = [],
3927             special = false,
3928             ch = '';
3929
3930         for (var i = 0; i < format.length; ++i) {
3931             ch = format.charAt(i);
3932             if (!special && ch == "\\") {
3933                 special = true;
3934             } else if (special) {
3935                 special = false;
3936                 code.push("'" + Ext.String.escape(ch) + "'");
3937             } else {
3938                 code.push(utilDate.getFormatCode(ch));
3939             }
3940         }
3941         utilDate.formatFunctions[format] = Ext.functionFactory("return " + code.join('+'));
3942     },
3943
3944     // private
3945     createParser : (function() {
3946         var code = [
3947             "var dt, y, m, d, h, i, s, ms, o, z, zz, u, v,",
3948                 "def = Ext.Date.defaults,",
3949                 "results = String(input).match(Ext.Date.parseRegexes[{0}]);", // either null, or an array of matched strings
3950
3951             "if(results){",
3952                 "{1}",
3953
3954                 "if(u != null){", // i.e. unix time is defined
3955                     "v = new Date(u * 1000);", // give top priority to UNIX time
3956                 "}else{",
3957                     // create Date object representing midnight of the current day;
3958                     // this will provide us with our date defaults
3959                     // (note: clearTime() handles Daylight Saving Time automatically)
3960                     "dt = Ext.Date.clearTime(new Date);",
3961
3962                     // date calculations (note: these calculations create a dependency on Ext.Number.from())
3963                     "y = Ext.Number.from(y, Ext.Number.from(def.y, dt.getFullYear()));",
3964                     "m = Ext.Number.from(m, Ext.Number.from(def.m - 1, dt.getMonth()));",
3965                     "d = Ext.Number.from(d, Ext.Number.from(def.d, dt.getDate()));",
3966
3967                     // time calculations (note: these calculations create a dependency on Ext.Number.from())
3968                     "h  = Ext.Number.from(h, Ext.Number.from(def.h, dt.getHours()));",
3969                     "i  = Ext.Number.from(i, Ext.Number.from(def.i, dt.getMinutes()));",
3970                     "s  = Ext.Number.from(s, Ext.Number.from(def.s, dt.getSeconds()));",
3971                     "ms = Ext.Number.from(ms, Ext.Number.from(def.ms, dt.getMilliseconds()));",
3972
3973                     "if(z >= 0 && y >= 0){",
3974                         // both the year and zero-based day of year are defined and >= 0.
3975                         // these 2 values alone provide sufficient info to create a full date object
3976
3977                         // create Date object representing January 1st for the given year
3978                         // handle years < 100 appropriately
3979                         "v = Ext.Date.add(new Date(y < 100 ? 100 : y, 0, 1, h, i, s, ms), Ext.Date.YEAR, y < 100 ? y - 100 : 0);",
3980
3981                         // then add day of year, checking for Date "rollover" if necessary
3982                         "v = !strict? v : (strict === true && (z <= 364 || (Ext.Date.isLeapYear(v) && z <= 365))? Ext.Date.add(v, Ext.Date.DAY, z) : null);",
3983                     "}else if(strict === true && !Ext.Date.isValid(y, m + 1, d, h, i, s, ms)){", // check for Date "rollover"
3984                         "v = null;", // invalid date, so return null
3985                     "}else{",
3986                         // plain old Date object
3987                         // handle years < 100 properly
3988                         "v = Ext.Date.add(new Date(y < 100 ? 100 : y, m, d, h, i, s, ms), Ext.Date.YEAR, y < 100 ? y - 100 : 0);",
3989                     "}",
3990                 "}",
3991             "}",
3992
3993             "if(v){",
3994                 // favour UTC offset over GMT offset
3995                 "if(zz != null){",
3996                     // reset to UTC, then add offset
3997                     "v = Ext.Date.add(v, Ext.Date.SECOND, -v.getTimezoneOffset() * 60 - zz);",
3998                 "}else if(o){",
3999                     // reset to GMT, then add offset
4000                     "v = Ext.Date.add(v, Ext.Date.MINUTE, -v.getTimezoneOffset() + (sn == '+'? -1 : 1) * (hr * 60 + mn));",
4001                 "}",
4002             "}",
4003
4004             "return v;"
4005         ].join('\n');
4006
4007         return function(format) {
4008             var regexNum = utilDate.parseRegexes.length,
4009                 currentGroup = 1,
4010                 calc = [],
4011                 regex = [],
4012                 special = false,
4013                 ch = "";
4014
4015             for (var i = 0; i < format.length; ++i) {
4016                 ch = format.charAt(i);
4017                 if (!special && ch == "\\") {
4018                     special = true;
4019                 } else if (special) {
4020                     special = false;
4021                     regex.push(Ext.String.escape(ch));
4022                 } else {
4023                     var obj = utilDate.formatCodeToRegex(ch, currentGroup);
4024                     currentGroup += obj.g;
4025                     regex.push(obj.s);
4026                     if (obj.g && obj.c) {
4027                         calc.push(obj.c);
4028                     }
4029                 }
4030             }
4031
4032             utilDate.parseRegexes[regexNum] = new RegExp("^" + regex.join('') + "$", 'i');
4033             utilDate.parseFunctions[format] = Ext.functionFactory("input", "strict", xf(code, regexNum, calc.join('')));
4034         };
4035     })(),
4036
4037     // private
4038     parseCodes : {
4039         /*
4040          * Notes:
4041          * g = {Number} calculation group (0 or 1. only group 1 contributes to date calculations.)
4042          * c = {String} calculation method (required for group 1. null for group 0. {0} = currentGroup - position in regex result array)
4043          * s = {String} regex pattern. all matches are stored in results[], and are accessible by the calculation mapped to 'c'
4044          */
4045         d: {
4046             g:1,
4047             c:"d = parseInt(results[{0}], 10);\n",
4048             s:"(\\d{2})" // day of month with leading zeroes (01 - 31)
4049         },
4050         j: {
4051             g:1,
4052             c:"d = parseInt(results[{0}], 10);\n",
4053             s:"(\\d{1,2})" // day of month without leading zeroes (1 - 31)
4054         },
4055         D: function() {
4056             for (var a = [], i = 0; i < 7; a.push(utilDate.getShortDayName(i)), ++i); // get localised short day names
4057             return {
4058                 g:0,
4059                 c:null,
4060                 s:"(?:" + a.join("|") +")"
4061             };
4062         },
4063         l: function() {
4064             return {
4065                 g:0,
4066                 c:null,
4067                 s:"(?:" + utilDate.dayNames.join("|") + ")"
4068             };
4069         },
4070         N: {
4071             g:0,
4072             c:null,
4073             s:"[1-7]" // ISO-8601 day number (1 (monday) - 7 (sunday))
4074         },
4075         S: {
4076             g:0,
4077             c:null,
4078             s:"(?:st|nd|rd|th)"
4079         },
4080         w: {
4081             g:0,
4082             c:null,
4083             s:"[0-6]" // javascript day number (0 (sunday) - 6 (saturday))
4084         },
4085         z: {
4086             g:1,
4087             c:"z = parseInt(results[{0}], 10);\n",
4088             s:"(\\d{1,3})" // day of the year (0 - 364 (365 in leap years))
4089         },
4090         W: {
4091             g:0,
4092             c:null,
4093             s:"(?:\\d{2})" // ISO-8601 week number (with leading zero)
4094         },
4095         F: function() {
4096             return {
4097                 g:1,
4098                 c:"m = parseInt(Ext.Date.getMonthNumber(results[{0}]), 10);\n", // get localised month number
4099                 s:"(" + utilDate.monthNames.join("|") + ")"
4100             };
4101         },
4102         M: function() {
4103             for (var a = [], i = 0; i < 12; a.push(utilDate.getShortMonthName(i)), ++i); // get localised short month names
4104             return Ext.applyIf({
4105                 s:"(" + a.join("|") + ")"
4106             }, utilDate.formatCodeToRegex("F"));
4107         },
4108         m: {
4109             g:1,
4110             c:"m = parseInt(results[{0}], 10) - 1;\n",
4111             s:"(\\d{2})" // month number with leading zeros (01 - 12)
4112         },
4113         n: {
4114             g:1,
4115             c:"m = parseInt(results[{0}], 10) - 1;\n",
4116             s:"(\\d{1,2})" // month number without leading zeros (1 - 12)
4117         },
4118         t: {
4119             g:0,
4120             c:null,
4121             s:"(?:\\d{2})" // no. of days in the month (28 - 31)
4122         },
4123         L: {
4124             g:0,
4125             c:null,
4126             s:"(?:1|0)"
4127         },
4128         o: function() {
4129             return utilDate.formatCodeToRegex("Y");
4130         },
4131         Y: {
4132             g:1,
4133             c:"y = parseInt(results[{0}], 10);\n",
4134             s:"(\\d{4})" // 4-digit year
4135         },
4136         y: {
4137             g:1,
4138             c:"var ty = parseInt(results[{0}], 10);\n"
4139                 + "y = ty > Ext.Date.y2kYear ? 1900 + ty : 2000 + ty;\n", // 2-digit year
4140             s:"(\\d{1,2})"
4141         },
4142         /*
4143          * In the am/pm parsing routines, we allow both upper and lower case
4144          * even though it doesn't exactly match the spec. It gives much more flexibility
4145          * in being able to specify case insensitive regexes.
4146          */
4147         a: {
4148             g:1,
4149             c:"if (/(am)/i.test(results[{0}])) {\n"
4150                 + "if (!h || h == 12) { h = 0; }\n"
4151                 + "} else { if (!h || h < 12) { h = (h || 0) + 12; }}",
4152             s:"(am|pm|AM|PM)"
4153         },
4154         A: {
4155             g:1,
4156             c:"if (/(am)/i.test(results[{0}])) {\n"
4157                 + "if (!h || h == 12) { h = 0; }\n"
4158                 + "} else { if (!h || h < 12) { h = (h || 0) + 12; }}",
4159             s:"(AM|PM|am|pm)"
4160         },
4161         g: function() {
4162             return utilDate.formatCodeToRegex("G");
4163         },
4164         G: {
4165             g:1,
4166             c:"h = parseInt(results[{0}], 10);\n",
4167             s:"(\\d{1,2})" // 24-hr format of an hour without leading zeroes (0 - 23)
4168         },
4169         h: function() {
4170             return utilDate.formatCodeToRegex("H");
4171         },
4172         H: {
4173             g:1,
4174             c:"h = parseInt(results[{0}], 10);\n",
4175             s:"(\\d{2})" //  24-hr format of an hour with leading zeroes (00 - 23)
4176         },
4177         i: {
4178             g:1,
4179             c:"i = parseInt(results[{0}], 10);\n",
4180             s:"(\\d{2})" // minutes with leading zeros (00 - 59)
4181         },
4182         s: {
4183             g:1,
4184             c:"s = parseInt(results[{0}], 10);\n",
4185             s:"(\\d{2})" // seconds with leading zeros (00 - 59)
4186         },
4187         u: {
4188             g:1,
4189             c:"ms = results[{0}]; ms = parseInt(ms, 10)/Math.pow(10, ms.length - 3);\n",
4190             s:"(\\d+)" // decimal fraction of a second (minimum = 1 digit, maximum = unlimited)
4191         },
4192         O: {
4193             g:1,
4194             c:[
4195                 "o = results[{0}];",
4196                 "var sn = o.substring(0,1),", // get + / - sign
4197                     "hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60),", // get hours (performs minutes-to-hour conversion also, just in case)
4198                     "mn = o.substring(3,5) % 60;", // get minutes
4199                 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))? (sn + Ext.String.leftPad(hr, 2, '0') + Ext.String.leftPad(mn, 2, '0')) : null;\n" // -12hrs <= GMT offset <= 14hrs
4200             ].join("\n"),
4201             s: "([+\-]\\d{4})" // GMT offset in hrs and mins
4202         },
4203         P: {
4204             g:1,
4205             c:[
4206                 "o = results[{0}];",
4207                 "var sn = o.substring(0,1),", // get + / - sign
4208                     "hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60),", // get hours (performs minutes-to-hour conversion also, just in case)
4209                     "mn = o.substring(4,6) % 60;", // get minutes
4210                 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))? (sn + Ext.String.leftPad(hr, 2, '0') + Ext.String.leftPad(mn, 2, '0')) : null;\n" // -12hrs <= GMT offset <= 14hrs
4211             ].join("\n"),
4212             s: "([+\-]\\d{2}:\\d{2})" // GMT offset in hrs and mins (with colon separator)
4213         },
4214         T: {
4215             g:0,
4216             c:null,
4217             s:"[A-Z]{1,4}" // timezone abbrev. may be between 1 - 4 chars
4218         },
4219         Z: {
4220             g:1,
4221             c:"zz = results[{0}] * 1;\n" // -43200 <= UTC offset <= 50400
4222                   + "zz = (-43200 <= zz && zz <= 50400)? zz : null;\n",
4223             s:"([+\-]?\\d{1,5})" // leading '+' sign is optional for UTC offset
4224         },
4225         c: function() {
4226             var calc = [],
4227                 arr = [
4228                     utilDate.formatCodeToRegex("Y", 1), // year
4229                     utilDate.formatCodeToRegex("m", 2), // month
4230                     utilDate.formatCodeToRegex("d", 3), // day
4231                     utilDate.formatCodeToRegex("h", 4), // hour
4232                     utilDate.formatCodeToRegex("i", 5), // minute
4233                     utilDate.formatCodeToRegex("s", 6), // second
4234                     {c:"ms = results[7] || '0'; ms = parseInt(ms, 10)/Math.pow(10, ms.length - 3);\n"}, // decimal fraction of a second (minimum = 1 digit, maximum = unlimited)
4235                     {c:[ // allow either "Z" (i.e. UTC) or "-0530" or "+08:00" (i.e. UTC offset) timezone delimiters. assumes local timezone if no timezone is specified
4236                         "if(results[8]) {", // timezone specified
4237                             "if(results[8] == 'Z'){",
4238                                 "zz = 0;", // UTC
4239                             "}else if (results[8].indexOf(':') > -1){",
4240                                 utilDate.formatCodeToRegex("P", 8).c, // timezone offset with colon separator
4241                             "}else{",
4242                                 utilDate.formatCodeToRegex("O", 8).c, // timezone offset without colon separator
4243                             "}",
4244                         "}"
4245                     ].join('\n')}
4246                 ];
4247
4248             for (var i = 0, l = arr.length; i < l; ++i) {
4249                 calc.push(arr[i].c);
4250             }
4251
4252             return {
4253                 g:1,
4254                 c:calc.join(""),
4255                 s:[
4256                     arr[0].s, // year (required)
4257                     "(?:", "-", arr[1].s, // month (optional)
4258                         "(?:", "-", arr[2].s, // day (optional)
4259                             "(?:",
4260                                 "(?:T| )?", // time delimiter -- either a "T" or a single blank space
4261                                 arr[3].s, ":", arr[4].s,  // hour AND minute, delimited by a single colon (optional). MUST be preceded by either a "T" or a single blank space
4262                                 "(?::", arr[5].s, ")?", // seconds (optional)
4263                                 "(?:(?:\\.|,)(\\d+))?", // decimal fraction of a second (e.g. ",12345" or ".98765") (optional)
4264                                 "(Z|(?:[-+]\\d{2}(?::)?\\d{2}))?", // "Z" (UTC) or "-0530" (UTC offset without colon delimiter) or "+08:00" (UTC offset with colon delimiter) (optional)
4265                             ")?",
4266                         ")?",
4267                     ")?"
4268                 ].join("")
4269             };
4270         },
4271         U: {
4272             g:1,
4273             c:"u = parseInt(results[{0}], 10);\n",
4274             s:"(-?\\d+)" // leading minus sign indicates seconds before UNIX epoch
4275         }
4276     },
4277
4278     //Old Ext.Date prototype methods.
4279     // private
4280     dateFormat: function(date, format) {
4281         return utilDate.format(date, format);
4282     },
4283
4284     /**
4285      * Formats a date given the supplied format string.
4286      * @param {Date} date The date to format
4287      * @param {String} format The format string
4288      * @return {String} The formatted date
4289      */
4290     format: function(date, format) {
4291         if (utilDate.formatFunctions[format] == null) {
4292             utilDate.createFormat(format);
4293         }
4294         var result = utilDate.formatFunctions[format].call(date);
4295         return result + '';
4296     },
4297
4298     /**
4299      * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
4300      *
4301      * Note: The date string returned by the javascript Date object's toString() method varies
4302      * between browsers (e.g. FF vs IE) and system region settings (e.g. IE in Asia vs IE in America).
4303      * For a given date string e.g. "Thu Oct 25 2007 22:55:35 GMT+0800 (Malay Peninsula Standard Time)",
4304      * getTimezone() first tries to get the timezone abbreviation from between a pair of parentheses
4305      * (which may or may not be present), failing which it proceeds to get the timezone abbreviation
4306      * from the GMT offset portion of the date string.
4307      * @param {Date} date The date
4308      * @return {String} The abbreviated timezone name (e.g. 'CST', 'PDT', 'EDT', 'MPST' ...).
4309      */
4310     getTimezone : function(date) {
4311         // the following list shows the differences between date strings from different browsers on a WinXP SP2 machine from an Asian locale:
4312         //
4313         // Opera  : "Thu, 25 Oct 2007 22:53:45 GMT+0800" -- shortest (weirdest) date string of the lot
4314         // Safari : "Thu Oct 25 2007 22:55:35 GMT+0800 (Malay Peninsula Standard Time)" -- value in parentheses always gives the correct timezone (same as FF)
4315         // FF     : "Thu Oct 25 2007 22:55:35 GMT+0800 (Malay Peninsula Standard Time)" -- value in parentheses always gives the correct timezone
4316         // IE     : "Thu Oct 25 22:54:35 UTC+0800 2007" -- (Asian system setting) look for 3-4 letter timezone abbrev
4317         // IE     : "Thu Oct 25 17:06:37 PDT 2007" -- (American system setting) look for 3-4 letter timezone abbrev
4318         //
4319         // this crazy regex attempts to guess the correct timezone abbreviation despite these differences.
4320         // step 1: (?:\((.*)\) -- find timezone in parentheses
4321         // step 2: ([A-Z]{1,4})(?:[\-+][0-9]{4})?(?: -?\d+)?) -- if nothing was found in step 1, find timezone from timezone offset portion of date string
4322         // step 3: remove all non uppercase characters found in step 1 and 2
4323         return date.toString().replace(/^.* (?:\((.*)\)|([A-Z]{1,4})(?:[\-+][0-9]{4})?(?: -?\d+)?)$/, "$1$2").replace(/[^A-Z]/g, "");
4324     },
4325
4326     /**
4327      * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
4328      * @param {Date} date The date
4329      * @param {Boolean} colon (optional) true to separate the hours and minutes with a colon (defaults to false).
4330      * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600').
4331      */
4332     getGMTOffset : function(date, colon) {
4333         var offset = date.getTimezoneOffset();
4334         return (offset > 0 ? "-" : "+")
4335             + Ext.String.leftPad(Math.floor(Math.abs(offset) / 60), 2, "0")
4336             + (colon ? ":" : "")
4337             + Ext.String.leftPad(Math.abs(offset % 60), 2, "0");
4338     },
4339
4340     /**
4341      * Get the numeric day number of the year, adjusted for leap year.
4342      * @param {Date} date The date
4343      * @return {Number} 0 to 364 (365 in leap years).
4344      */
4345     getDayOfYear: function(date) {
4346         var num = 0,
4347             d = Ext.Date.clone(date),
4348             m = date.getMonth(),
4349             i;
4350
4351         for (i = 0, d.setDate(1), d.setMonth(0); i < m; d.setMonth(++i)) {
4352             num += utilDate.getDaysInMonth(d);
4353         }
4354         return num + date.getDate() - 1;
4355     },
4356
4357     /**
4358      * Get the numeric ISO-8601 week number of the year.
4359      * (equivalent to the format specifier 'W', but without a leading zero).
4360      * @param {Date} date The date
4361      * @return {Number} 1 to 53
4362      * @method
4363      */
4364     getWeekOfYear : (function() {
4365         // adapted from http://www.merlyn.demon.co.uk/weekcalc.htm
4366         var ms1d = 864e5, // milliseconds in a day
4367             ms7d = 7 * ms1d; // milliseconds in a week
4368
4369         return function(date) { // return a closure so constants get calculated only once
4370             var DC3 = Date.UTC(date.getFullYear(), date.getMonth(), date.getDate() + 3) / ms1d, // an Absolute Day Number
4371                 AWN = Math.floor(DC3 / 7), // an Absolute Week Number
4372                 Wyr = new Date(AWN * ms7d).getUTCFullYear();
4373
4374             return AWN - Math.floor(Date.UTC(Wyr, 0, 7) / ms7d) + 1;
4375         };
4376     })(),
4377
4378     /**
4379      * Checks if the current date falls within a leap year.
4380      * @param {Date} date The date
4381      * @return {Boolean} True if the current date falls within a leap year, false otherwise.
4382      */
4383     isLeapYear : function(date) {
4384         var year = date.getFullYear();
4385         return !!((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
4386     },
4387
4388     /**
4389      * Get the first day of the current month, adjusted for leap year.  The returned value
4390      * is the numeric day index within the week (0-6) which can be used in conjunction with
4391      * the {@link #monthNames} array to retrieve the textual day name.
4392      * Example:
4393      * <pre><code>
4394 var dt = new Date('1/10/2007'),
4395     firstDay = Ext.Date.getFirstDayOfMonth(dt);
4396 console.log(Ext.Date.dayNames[firstDay]); //output: 'Monday'
4397      * </code></pre>
4398      * @param {Date} date The date
4399      * @return {Number} The day number (0-6).
4400      */
4401     getFirstDayOfMonth : function(date) {
4402         var day = (date.getDay() - (date.getDate() - 1)) % 7;
4403         return (day < 0) ? (day + 7) : day;
4404     },
4405
4406     /**
4407      * Get the last day of the current month, adjusted for leap year.  The returned value
4408      * is the numeric day index within the week (0-6) which can be used in conjunction with
4409      * the {@link #monthNames} array to retrieve the textual day name.
4410      * Example:
4411      * <pre><code>
4412 var dt = new Date('1/10/2007'),
4413     lastDay = Ext.Date.getLastDayOfMonth(dt);
4414 console.log(Ext.Date.dayNames[lastDay]); //output: 'Wednesday'
4415      * </code></pre>
4416      * @param {Date} date The date
4417      * @return {Number} The day number (0-6).
4418      */
4419     getLastDayOfMonth : function(date) {
4420         return utilDate.getLastDateOfMonth(date).getDay();
4421     },
4422
4423
4424     /**
4425      * Get the date of the first day of the month in which this date resides.
4426      * @param {Date} date The date
4427      * @return {Date}
4428      */
4429     getFirstDateOfMonth : function(date) {
4430         return new Date(date.getFullYear(), date.getMonth(), 1);
4431     },
4432
4433     /**
4434      * Get the date of the last day of the month in which this date resides.
4435      * @param {Date} date The date
4436      * @return {Date}
4437      */
4438     getLastDateOfMonth : function(date) {
4439         return new Date(date.getFullYear(), date.getMonth(), utilDate.getDaysInMonth(date));
4440     },
4441
4442     /**
4443      * Get the number of days in the current month, adjusted for leap year.
4444      * @param {Date} date The date
4445      * @return {Number} The number of days in the month.
4446      * @method
4447      */
4448     getDaysInMonth: (function() {
4449         var daysInMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
4450
4451         return function(date) { // return a closure for efficiency
4452             var m = date.getMonth();
4453
4454             return m == 1 && utilDate.isLeapYear(date) ? 29 : daysInMonth[m];
4455         };
4456     })(),
4457
4458     /**
4459      * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
4460      * @param {Date} date The date
4461      * @return {String} 'st, 'nd', 'rd' or 'th'.
4462      */
4463     getSuffix : function(date) {
4464         switch (date.getDate()) {
4465             case 1:
4466             case 21:
4467             case 31:
4468                 return "st";
4469             case 2:
4470             case 22:
4471                 return "nd";
4472             case 3:
4473             case 23:
4474                 return "rd";
4475             default:
4476                 return "th";
4477         }
4478     },
4479
4480     /**
4481      * Creates and returns a new Date instance with the exact same date value as the called instance.
4482      * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
4483      * variable will also be changed.  When the intention is to create a new variable that will not
4484      * modify the original instance, you should create a clone.
4485      *
4486      * Example of correctly cloning a date:
4487      * <pre><code>
4488 //wrong way:
4489 var orig = new Date('10/1/2006');
4490 var copy = orig;
4491 copy.setDate(5);
4492 console.log(orig);  //returns 'Thu Oct 05 2006'!
4493
4494 //correct way:
4495 var orig = new Date('10/1/2006'),
4496     copy = Ext.Date.clone(orig);
4497 copy.setDate(5);
4498 console.log(orig);  //returns 'Thu Oct 01 2006'
4499      * </code></pre>
4500      * @param {Date} date The date
4501      * @return {Date} The new Date instance.
4502      */
4503     clone : function(date) {
4504         return new Date(date.getTime());
4505     },
4506
4507     /**
4508      * Checks if the current date is affected by Daylight Saving Time (DST).
4509      * @param {Date} date The date
4510      * @return {Boolean} True if the current date is affected by DST.
4511      */
4512     isDST : function(date) {
4513         // adapted from http://sencha.com/forum/showthread.php?p=247172#post247172
4514         // courtesy of @geoffrey.mcgill
4515         return new Date(date.getFullYear(), 0, 1).getTimezoneOffset() != date.getTimezoneOffset();
4516     },
4517
4518     /**
4519      * Attempts to clear all time information from this Date by setting the time to midnight of the same day,
4520      * automatically adjusting for Daylight Saving Time (DST) where applicable.
4521      * (note: DST timezone information for the browser's host operating system is assumed to be up-to-date)
4522      * @param {Date} date The date
4523      * @param {Boolean} clone true to create a clone of this date, clear the time and return it (defaults to false).
4524      * @return {Date} this or the clone.
4525      */
4526     clearTime : function(date, clone) {
4527         if (clone) {
4528             return Ext.Date.clearTime(Ext.Date.clone(date));
4529         }
4530
4531         // get current date before clearing time
4532         var d = date.getDate();
4533
4534         // clear time
4535         date.setHours(0);
4536         date.setMinutes(0);
4537         date.setSeconds(0);
4538         date.setMilliseconds(0);
4539
4540         if (date.getDate() != d) { // account for DST (i.e. day of month changed when setting hour = 0)
4541             // note: DST adjustments are assumed to occur in multiples of 1 hour (this is almost always the case)
4542             // refer to http://www.timeanddate.com/time/aboutdst.html for the (rare) exceptions to this rule
4543
4544             // increment hour until cloned date == current date
4545             for (var hr = 1, c = utilDate.add(date, Ext.Date.HOUR, hr); c.getDate() != d; hr++, c = utilDate.add(date, Ext.Date.HOUR, hr));
4546
4547             date.setDate(d);
4548             date.setHours(c.getHours());
4549         }
4550
4551         return date;
4552     },
4553
4554     /**
4555      * Provides a convenient method for performing basic date arithmetic. This method
4556      * does not modify the Date instance being called - it creates and returns
4557      * a new Date instance containing the resulting date value.
4558      *
4559      * Examples:
4560      * <pre><code>
4561 // Basic usage:
4562 var dt = Ext.Date.add(new Date('10/29/2006'), Ext.Date.DAY, 5);
4563 console.log(dt); //returns 'Fri Nov 03 2006 00:00:00'
4564
4565 // Negative values will be subtracted:
4566 var dt2 = Ext.Date.add(new Date('10/1/2006'), Ext.Date.DAY, -5);
4567 console.log(dt2); //returns 'Tue Sep 26 2006 00:00:00'
4568
4569      * </code></pre>
4570      *
4571      * @param {Date} date The date to modify
4572      * @param {String} interval A valid date interval enum value.
4573      * @param {Number} value The amount to add to the current date.
4574      * @return {Date} The new Date instance.
4575      */
4576     add : function(date, interval, value) {
4577         var d = Ext.Date.clone(date),
4578             Date = Ext.Date;
4579         if (!interval || value === 0) return d;
4580
4581         switch(interval.toLowerCase()) {
4582             case Ext.Date.MILLI:
4583                 d.setMilliseconds(d.getMilliseconds() + value);
4584                 break;
4585             case Ext.Date.SECOND:
4586                 d.setSeconds(d.getSeconds() + value);
4587                 break;
4588             case Ext.Date.MINUTE:
4589                 d.setMinutes(d.getMinutes() + value);
4590                 break;
4591             case Ext.Date.HOUR:
4592                 d.setHours(d.getHours() + value);
4593                 break;
4594             case Ext.Date.DAY:
4595                 d.setDate(d.getDate() + value);
4596                 break;
4597             case Ext.Date.MONTH:
4598                 var day = date.getDate();
4599                 if (day > 28) {
4600                     day = Math.min(day, Ext.Date.getLastDateOfMonth(Ext.Date.add(Ext.Date.getFirstDateOfMonth(date), 'mo', value)).getDate());
4601                 }
4602                 d.setDate(day);
4603                 d.setMonth(date.getMonth() + value);
4604                 break;
4605             case Ext.Date.YEAR:
4606                 d.setFullYear(date.getFullYear() + value);
4607                 break;
4608         }
4609         return d;
4610     },
4611
4612     /**
4613      * Checks if a date falls on or between the given start and end dates.
4614      * @param {Date} date The date to check
4615      * @param {Date} start Start date
4616      * @param {Date} end End date
4617      * @return {Boolean} true if this date falls on or between the given start and end dates.
4618      */
4619     between : function(date, start, end) {
4620         var t = date.getTime();
4621         return start.getTime() <= t && t <= end.getTime();
4622     },
4623
4624     //Maintains compatibility with old static and prototype window.Date methods.
4625     compat: function() {
4626         var nativeDate = window.Date,
4627             p, u,
4628             statics = ['useStrict', 'formatCodeToRegex', 'parseFunctions', 'parseRegexes', 'formatFunctions', 'y2kYear', 'MILLI', 'SECOND', 'MINUTE', 'HOUR', 'DAY', 'MONTH', 'YEAR', 'defaults', 'dayNames', 'monthNames', 'monthNumbers', 'getShortMonthName', 'getShortDayName', 'getMonthNumber', 'formatCodes', 'isValid', 'parseDate', 'getFormatCode', 'createFormat', 'createParser', 'parseCodes'],
4629             proto = ['dateFormat', 'format', 'getTimezone', 'getGMTOffset', 'getDayOfYear', 'getWeekOfYear', 'isLeapYear', 'getFirstDayOfMonth', 'getLastDayOfMonth', 'getDaysInMonth', 'getSuffix', 'clone', 'isDST', 'clearTime', 'add', 'between'];
4630
4631         //Append statics
4632         Ext.Array.forEach(statics, function(s) {
4633             nativeDate[s] = utilDate[s];
4634         });
4635
4636         //Append to prototype
4637         Ext.Array.forEach(proto, function(s) {
4638             nativeDate.prototype[s] = function() {
4639                 var args = Array.prototype.slice.call(arguments);
4640                 args.unshift(this);
4641                 return utilDate[s].apply(utilDate, args);
4642             };
4643         });
4644     }
4645 };
4646
4647 var utilDate = Ext.Date;
4648
4649 })();
4650
4651 /**
4652  * @author Jacky Nguyen <jacky@sencha.com>
4653  * @docauthor Jacky Nguyen <jacky@sencha.com>
4654  * @class Ext.Base
4655  *
4656  * The root of all classes created with {@link Ext#define}.
4657  *
4658  * Ext.Base is the building block of all Ext classes. All classes in Ext inherit from Ext.Base.
4659  * All prototype and static members of this class are inherited by all other classes.
4660  */
4661 (function(flexSetter) {
4662
4663 var Base = Ext.Base = function() {};
4664     Base.prototype = {
4665         $className: 'Ext.Base',
4666
4667         $class: Base,
4668
4669         /**
4670          * Get the reference to the current class from which this object was instantiated. Unlike {@link Ext.Base#statics},
4671          * `this.self` is scope-dependent and it's meant to be used for dynamic inheritance. See {@link Ext.Base#statics}
4672          * for a detailed comparison
4673          *
4674          *     Ext.define('My.Cat', {
4675          *         statics: {
4676          *             speciesName: 'Cat' // My.Cat.speciesName = 'Cat'
4677          *         },
4678          *
4679          *         constructor: function() {
4680          *             alert(this.self.speciesName); / dependent on 'this'
4681          *
4682          *             return this;
4683          *         },
4684          *
4685          *         clone: function() {
4686          *             return new this.self();
4687          *         }
4688          *     });
4689          *
4690          *
4691          *     Ext.define('My.SnowLeopard', {
4692          *         extend: 'My.Cat',
4693          *         statics: {
4694          *             speciesName: 'Snow Leopard'         // My.SnowLeopard.speciesName = 'Snow Leopard'
4695          *         }
4696          *     });
4697          *
4698          *     var cat = new My.Cat();                     // alerts 'Cat'
4699          *     var snowLeopard = new My.SnowLeopard();     // alerts 'Snow Leopard'
4700          *
4701          *     var clone = snowLeopard.clone();
4702          *     alert(Ext.getClassName(clone));             // alerts 'My.SnowLeopard'
4703          *
4704          * @type Ext.Class
4705          * @protected
4706          */
4707         self: Base,
4708
4709         // Default constructor, simply returns `this`
4710         constructor: function() {
4711             return this;
4712         },
4713
4714         //<feature classSystem.config>
4715         /**
4716          * Initialize configuration for this class. a typical example:
4717          *
4718          *     Ext.define('My.awesome.Class', {
4719          *         // The default config
4720          *         config: {
4721          *             name: 'Awesome',
4722          *             isAwesome: true
4723          *         },
4724          *
4725          *         constructor: function(config) {
4726          *             this.initConfig(config);
4727          *
4728          *             return this;
4729          *         }
4730          *     });
4731          *
4732          *     var awesome = new My.awesome.Class({
4733          *         name: 'Super Awesome'
4734          *     });
4735          *
4736          *     alert(awesome.getName()); // 'Super Awesome'
4737          *
4738          * @protected
4739          * @param {Object} config
4740          * @return {Object} mixins The mixin prototypes as key - value pairs
4741          */
4742         initConfig: function(config) {
4743             if (!this.$configInited) {
4744                 this.config = Ext.Object.merge({}, this.config || {}, config || {});
4745
4746                 this.applyConfig(this.config);
4747
4748                 this.$configInited = true;
4749             }
4750
4751             return this;
4752         },
4753
4754         /**
4755          * @private
4756          */
4757         setConfig: function(config) {
4758             this.applyConfig(config || {});
4759
4760             return this;
4761         },
4762
4763         /**
4764          * @private
4765          */
4766         applyConfig: flexSetter(function(name, value) {
4767             var setter = 'set' + Ext.String.capitalize(name);
4768
4769             if (typeof this[setter] === 'function') {
4770                 this[setter].call(this, value);
4771             }
4772
4773             return this;
4774         }),
4775         //</feature>
4776
4777         /**
4778          * Call the parent's overridden method. For example:
4779          *
4780          *     Ext.define('My.own.A', {
4781          *         constructor: function(test) {
4782          *             alert(test);
4783          *         }
4784          *     });
4785          *
4786          *     Ext.define('My.own.B', {
4787          *         extend: 'My.own.A',
4788          *
4789          *         constructor: function(test) {
4790          *             alert(test);
4791          *
4792          *             this.callParent([test + 1]);
4793          *         }
4794          *     });
4795          *
4796          *     Ext.define('My.own.C', {
4797          *         extend: 'My.own.B',
4798          *
4799          *         constructor: function() {
4800          *             alert("Going to call parent's overriden constructor...");
4801          *
4802          *             this.callParent(arguments);
4803          *         }
4804          *     });
4805          *
4806          *     var a = new My.own.A(1); // alerts '1'
4807          *     var b = new My.own.B(1); // alerts '1', then alerts '2'
4808          *     var c = new My.own.C(2); // alerts "Going to call parent's overriden constructor..."
4809          *                              // alerts '2', then alerts '3'
4810          *
4811          * @protected
4812          * @param {Array/Arguments} args The arguments, either an array or the `arguments` object
4813          * from the current method, for example: `this.callParent(arguments)`
4814          * @return {Object} Returns the result from the superclass' method
4815          */
4816         callParent: function(args) {
4817             var method = this.callParent.caller,
4818                 parentClass, methodName;
4819
4820             if (!method.$owner) {
4821                 if (!method.caller) {
4822                     Ext.Error.raise({
4823                         sourceClass: Ext.getClassName(this),
4824                         sourceMethod: "callParent",
4825                         msg: "Attempting to call a protected method from the public scope, which is not allowed"
4826                     });
4827                 }
4828
4829                 method = method.caller;
4830             }
4831
4832             parentClass = method.$owner.superclass;
4833             methodName = method.$name;
4834
4835             if (!(methodName in parentClass)) {
4836                 Ext.Error.raise({
4837                     sourceClass: Ext.getClassName(this),
4838                     sourceMethod: methodName,
4839                     msg: "this.callParent() was called but there's no such method (" + methodName +
4840                          ") found in the parent class (" + (Ext.getClassName(parentClass) || 'Object') + ")"
4841                  });
4842             }
4843
4844             return parentClass[methodName].apply(this, args || []);
4845         },
4846
4847
4848         /**
4849          * Get the reference to the class from which this object was instantiated. Note that unlike {@link Ext.Base#self},
4850          * `this.statics()` is scope-independent and it always returns the class from which it was called, regardless of what
4851          * `this` points to during run-time
4852          *
4853          *     Ext.define('My.Cat', {
4854          *         statics: {
4855          *             totalCreated: 0,
4856          *             speciesName: 'Cat' // My.Cat.speciesName = 'Cat'
4857          *         },
4858          *
4859          *         constructor: function() {
4860          *             var statics = this.statics();
4861          *
4862          *             alert(statics.speciesName);     // always equals to 'Cat' no matter what 'this' refers to
4863          *                                             // equivalent to: My.Cat.speciesName
4864          *
4865          *             alert(this.self.speciesName);   // dependent on 'this'
4866          *
4867          *             statics.totalCreated++;
4868          *
4869          *             return this;
4870          *         },
4871          *
4872          *         clone: function() {
4873          *             var cloned = new this.self;                      // dependent on 'this'
4874          *
4875          *             cloned.groupName = this.statics().speciesName;   // equivalent to: My.Cat.speciesName
4876          *
4877          *             return cloned;
4878          *         }
4879          *     });
4880          *
4881          *
4882          *     Ext.define('My.SnowLeopard', {
4883          *         extend: 'My.Cat',
4884          *
4885          *         statics: {
4886          *             speciesName: 'Snow Leopard'     // My.SnowLeopard.speciesName = 'Snow Leopard'
4887          *         },
4888          *
4889          *         constructor: function() {
4890          *             this.callParent();
4891          *         }
4892          *     });
4893          *
4894          *     var cat = new My.Cat();                 // alerts 'Cat', then alerts 'Cat'
4895          *
4896          *     var snowLeopard = new My.SnowLeopard(); // alerts 'Cat', then alerts 'Snow Leopard'
4897          *
4898          *     var clone = snowLeopard.clone();
4899          *     alert(Ext.getClassName(clone));         // alerts 'My.SnowLeopard'
4900          *     alert(clone.groupName);                 // alerts 'Cat'
4901          *
4902          *     alert(My.Cat.totalCreated);             // alerts 3
4903          *
4904          * @protected
4905          * @return {Ext.Class}
4906          */
4907         statics: function() {
4908             var method = this.statics.caller,
4909                 self = this.self;
4910
4911             if (!method) {
4912                 return self;
4913             }
4914
4915             return method.$owner;
4916         },
4917
4918         /**
4919          * Call the original method that was previously overridden with {@link Ext.Base#override}
4920          *
4921          *     Ext.define('My.Cat', {
4922          *         constructor: function() {
4923          *             alert("I'm a cat!");
4924          *
4925          *             return this;
4926          *         }
4927          *     });
4928          *
4929          *     My.Cat.override({
4930          *         constructor: function() {
4931          *             alert("I'm going to be a cat!");
4932          *
4933          *             var instance = this.callOverridden();
4934          *
4935          *             alert("Meeeeoooowwww");
4936          *
4937          *             return instance;
4938          *         }
4939          *     });
4940          *
4941          *     var kitty = new My.Cat(); // alerts "I'm going to be a cat!"
4942          *                               // alerts "I'm a cat!"
4943          *                               // alerts "Meeeeoooowwww"
4944          *
4945          * @param {Array/Arguments} args The arguments, either an array or the `arguments` object
4946          * @return {Object} Returns the result after calling the overridden method
4947          * @protected
4948          */
4949         callOverridden: function(args) {
4950             var method = this.callOverridden.caller;
4951
4952             if (!method.$owner) {
4953                 Ext.Error.raise({
4954                     sourceClass: Ext.getClassName(this),
4955                     sourceMethod: "callOverridden",
4956                     msg: "Attempting to call a protected method from the public scope, which is not allowed"
4957                 });
4958             }
4959
4960             if (!method.$previous) {
4961                 Ext.Error.raise({
4962                     sourceClass: Ext.getClassName(this),
4963                     sourceMethod: "callOverridden",
4964                     msg: "this.callOverridden was called in '" + method.$name +
4965                          "' but this method has never been overridden"
4966                  });
4967             }
4968
4969             return method.$previous.apply(this, args || []);
4970         },
4971
4972         destroy: function() {}
4973     };
4974
4975     // These static properties will be copied to every newly created class with {@link Ext#define}
4976     Ext.apply(Ext.Base, {
4977         /**
4978          * Create a new instance of this Class.
4979          *
4980          *     Ext.define('My.cool.Class', {
4981          *         ...
4982          *     });
4983          *
4984          *     My.cool.Class.create({
4985          *         someConfig: true
4986          *     });
4987          *
4988          * All parameters are passed to the constructor of the class.
4989          *
4990          * @return {Object} the created instance.
4991          * @static
4992          * @inheritable
4993          */
4994         create: function() {
4995             return Ext.create.apply(Ext, [this].concat(Array.prototype.slice.call(arguments, 0)));
4996         },
4997
4998         /**
4999          * @private
5000          * @inheritable
5001          */
5002         own: function(name, value) {
5003             if (typeof value == 'function') {
5004                 this.ownMethod(name, value);
5005             }
5006             else {
5007                 this.prototype[name] = value;
5008             }
5009         },
5010
5011         /**
5012          * @private
5013          * @inheritable
5014          */
5015         ownMethod: function(name, fn) {
5016             var originalFn;
5017
5018             if (typeof fn.$owner !== 'undefined' && fn !== Ext.emptyFn) {
5019                 originalFn = fn;
5020
5021                 fn = function() {
5022                     return originalFn.apply(this, arguments);
5023                 };
5024             }
5025
5026             var className;
5027             className = Ext.getClassName(this);
5028             if (className) {
5029                 fn.displayName = className + '#' + name;
5030             }
5031             fn.$owner = this;
5032             fn.$name = name;
5033
5034             this.prototype[name] = fn;
5035         },
5036
5037         /**
5038          * Add / override static properties of this class.
5039          *
5040          *     Ext.define('My.cool.Class', {
5041          *         ...
5042          *     });
5043          *
5044          *     My.cool.Class.addStatics({
5045          *         someProperty: 'someValue',      // My.cool.Class.someProperty = 'someValue'
5046          *         method1: function() { ... },    // My.cool.Class.method1 = function() { ... };
5047          *         method2: function() { ... }     // My.cool.Class.method2 = function() { ... };
5048          *     });
5049          *
5050          * @param {Object} members
5051          * @return {Ext.Base} this
5052          * @static
5053          * @inheritable
5054          */
5055         addStatics: function(members) {
5056             for (var name in members) {
5057                 if (members.hasOwnProperty(name)) {
5058                     this[name] = members[name];
5059                 }
5060             }
5061
5062             return this;
5063         },
5064
5065         /**
5066          * @private
5067          * @param {Object} members
5068          */
5069         addInheritableStatics: function(members) {
5070             var inheritableStatics,
5071                 hasInheritableStatics,
5072                 prototype = this.prototype,
5073                 name, member;
5074
5075             inheritableStatics = prototype.$inheritableStatics;
5076             hasInheritableStatics = prototype.$hasInheritableStatics;
5077
5078             if (!inheritableStatics) {
5079                 inheritableStatics = prototype.$inheritableStatics = [];
5080                 hasInheritableStatics = prototype.$hasInheritableStatics = {};
5081             }
5082
5083             var className = Ext.getClassName(this);
5084
5085             for (name in members) {
5086                 if (members.hasOwnProperty(name)) {
5087                     member = members[name];
5088                     if (typeof member == 'function') {
5089                         member.displayName = className + '.' + name;
5090                     }
5091                     this[name] = member;
5092
5093                     if (!hasInheritableStatics[name]) {
5094                         hasInheritableStatics[name] = true;
5095                         inheritableStatics.push(name);
5096                     }
5097                 }
5098             }
5099
5100             return this;
5101         },
5102
5103         /**
5104          * Add methods / properties to the prototype of this class.
5105          *
5106          *     Ext.define('My.awesome.Cat', {
5107          *         constructor: function() {
5108          *             ...
5109          *         }
5110          *     });
5111          *
5112          *      My.awesome.Cat.implement({
5113          *          meow: function() {
5114          *             alert('Meowww...');
5115          *          }
5116          *      });
5117          *
5118          *      var kitty = new My.awesome.Cat;
5119          *      kitty.meow();
5120          *
5121          * @param {Object} members
5122          * @static
5123          * @inheritable
5124          */
5125         implement: function(members) {
5126             var prototype = this.prototype,
5127                 enumerables = Ext.enumerables,
5128                 name, i, member;
5129             var className = Ext.getClassName(this);
5130             for (name in members) {
5131                 if (members.hasOwnProperty(name)) {
5132                     member = members[name];
5133
5134                     if (typeof member === 'function') {
5135                         member.$owner = this;
5136                         member.$name = name;
5137                         if (className) {
5138                             member.displayName = className + '#' + name;
5139                         }
5140                     }
5141
5142                     prototype[name] = member;
5143                 }
5144             }
5145
5146             if (enumerables) {
5147                 for (i = enumerables.length; i--;) {
5148                     name = enumerables[i];
5149
5150                     if (members.hasOwnProperty(name)) {
5151                         member = members[name];
5152                         member.$owner = this;
5153                         member.$name = name;
5154                         prototype[name] = member;
5155                     }
5156                 }
5157             }
5158         },
5159
5160         /**
5161          * Borrow another class' members to the prototype of this class.
5162          *
5163          *     Ext.define('Bank', {
5164          *         money: '$$$',
5165          *         printMoney: function() {
5166          *             alert('$$$$$$$');
5167          *         }
5168          *     });
5169          *
5170          *     Ext.define('Thief', {
5171          *         ...
5172          *     });
5173          *
5174          *     Thief.borrow(Bank, ['money', 'printMoney']);
5175          *
5176          *     var steve = new Thief();
5177          *
5178          *     alert(steve.money); // alerts '$$$'
5179          *     steve.printMoney(); // alerts '$$$$$$$'
5180          *
5181          * @param {Ext.Base} fromClass The class to borrow members from
5182          * @param {String/String[]} members The names of the members to borrow
5183          * @return {Ext.Base} this
5184          * @static
5185          * @inheritable
5186          */
5187         borrow: function(fromClass, members) {
5188             var fromPrototype = fromClass.prototype,
5189                 i, ln, member;
5190
5191             members = Ext.Array.from(members);
5192
5193             for (i = 0, ln = members.length; i < ln; i++) {
5194                 member = members[i];
5195
5196                 this.own(member, fromPrototype[member]);
5197             }
5198
5199             return this;
5200         },
5201
5202         /**
5203          * Override prototype members of this class. Overridden methods can be invoked via
5204          * {@link Ext.Base#callOverridden}
5205          *
5206          *     Ext.define('My.Cat', {
5207          *         constructor: function() {
5208          *             alert("I'm a cat!");
5209          *
5210          *             return this;
5211          *         }
5212          *     });
5213          *
5214          *     My.Cat.override({
5215          *         constructor: function() {
5216          *             alert("I'm going to be a cat!");
5217          *
5218          *             var instance = this.callOverridden();
5219          *
5220          *             alert("Meeeeoooowwww");
5221          *
5222          *             return instance;
5223          *         }
5224          *     });
5225          *
5226          *     var kitty = new My.Cat(); // alerts "I'm going to be a cat!"
5227          *                               // alerts "I'm a cat!"
5228          *                               // alerts "Meeeeoooowwww"
5229          *
5230          * @param {Object} members
5231          * @return {Ext.Base} this
5232          * @static
5233          * @inheritable
5234          */
5235         override: function(members) {
5236             var prototype = this.prototype,
5237                 enumerables = Ext.enumerables,
5238                 name, i, member, previous;
5239
5240             if (arguments.length === 2) {
5241                 name = members;
5242                 member = arguments[1];
5243
5244                 if (typeof member == 'function') {
5245                     if (typeof prototype[name] == 'function') {
5246                         previous = prototype[name];
5247                         member.$previous = previous;
5248                     }
5249
5250                     this.ownMethod(name, member);
5251                 }
5252                 else {
5253                     prototype[name] = member;
5254                 }
5255
5256                 return this;
5257             }
5258
5259             for (name in members) {
5260                 if (members.hasOwnProperty(name)) {
5261                     member = members[name];
5262
5263                     if (typeof member === 'function') {
5264                         if (typeof prototype[name] === 'function') {
5265                             previous = prototype[name];
5266                             member.$previous = previous;
5267                         }
5268
5269                         this.ownMethod(name, member);
5270                     }
5271                     else {
5272                         prototype[name] = member;
5273                     }
5274                 }
5275             }
5276
5277             if (enumerables) {
5278                 for (i = enumerables.length; i--;) {
5279                     name = enumerables[i];
5280
5281                     if (members.hasOwnProperty(name)) {
5282                         if (typeof prototype[name] !== 'undefined') {
5283                             previous = prototype[name];
5284                             members[name].$previous = previous;
5285                         }
5286
5287                         this.ownMethod(name, members[name]);
5288                     }
5289                 }
5290             }
5291
5292             return this;
5293         },
5294
5295         //<feature classSystem.mixins>
5296         /**
5297          * Used internally by the mixins pre-processor
5298          * @private
5299          * @inheritable
5300          */
5301         mixin: function(name, cls) {
5302             var mixin = cls.prototype,
5303                 my = this.prototype,
5304                 key, fn;
5305
5306             for (key in mixin) {
5307                 if (mixin.hasOwnProperty(key)) {
5308                     if (typeof my[key] === 'undefined' && key !== 'mixins' && key !== 'mixinId') {
5309                         if (typeof mixin[key] === 'function') {
5310                             fn = mixin[key];
5311
5312                             if (typeof fn.$owner === 'undefined') {
5313                                 this.ownMethod(key, fn);
5314                             }
5315                             else {
5316                                 my[key] = fn;
5317                             }
5318                         }
5319                         else {
5320                             my[key] = mixin[key];
5321                         }
5322                     }
5323                     //<feature classSystem.config>
5324                     else if (key === 'config' && my.config && mixin.config) {
5325                         Ext.Object.merge(my.config, mixin.config);
5326                     }
5327                     //</feature>
5328                 }
5329             }
5330
5331             if (typeof mixin.onClassMixedIn !== 'undefined') {
5332                 mixin.onClassMixedIn.call(cls, this);
5333             }
5334
5335             if (!my.hasOwnProperty('mixins')) {
5336                 if ('mixins' in my) {
5337                     my.mixins = Ext.Object.merge({}, my.mixins);
5338                 }
5339                 else {
5340                     my.mixins = {};
5341                 }
5342             }
5343
5344             my.mixins[name] = mixin;
5345         },
5346         //</feature>
5347
5348         /**
5349          * Get the current class' name in string format.
5350          *
5351          *     Ext.define('My.cool.Class', {
5352          *         constructor: function() {
5353          *             alert(this.self.getName()); // alerts 'My.cool.Class'
5354          *         }
5355          *     });
5356          *
5357          *     My.cool.Class.getName(); // 'My.cool.Class'
5358          *
5359          * @return {String} className
5360          * @static
5361          * @inheritable
5362          */
5363         getName: function() {
5364             return Ext.getClassName(this);
5365         },
5366
5367         /**
5368          * Create aliases for existing prototype methods. Example:
5369          *
5370          *     Ext.define('My.cool.Class', {
5371          *         method1: function() { ... },
5372          *         method2: function() { ... }
5373          *     });
5374          *
5375          *     var test = new My.cool.Class();
5376          *
5377          *     My.cool.Class.createAlias({
5378          *         method3: 'method1',
5379          *         method4: 'method2'
5380          *     });
5381          *
5382          *     test.method3(); // test.method1()
5383          *
5384          *     My.cool.Class.createAlias('method5', 'method3');
5385          *
5386          *     test.method5(); // test.method3() -> test.method1()
5387          *
5388          * @param {String/Object} alias The new method name, or an object to set multiple aliases. See
5389          * {@link Ext.Function#flexSetter flexSetter}
5390          * @param {String/Object} origin The original method name
5391          * @static
5392          * @inheritable
5393          * @method
5394          */
5395         createAlias: flexSetter(function(alias, origin) {
5396             this.prototype[alias] = function() {
5397                 return this[origin].apply(this, arguments);
5398             }
5399         })
5400     });
5401
5402 })(Ext.Function.flexSetter);
5403
5404 /**
5405  * @author Jacky Nguyen <jacky@sencha.com>
5406  * @docauthor Jacky Nguyen <jacky@sencha.com>
5407  * @class Ext.Class
5408  *
5409  * Handles class creation throughout the framework. This is a low level factory that is used by Ext.ClassManager and generally
5410  * should not be used directly. If you choose to use Ext.Class you will lose out on the namespace, aliasing and depency loading
5411  * features made available by Ext.ClassManager. The only time you would use Ext.Class directly is to create an anonymous class.
5412  *
5413  * If you wish to create a class you should use {@link Ext#define Ext.define} which aliases
5414  * {@link Ext.ClassManager#create Ext.ClassManager.create} to enable namespacing and dynamic dependency resolution.
5415  *
5416  * Ext.Class is the factory and **not** the superclass of everything. For the base class that **all** Ext classes inherit
5417  * from, see {@link Ext.Base}.
5418  */
5419 (function() {
5420
5421     var Class,
5422         Base = Ext.Base,
5423         baseStaticProperties = [],
5424         baseStaticProperty;
5425
5426     for (baseStaticProperty in Base) {
5427         if (Base.hasOwnProperty(baseStaticProperty)) {
5428             baseStaticProperties.push(baseStaticProperty);
5429         }
5430     }
5431
5432     /**
5433      * @method constructor
5434      * Creates new class.
5435      * @param {Object} classData An object represent the properties of this class
5436      * @param {Function} createdFn (Optional) The callback function to be executed when this class is fully created.
5437      * Note that the creation process can be asynchronous depending on the pre-processors used.
5438      * @return {Ext.Base} The newly created class
5439      */
5440     Ext.Class = Class = function(newClass, classData, onClassCreated) {
5441         if (typeof newClass != 'function') {
5442             onClassCreated = classData;
5443             classData = newClass;
5444             newClass = function() {
5445                 return this.constructor.apply(this, arguments);
5446             };
5447         }
5448
5449         if (!classData) {
5450             classData = {};
5451         }
5452
5453         var preprocessorStack = classData.preprocessors || Class.getDefaultPreprocessors(),
5454             registeredPreprocessors = Class.getPreprocessors(),
5455             index = 0,
5456             preprocessors = [],
5457             preprocessor, staticPropertyName, process, i, j, ln;
5458
5459         for (i = 0, ln = baseStaticProperties.length; i < ln; i++) {
5460             staticPropertyName = baseStaticProperties[i];
5461             newClass[staticPropertyName] = Base[staticPropertyName];
5462         }
5463
5464         delete classData.preprocessors;
5465
5466         for (j = 0, ln = preprocessorStack.length; j < ln; j++) {
5467             preprocessor = preprocessorStack[j];
5468
5469             if (typeof preprocessor == 'string') {
5470                 preprocessor = registeredPreprocessors[preprocessor];
5471
5472                 if (!preprocessor.always) {
5473                     if (classData.hasOwnProperty(preprocessor.name)) {
5474                         preprocessors.push(preprocessor.fn);
5475                     }
5476                 }
5477                 else {
5478                     preprocessors.push(preprocessor.fn);
5479                 }
5480             }
5481             else {
5482                 preprocessors.push(preprocessor);
5483             }
5484         }
5485
5486         classData.onClassCreated = onClassCreated || Ext.emptyFn;
5487
5488         classData.onBeforeClassCreated = function(cls, data) {
5489             onClassCreated = data.onClassCreated;
5490
5491             delete data.onBeforeClassCreated;
5492             delete data.onClassCreated;
5493
5494             cls.implement(data);
5495
5496             onClassCreated.call(cls, cls);
5497         };
5498
5499         process = function(cls, data) {
5500             preprocessor = preprocessors[index++];
5501
5502             if (!preprocessor) {
5503                 data.onBeforeClassCreated.apply(this, arguments);
5504                 return;
5505             }
5506
5507             if (preprocessor.call(this, cls, data, process) !== false) {
5508                 process.apply(this, arguments);
5509             }
5510         };
5511
5512         process.call(Class, newClass, classData);
5513
5514         return newClass;
5515     };
5516
5517     Ext.apply(Class, {
5518
5519         /** @private */
5520         preprocessors: {},
5521
5522         /**
5523          * Register a new pre-processor to be used during the class creation process
5524          *
5525          * @member Ext.Class
5526          * @param {String} name The pre-processor's name
5527          * @param {Function} fn The callback function to be executed. Typical format:
5528          *
5529          *     function(cls, data, fn) {
5530          *         // Your code here
5531          *
5532          *         // Execute this when the processing is finished.
5533          *         // Asynchronous processing is perfectly ok
5534          *         if (fn) {
5535          *             fn.call(this, cls, data);
5536          *         }
5537          *     });
5538          *
5539          * @param {Function} fn.cls The created class
5540          * @param {Object} fn.data The set of properties passed in {@link Ext.Class} constructor
5541          * @param {Function} fn.fn The callback function that **must** to be executed when this pre-processor finishes,
5542          * regardless of whether the processing is synchronous or aynchronous
5543          *
5544          * @return {Ext.Class} this
5545          * @static
5546          */
5547         registerPreprocessor: function(name, fn, always) {
5548             this.preprocessors[name] = {
5549                 name: name,
5550                 always: always ||  false,
5551                 fn: fn
5552             };
5553
5554             return this;
5555         },
5556
5557         /**
5558          * Retrieve a pre-processor callback function by its name, which has been registered before
5559          *
5560          * @param {String} name
5561          * @return {Function} preprocessor
5562          * @static
5563          */
5564         getPreprocessor: function(name) {
5565             return this.preprocessors[name];
5566         },
5567
5568         getPreprocessors: function() {
5569             return this.preprocessors;
5570         },
5571
5572         /**
5573          * Retrieve the array stack of default pre-processors
5574          *
5575          * @return {Function[]} defaultPreprocessors
5576          * @static
5577          */
5578         getDefaultPreprocessors: function() {
5579             return this.defaultPreprocessors || [];
5580         },
5581
5582         /**
5583          * Set the default array stack of default pre-processors
5584          *
5585          * @param {Function/Function[]} preprocessors
5586          * @return {Ext.Class} this
5587          * @static
5588          */
5589         setDefaultPreprocessors: function(preprocessors) {
5590             this.defaultPreprocessors = Ext.Array.from(preprocessors);
5591
5592             return this;
5593         },
5594
5595         /**
5596          * Inserts this pre-processor at a specific position in the stack, optionally relative to
5597          * any existing pre-processor. For example:
5598          *
5599          *     Ext.Class.registerPreprocessor('debug', function(cls, data, fn) {
5600          *         // Your code here
5601          *
5602          *         if (fn) {
5603          *             fn.call(this, cls, data);
5604          *         }
5605          *     }).setDefaultPreprocessorPosition('debug', 'last');
5606          *
5607          * @param {String} name The pre-processor name. Note that it needs to be registered with
5608          * {@link #registerPreprocessor registerPreprocessor} before this
5609          * @param {String} offset The insertion position. Four possible values are:
5610          * 'first', 'last', or: 'before', 'after' (relative to the name provided in the third argument)
5611          * @param {String} relativeName
5612          * @return {Ext.Class} this
5613          * @static
5614          */
5615         setDefaultPreprocessorPosition: function(name, offset, relativeName) {
5616             var defaultPreprocessors = this.defaultPreprocessors,
5617                 index;
5618
5619             if (typeof offset == 'string') {
5620                 if (offset === 'first') {
5621                     defaultPreprocessors.unshift(name);
5622
5623                     return this;
5624                 }
5625                 else if (offset === 'last') {
5626                     defaultPreprocessors.push(name);
5627
5628                     return this;
5629                 }
5630
5631                 offset = (offset === 'after') ? 1 : -1;
5632             }
5633
5634             index = Ext.Array.indexOf(defaultPreprocessors, relativeName);
5635
5636             if (index !== -1) {
5637                 Ext.Array.splice(defaultPreprocessors, Math.max(0, index + offset), 0, name);
5638             }
5639
5640             return this;
5641         }
5642     });
5643
5644     /**
5645      * @cfg {String} extend
5646      * The parent class that this class extends. For example:
5647      *
5648      *     Ext.define('Person', {
5649      *         say: function(text) { alert(text); }
5650      *     });
5651      *
5652      *     Ext.define('Developer', {
5653      *         extend: 'Person',
5654      *         say: function(text) { this.callParent(["print "+text]); }
5655      *     });
5656      */
5657     Class.registerPreprocessor('extend', function(cls, data) {
5658         var extend = data.extend,
5659             base = Ext.Base,
5660             basePrototype = base.prototype,
5661             prototype = function() {},
5662             parent, i, k, ln, staticName, parentStatics,
5663             parentPrototype, clsPrototype;
5664
5665         if (extend && extend !== Object) {
5666             parent = extend;
5667         }
5668         else {
5669             parent = base;
5670         }
5671
5672         parentPrototype = parent.prototype;
5673
5674         prototype.prototype = parentPrototype;
5675         clsPrototype = cls.prototype = new prototype();
5676
5677         if (!('$class' in parent)) {
5678             for (i in basePrototype) {
5679                 if (!parentPrototype[i]) {
5680                     parentPrototype[i] = basePrototype[i];
5681                 }
5682             }
5683         }
5684
5685         clsPrototype.self = cls;
5686
5687         cls.superclass = clsPrototype.superclass = parentPrototype;
5688
5689         delete data.extend;
5690
5691         //<feature classSystem.inheritableStatics>
5692         // Statics inheritance
5693         parentStatics = parentPrototype.$inheritableStatics;
5694
5695         if (parentStatics) {
5696             for (k = 0, ln = parentStatics.length; k < ln; k++) {
5697                 staticName = parentStatics[k];
5698
5699                 if (!cls.hasOwnProperty(staticName)) {
5700                     cls[staticName] = parent[staticName];
5701                 }
5702             }
5703         }
5704         //</feature>
5705
5706         //<feature classSystem.config>
5707         // Merge the parent class' config object without referencing it
5708         if (parentPrototype.config) {
5709             clsPrototype.config = Ext.Object.merge({}, parentPrototype.config);
5710         }
5711         else {
5712             clsPrototype.config = {};
5713         }
5714         //</feature>
5715
5716         //<feature classSystem.onClassExtended>
5717         if (clsPrototype.$onExtended) {
5718             clsPrototype.$onExtended.call(cls, cls, data);
5719         }
5720
5721         if (data.onClassExtended) {
5722             clsPrototype.$onExtended = data.onClassExtended;
5723             delete data.onClassExtended;
5724         }
5725         //</feature>
5726
5727     }, true);
5728
5729     //<feature classSystem.statics>
5730     /**
5731      * @cfg {Object} statics
5732      * List of static methods for this class. For example:
5733      *
5734      *     Ext.define('Computer', {
5735      *          statics: {
5736      *              factory: function(brand) {
5737      *                  // 'this' in static methods refer to the class itself
5738      *                  return new this(brand);
5739      *              }
5740      *          },
5741      *
5742      *          constructor: function() { ... }
5743      *     });
5744      *
5745      *     var dellComputer = Computer.factory('Dell');
5746      */
5747     Class.registerPreprocessor('statics', function(cls, data) {
5748         cls.addStatics(data.statics);
5749
5750         delete data.statics;
5751     });
5752     //</feature>
5753
5754     //<feature classSystem.inheritableStatics>
5755     /**
5756      * @cfg {Object} inheritableStatics
5757      * List of inheritable static methods for this class.
5758      * Otherwise just like {@link #statics} but subclasses inherit these methods.
5759      */
5760     Class.registerPreprocessor('inheritableStatics', function(cls, data) {
5761         cls.addInheritableStatics(data.inheritableStatics);
5762
5763         delete data.inheritableStatics;
5764     });
5765     //</feature>
5766
5767     //<feature classSystem.config>
5768     /**
5769      * @cfg {Object} config
5770      * List of configuration options with their default values, for which automatically
5771      * accessor methods are generated.  For example:
5772      *
5773      *     Ext.define('SmartPhone', {
5774      *          config: {
5775      *              hasTouchScreen: false,
5776      *              operatingSystem: 'Other',
5777      *              price: 500
5778      *          },
5779      *          constructor: function(cfg) {
5780      *              this.initConfig(cfg);
5781      *          }
5782      *     });
5783      *
5784      *     var iPhone = new SmartPhone({
5785      *          hasTouchScreen: true,
5786      *          operatingSystem: 'iOS'
5787      *     });
5788      *
5789      *     iPhone.getPrice(); // 500;
5790      *     iPhone.getOperatingSystem(); // 'iOS'
5791      *     iPhone.getHasTouchScreen(); // true;
5792      *     iPhone.hasTouchScreen(); // true
5793      */
5794     Class.registerPreprocessor('config', function(cls, data) {
5795         var prototype = cls.prototype;
5796
5797         Ext.Object.each(data.config, function(name) {
5798             var cName = name.charAt(0).toUpperCase() + name.substr(1),
5799                 pName = name,
5800                 apply = 'apply' + cName,
5801                 setter = 'set' + cName,
5802                 getter = 'get' + cName;
5803
5804             if (!(apply in prototype) && !data.hasOwnProperty(apply)) {
5805                 data[apply] = function(val) {
5806                     return val;
5807                 };
5808             }
5809
5810             if (!(setter in prototype) && !data.hasOwnProperty(setter)) {
5811                 data[setter] = function(val) {
5812                     var ret = this[apply].call(this, val, this[pName]);
5813
5814                     if (typeof ret != 'undefined') {
5815                         this[pName] = ret;
5816                     }
5817
5818                     return this;
5819                 };
5820             }
5821
5822             if (!(getter in prototype) && !data.hasOwnProperty(getter)) {
5823                 data[getter] = function() {
5824                     return this[pName];
5825                 };
5826             }
5827         });
5828
5829         Ext.Object.merge(prototype.config, data.config);
5830         delete data.config;
5831     });
5832     //</feature>
5833
5834     //<feature classSystem.mixins>
5835     /**
5836      * @cfg {Object} mixins
5837      * List of classes to mix into this class. For example:
5838      *
5839      *     Ext.define('CanSing', {
5840      *          sing: function() {
5841      *              alert("I'm on the highway to hell...")
5842      *          }
5843      *     });
5844      *
5845      *     Ext.define('Musician', {
5846      *          extend: 'Person',
5847      *
5848      *          mixins: {
5849      *              canSing: 'CanSing'
5850      *          }
5851      *     })
5852      */
5853     Class.registerPreprocessor('mixins', function(cls, data) {
5854         var mixins = data.mixins,
5855             name, mixin, i, ln;
5856
5857         delete data.mixins;
5858
5859         Ext.Function.interceptBefore(data, 'onClassCreated', function(cls) {
5860             if (mixins instanceof Array) {
5861                 for (i = 0,ln = mixins.length; i < ln; i++) {
5862                     mixin = mixins[i];
5863                     name = mixin.prototype.mixinId || mixin.$className;
5864
5865                     cls.mixin(name, mixin);
5866                 }
5867             }
5868             else {
5869                 for (name in mixins) {
5870                     if (mixins.hasOwnProperty(name)) {
5871                         cls.mixin(name, mixins[name]);
5872                     }
5873                 }
5874             }
5875         });
5876     });
5877
5878     //</feature>
5879
5880     Class.setDefaultPreprocessors([
5881         'extend'
5882         //<feature classSystem.statics>
5883         ,'statics'
5884         //</feature>
5885         //<feature classSystem.inheritableStatics>
5886         ,'inheritableStatics'
5887         //</feature>
5888         //<feature classSystem.config>
5889         ,'config'
5890         //</feature>
5891         //<feature classSystem.mixins>
5892         ,'mixins'
5893         //</feature>
5894     ]);
5895
5896     //<feature classSystem.backwardsCompatible>
5897     // Backwards compatible
5898     Ext.extend = function(subclass, superclass, members) {
5899         if (arguments.length === 2 && Ext.isObject(superclass)) {
5900             members = superclass;
5901             superclass = subclass;
5902             subclass = null;
5903         }
5904
5905         var cls;
5906
5907         if (!superclass) {
5908             Ext.Error.raise("Attempting to extend from a class which has not been loaded on the page.");
5909         }
5910
5911         members.extend = superclass;
5912         members.preprocessors = [
5913             'extend'
5914             //<feature classSystem.statics>
5915             ,'statics'
5916             //</feature>
5917             //<feature classSystem.inheritableStatics>
5918             ,'inheritableStatics'
5919             //</feature>
5920             //<feature classSystem.mixins>
5921             ,'mixins'
5922             //</feature>
5923             //<feature classSystem.config>
5924             ,'config'
5925             //</feature>
5926         ];
5927
5928         if (subclass) {
5929             cls = new Class(subclass, members);
5930         }
5931         else {
5932             cls = new Class(members);
5933         }
5934
5935         cls.prototype.override = function(o) {
5936             for (var m in o) {
5937                 if (o.hasOwnProperty(m)) {
5938                     this[m] = o[m];
5939                 }
5940             }
5941         };
5942
5943         return cls;
5944     };
5945     //</feature>
5946
5947 })();
5948
5949 /**
5950  * @author Jacky Nguyen <jacky@sencha.com>
5951  * @docauthor Jacky Nguyen <jacky@sencha.com>
5952  * @class Ext.ClassManager
5953  *
5954  * Ext.ClassManager manages all classes and handles mapping from string class name to
5955  * actual class objects throughout the whole framework. It is not generally accessed directly, rather through
5956  * these convenient shorthands:
5957  *
5958  * - {@link Ext#define Ext.define}
5959  * - {@link Ext#create Ext.create}
5960  * - {@link Ext#widget Ext.widget}
5961  * - {@link Ext#getClass Ext.getClass}
5962  * - {@link Ext#getClassName Ext.getClassName}
5963  *
5964  * # Basic syntax:
5965  *
5966  *     Ext.define(className, properties);
5967  *
5968  * in which `properties` is an object represent a collection of properties that apply to the class. See
5969  * {@link Ext.ClassManager#create} for more detailed instructions.
5970  *
5971  *     Ext.define('Person', {
5972  *          name: 'Unknown',
5973  *
5974  *          constructor: function(name) {
5975  *              if (name) {
5976  *                  this.name = name;
5977  *              }
5978  *
5979  *              return this;
5980  *          },
5981  *
5982  *          eat: function(foodType) {
5983  *              alert("I'm eating: " + foodType);
5984  *
5985  *              return this;
5986  *          }
5987  *     });
5988  *
5989  *     var aaron = new Person("Aaron");
5990  *     aaron.eat("Sandwich"); // alert("I'm eating: Sandwich");
5991  *
5992  * Ext.Class has a powerful set of extensible {@link Ext.Class#registerPreprocessor pre-processors} which takes care of
5993  * everything related to class creation, including but not limited to inheritance, mixins, configuration, statics, etc.
5994  *
5995  * # Inheritance:
5996  *
5997  *     Ext.define('Developer', {
5998  *          extend: 'Person',
5999  *
6000  *          constructor: function(name, isGeek) {
6001  *              this.isGeek = isGeek;
6002  *
6003  *              // Apply a method from the parent class' prototype
6004  *              this.callParent([name]);
6005  *
6006  *              return this;
6007  *
6008  *          },
6009  *
6010  *          code: function(language) {
6011  *              alert("I'm coding in: " + language);
6012  *
6013  *              this.eat("Bugs");
6014  *
6015  *              return this;
6016  *          }
6017  *     });
6018  *
6019  *     var jacky = new Developer("Jacky", true);
6020  *     jacky.code("JavaScript"); // alert("I'm coding in: JavaScript");
6021  *                               // alert("I'm eating: Bugs");
6022  *
6023  * See {@link Ext.Base#callParent} for more details on calling superclass' methods
6024  *
6025  * # Mixins:
6026  *
6027  *     Ext.define('CanPlayGuitar', {
6028  *          playGuitar: function() {
6029  *             alert("F#...G...D...A");
6030  *          }
6031  *     });
6032  *
6033  *     Ext.define('CanComposeSongs', {
6034  *          composeSongs: function() { ... }
6035  *     });
6036  *
6037  *     Ext.define('CanSing', {
6038  *          sing: function() {
6039  *              alert("I'm on the highway to hell...")
6040  *          }
6041  *     });
6042  *
6043  *     Ext.define('Musician', {
6044  *          extend: 'Person',
6045  *
6046  *          mixins: {
6047  *              canPlayGuitar: 'CanPlayGuitar',
6048  *              canComposeSongs: 'CanComposeSongs',
6049  *              canSing: 'CanSing'
6050  *          }
6051  *     })
6052  *
6053  *     Ext.define('CoolPerson', {
6054  *          extend: 'Person',
6055  *
6056  *          mixins: {
6057  *              canPlayGuitar: 'CanPlayGuitar',
6058  *              canSing: 'CanSing'
6059  *          },
6060  *
6061  *          sing: function() {
6062  *              alert("Ahem....");
6063  *
6064  *              this.mixins.canSing.sing.call(this);
6065  *
6066  *              alert("[Playing guitar at the same time...]");
6067  *
6068  *              this.playGuitar();
6069  *          }
6070  *     });
6071  *
6072  *     var me = new CoolPerson("Jacky");
6073  *
6074  *     me.sing(); // alert("Ahem...");
6075  *                // alert("I'm on the highway to hell...");
6076  *                // alert("[Playing guitar at the same time...]");
6077  *                // alert("F#...G...D...A");
6078  *
6079  * # Config:
6080  *
6081  *     Ext.define('SmartPhone', {
6082  *          config: {
6083  *              hasTouchScreen: false,
6084  *              operatingSystem: 'Other',
6085  *              price: 500
6086  *          },
6087  *
6088  *          isExpensive: false,
6089  *
6090  *          constructor: function(config) {
6091  *              this.initConfig(config);
6092  *
6093  *              return this;
6094  *          },
6095  *
6096  *          applyPrice: function(price) {
6097  *              this.isExpensive = (price > 500);
6098  *
6099  *              return price;
6100  *          },
6101  *
6102  *          applyOperatingSystem: function(operatingSystem) {
6103  *              if (!(/^(iOS|Android|BlackBerry)$/i).test(operatingSystem)) {
6104  *                  return 'Other';
6105  *              }
6106  *
6107  *              return operatingSystem;
6108  *          }
6109  *     });
6110  *
6111  *     var iPhone = new SmartPhone({
6112  *          hasTouchScreen: true,
6113  *          operatingSystem: 'iOS'
6114  *     });
6115  *
6116  *     iPhone.getPrice(); // 500;
6117  *     iPhone.getOperatingSystem(); // 'iOS'
6118  *     iPhone.getHasTouchScreen(); // true;
6119  *     iPhone.hasTouchScreen(); // true
6120  *
6121  *     iPhone.isExpensive; // false;
6122  *     iPhone.setPrice(600);
6123  *     iPhone.getPrice(); // 600
6124  *     iPhone.isExpensive; // true;
6125  *
6126  *     iPhone.setOperatingSystem('AlienOS');
6127  *     iPhone.getOperatingSystem(); // 'Other'
6128  *
6129  * # Statics:
6130  *
6131  *     Ext.define('Computer', {
6132  *          statics: {
6133  *              factory: function(brand) {
6134  *                 // 'this' in static methods refer to the class itself
6135  *                  return new this(brand);
6136  *              }
6137  *          },
6138  *
6139  *          constructor: function() { ... }
6140  *     });
6141  *
6142  *     var dellComputer = Computer.factory('Dell');
6143  *
6144  * Also see {@link Ext.Base#statics} and {@link Ext.Base#self} for more details on accessing
6145  * static properties within class methods
6146  *
6147  * @singleton
6148  */
6149 (function(Class, alias) {
6150
6151     var slice = Array.prototype.slice;
6152
6153     var Manager = Ext.ClassManager = {
6154
6155         /**
6156          * @property {Object} classes
6157          * All classes which were defined through the ClassManager. Keys are the
6158          * name of the classes and the values are references to the classes.
6159          * @private
6160          */
6161         classes: {},
6162
6163         /**
6164          * @private
6165          */
6166         existCache: {},
6167
6168         /**
6169          * @private
6170          */
6171         namespaceRewrites: [{
6172             from: 'Ext.',
6173             to: Ext
6174         }],
6175
6176         /**
6177          * @private
6178          */
6179         maps: {
6180             alternateToName: {},
6181             aliasToName: {},
6182             nameToAliases: {}
6183         },
6184
6185         /** @private */
6186         enableNamespaceParseCache: true,
6187
6188         /** @private */
6189         namespaceParseCache: {},
6190
6191         /** @private */
6192         instantiators: [],
6193
6194         /** @private */
6195         instantiationCounts: {},
6196
6197         /**
6198          * Checks if a class has already been created.
6199          *
6200          * @param {String} className
6201          * @return {Boolean} exist
6202          */
6203         isCreated: function(className) {
6204             var i, ln, part, root, parts;
6205
6206             if (typeof className !== 'string' || className.length < 1) {
6207                 Ext.Error.raise({
6208                     sourceClass: "Ext.ClassManager",
6209                     sourceMethod: "exist",
6210                     msg: "Invalid classname, must be a string and must not be empty"
6211                 });
6212             }
6213
6214             if (this.classes.hasOwnProperty(className) || this.existCache.hasOwnProperty(className)) {
6215                 return true;
6216             }
6217
6218             root = Ext.global;
6219             parts = this.parseNamespace(className);
6220
6221             for (i = 0, ln = parts.length; i < ln; i++) {
6222                 part = parts[i];
6223
6224                 if (typeof part !== 'string') {
6225                     root = part;
6226                 } else {
6227                     if (!root || !root[part]) {
6228                         return false;
6229                     }
6230
6231                     root = root[part];
6232                 }
6233             }
6234
6235             Ext.Loader.historyPush(className);
6236
6237             this.existCache[className] = true;
6238
6239             return true;
6240         },
6241
6242         /**
6243          * Supports namespace rewriting
6244          * @private
6245          */
6246         parseNamespace: function(namespace) {
6247             if (typeof namespace !== 'string') {
6248                 Ext.Error.raise({
6249                     sourceClass: "Ext.ClassManager",
6250                     sourceMethod: "parseNamespace",
6251                     msg: "Invalid namespace, must be a string"
6252                 });
6253             }
6254
6255             var cache = this.namespaceParseCache;
6256
6257             if (this.enableNamespaceParseCache) {
6258                 if (cache.hasOwnProperty(namespace)) {
6259                     return cache[namespace];
6260                 }
6261             }
6262
6263             var parts = [],
6264                 rewrites = this.namespaceRewrites,
6265                 rewrite, from, to, i, ln, root = Ext.global;
6266
6267             for (i = 0, ln = rewrites.length; i < ln; i++) {
6268                 rewrite = rewrites[i];
6269                 from = rewrite.from;
6270                 to = rewrite.to;
6271
6272                 if (namespace === from || namespace.substring(0, from.length) === from) {
6273                     namespace = namespace.substring(from.length);
6274
6275                     if (typeof to !== 'string') {
6276                         root = to;
6277                     } else {
6278                         parts = parts.concat(to.split('.'));
6279                     }
6280
6281                     break;
6282                 }
6283             }
6284
6285             parts.push(root);
6286
6287             parts = parts.concat(namespace.split('.'));
6288
6289             if (this.enableNamespaceParseCache) {
6290                 cache[namespace] = parts;
6291             }
6292
6293             return parts;
6294         },
6295
6296         /**
6297          * Creates a namespace and assign the `value` to the created object
6298          *
6299          *     Ext.ClassManager.setNamespace('MyCompany.pkg.Example', someObject);
6300          *
6301          *     alert(MyCompany.pkg.Example === someObject); // alerts true
6302          *
6303          * @param {String} name
6304          * @param {Object} value
6305          */
6306         setNamespace: function(name, value) {
6307             var root = Ext.global,
6308                 parts = this.parseNamespace(name),
6309                 ln = parts.length - 1,
6310                 leaf = parts[ln],
6311                 i, part;
6312
6313             for (i = 0; i < ln; i++) {
6314                 part = parts[i];
6315
6316                 if (typeof part !== 'string') {
6317                     root = part;
6318                 } else {
6319                     if (!root[part]) {
6320                         root[part] = {};
6321                     }
6322
6323                     root = root[part];
6324                 }
6325             }
6326
6327             root[leaf] = value;
6328
6329             return root[leaf];
6330         },
6331
6332         /**
6333          * The new Ext.ns, supports namespace rewriting
6334          * @private
6335          */
6336         createNamespaces: function() {
6337             var root = Ext.global,
6338                 parts, part, i, j, ln, subLn;
6339
6340             for (i = 0, ln = arguments.length; i < ln; i++) {
6341                 parts = this.parseNamespace(arguments[i]);
6342
6343                 for (j = 0, subLn = parts.length; j < subLn; j++) {
6344                     part = parts[j];
6345
6346                     if (typeof part !== 'string') {
6347                         root = part;
6348                     } else {
6349                         if (!root[part]) {
6350                             root[part] = {};
6351                         }
6352
6353                         root = root[part];
6354                     }
6355                 }
6356             }
6357
6358             return root;
6359         },
6360
6361         /**
6362          * Sets a name reference to a class.
6363          *
6364          * @param {String} name
6365          * @param {Object} value
6366          * @return {Ext.ClassManager} this
6367          */
6368         set: function(name, value) {
6369             var targetName = this.getName(value);
6370
6371             this.classes[name] = this.setNamespace(name, value);
6372
6373             if (targetName && targetName !== name) {
6374                 this.maps.alternateToName[name] = targetName;
6375             }
6376
6377             return this;
6378         },
6379
6380         /**
6381          * Retrieve a class by its name.
6382          *
6383          * @param {String} name
6384          * @return {Ext.Class} class
6385          */
6386         get: function(name) {
6387             if (this.classes.hasOwnProperty(name)) {
6388                 return this.classes[name];
6389             }
6390
6391             var root = Ext.global,
6392                 parts = this.parseNamespace(name),
6393                 part, i, ln;
6394
6395             for (i = 0, ln = parts.length; i < ln; i++) {
6396                 part = parts[i];
6397
6398                 if (typeof part !== 'string') {
6399                     root = part;
6400                 } else {
6401                     if (!root || !root[part]) {
6402                         return null;
6403                     }
6404
6405                     root = root[part];
6406                 }
6407             }
6408
6409             return root;
6410         },
6411
6412         /**
6413          * Register the alias for a class.
6414          *
6415          * @param {Ext.Class/String} cls a reference to a class or a className
6416          * @param {String} alias Alias to use when referring to this class
6417          */
6418         setAlias: function(cls, alias) {
6419             var aliasToNameMap = this.maps.aliasToName,
6420                 nameToAliasesMap = this.maps.nameToAliases,
6421                 className;
6422
6423             if (typeof cls === 'string') {
6424                 className = cls;
6425             } else {
6426                 className = this.getName(cls);
6427             }
6428
6429             if (alias && aliasToNameMap[alias] !== className) {
6430                 if (aliasToNameMap.hasOwnProperty(alias) && Ext.isDefined(Ext.global.console)) {
6431                     Ext.global.console.log("[Ext.ClassManager] Overriding existing alias: '" + alias + "' " +
6432                         "of: '" + aliasToNameMap[alias] + "' with: '" + className + "'. Be sure it's intentional.");
6433                 }
6434
6435                 aliasToNameMap[alias] = className;
6436             }
6437
6438             if (!nameToAliasesMap[className]) {
6439                 nameToAliasesMap[className] = [];
6440             }
6441
6442             if (alias) {
6443                 Ext.Array.include(nameToAliasesMap[className], alias);
6444             }
6445
6446             return this;
6447         },
6448
6449         /**
6450          * Get a reference to the class by its alias.
6451          *
6452          * @param {String} alias
6453          * @return {Ext.Class} class
6454          */
6455         getByAlias: function(alias) {
6456             return this.get(this.getNameByAlias(alias));
6457         },
6458
6459         /**
6460          * Get the name of a class by its alias.
6461          *
6462          * @param {String} alias
6463          * @return {String} className
6464          */
6465         getNameByAlias: function(alias) {
6466             return this.maps.aliasToName[alias] || '';
6467         },
6468
6469         /**
6470          * Get the name of a class by its alternate name.
6471          *
6472          * @param {String} alternate
6473          * @return {String} className
6474          */
6475         getNameByAlternate: function(alternate) {
6476             return this.maps.alternateToName[alternate] || '';
6477         },
6478
6479         /**
6480          * Get the aliases of a class by the class name
6481          *
6482          * @param {String} name
6483          * @return {String[]} aliases
6484          */
6485         getAliasesByName: function(name) {
6486             return this.maps.nameToAliases[name] || [];
6487         },
6488
6489         /**
6490          * Get the name of the class by its reference or its instance.
6491          *
6492          *     Ext.ClassManager.getName(Ext.Action); // returns "Ext.Action"
6493          *
6494          * {@link Ext#getClassName Ext.getClassName} is alias for {@link Ext.ClassManager#getName Ext.ClassManager.getName}.
6495          *
6496          * @param {Ext.Class/Object} object
6497          * @return {String} className
6498          */
6499         getName: function(object) {
6500             return object && object.$className || '';
6501         },
6502
6503         /**
6504          * Get the class of the provided object; returns null if it's not an instance
6505          * of any class created with Ext.define.
6506          *
6507          *     var component = new Ext.Component();
6508          *
6509          *     Ext.ClassManager.getClass(component); // returns Ext.Component
6510          *
6511          * {@link Ext#getClass Ext.getClass} is alias for {@link Ext.ClassManager#getClass Ext.ClassManager.getClass}.
6512          *
6513          * @param {Object} object
6514          * @return {Ext.Class} class
6515          */
6516         getClass: function(object) {
6517             return object && object.self || null;
6518         },
6519
6520         /**
6521          * Defines a class.
6522          *
6523          * {@link Ext#define Ext.define} and {@link Ext.ClassManager#create Ext.ClassManager.create} are almost aliases
6524          * of each other, with the only exception that Ext.define allows definition of {@link Ext.Class#override overrides}.
6525          * To avoid trouble, always use Ext.define.
6526          *
6527          *     Ext.define('My.awesome.Class', {
6528          *         someProperty: 'something',
6529          *         someMethod: function() { ... }
6530          *         ...
6531          *
6532          *     }, function() {
6533          *         alert('Created!');
6534          *         alert(this === My.awesome.Class); // alerts true
6535          *
6536          *         var myInstance = new this();
6537          *     });
6538          *
6539          * @param {String} className The class name to create in string dot-namespaced format, for example:
6540          * `My.very.awesome.Class`, `FeedViewer.plugin.CoolPager`. It is highly recommended to follow this simple convention:
6541          *
6542          * - The root and the class name are 'CamelCased'
6543          * - Everything else is lower-cased
6544          *
6545          * @param {Object} data The key-value pairs of properties to apply to this class. Property names can be of any valid
6546          * strings, except those in the reserved list below:
6547          *
6548          * - {@link Ext.Base#self self}
6549          * - {@link Ext.Class#alias alias}
6550          * - {@link Ext.Class#alternateClassName alternateClassName}
6551          * - {@link Ext.Class#config config}
6552          * - {@link Ext.Class#extend extend}
6553          * - {@link Ext.Class#inheritableStatics inheritableStatics}
6554          * - {@link Ext.Class#mixins mixins}
6555          * - {@link Ext.Class#override override} (only when using {@link Ext#define Ext.define})
6556          * - {@link Ext.Class#requires requires}
6557          * - {@link Ext.Class#singleton singleton}
6558          * - {@link Ext.Class#statics statics}
6559          * - {@link Ext.Class#uses uses}
6560          *
6561          * @param {Function} [createdFn] callback to execute after the class is created, the execution scope of which
6562          * (`this`) will be the newly created class itself.
6563          *
6564          * @return {Ext.Base}
6565          */
6566         create: function(className, data, createdFn) {
6567             var manager = this;
6568
6569             if (typeof className !== 'string') {
6570                 Ext.Error.raise({
6571                     sourceClass: "Ext",
6572                     sourceMethod: "define",
6573                     msg: "Invalid class name '" + className + "' specified, must be a non-empty string"
6574                 });
6575             }
6576
6577             data.$className = className;
6578
6579             return new Class(data, function() {
6580                 var postprocessorStack = data.postprocessors || manager.defaultPostprocessors,
6581                     registeredPostprocessors = manager.postprocessors,
6582                     index = 0,
6583                     postprocessors = [],
6584                     postprocessor, process, i, ln;
6585
6586                 delete data.postprocessors;
6587
6588                 for (i = 0, ln = postprocessorStack.length; i < ln; i++) {
6589                     postprocessor = postprocessorStack[i];
6590
6591                     if (typeof postprocessor === 'string') {
6592                         postprocessor = registeredPostprocessors[postprocessor];
6593
6594                         if (!postprocessor.always) {
6595                             if (data[postprocessor.name] !== undefined) {
6596                                 postprocessors.push(postprocessor.fn);
6597                             }
6598                         }
6599                         else {
6600                             postprocessors.push(postprocessor.fn);
6601                         }
6602                     }
6603                     else {
6604                         postprocessors.push(postprocessor);
6605                     }
6606                 }
6607
6608                 process = function(clsName, cls, clsData) {
6609                     postprocessor = postprocessors[index++];
6610
6611                     if (!postprocessor) {
6612                         manager.set(className, cls);
6613
6614                         Ext.Loader.historyPush(className);
6615
6616                         if (createdFn) {
6617                             createdFn.call(cls, cls);
6618                         }
6619
6620                         return;
6621                     }
6622
6623                     if (postprocessor.call(this, clsName, cls, clsData, process) !== false) {
6624                         process.apply(this, arguments);
6625                     }
6626                 };
6627
6628                 process.call(manager, className, this, data);
6629             });
6630         },
6631
6632         /**
6633          * Instantiate a class by its alias.
6634          *
6635          * If {@link Ext.Loader} is {@link Ext.Loader#setConfig enabled} and the class has not been defined yet, it will
6636          * attempt to load the class via synchronous loading.
6637          *
6638          *     var window = Ext.ClassManager.instantiateByAlias('widget.window', { width: 600, height: 800, ... });
6639          *
6640          * {@link Ext#createByAlias Ext.createByAlias} is alias for {@link Ext.ClassManager#instantiateByAlias Ext.ClassManager.instantiateByAlias}.
6641          *
6642          * @param {String} alias
6643          * @param {Object...} args Additional arguments after the alias will be passed to the
6644          * class constructor.
6645          * @return {Object} instance
6646          */
6647         instantiateByAlias: function() {
6648             var alias = arguments[0],
6649                 args = slice.call(arguments),
6650                 className = this.getNameByAlias(alias);
6651
6652             if (!className) {
6653                 className = this.maps.aliasToName[alias];
6654
6655                 if (!className) {
6656                     Ext.Error.raise({
6657                         sourceClass: "Ext",
6658                         sourceMethod: "createByAlias",
6659                         msg: "Cannot create an instance of unrecognized alias: " + alias
6660                     });
6661                 }
6662
6663                 if (Ext.global.console) {
6664                     Ext.global.console.warn("[Ext.Loader] Synchronously loading '" + className + "'; consider adding " +
6665                          "Ext.require('" + alias + "') above Ext.onReady");
6666                 }
6667
6668                 Ext.syncRequire(className);
6669             }
6670
6671             args[0] = className;
6672
6673             return this.instantiate.apply(this, args);
6674         },
6675
6676         /**
6677          * Instantiate a class by either full name, alias or alternate name.
6678          *
6679          * If {@link Ext.Loader} is {@link Ext.Loader#setConfig enabled} and the class has not been defined yet, it will
6680          * attempt to load the class via synchronous loading.
6681          *
6682          * For example, all these three lines return the same result:
6683          *
6684          *     // alias
6685          *     var window = Ext.ClassManager.instantiate('widget.window', { width: 600, height: 800, ... });
6686          *
6687          *     // alternate name
6688          *     var window = Ext.ClassManager.instantiate('Ext.Window', { width: 600, height: 800, ... });
6689          *
6690          *     // full class name
6691          *     var window = Ext.ClassManager.instantiate('Ext.window.Window', { width: 600, height: 800, ... });
6692          *
6693          * {@link Ext#create Ext.create} is alias for {@link Ext.ClassManager#instantiate Ext.ClassManager.instantiate}.
6694          *
6695          * @param {String} name
6696          * @param {Object...} args Additional arguments after the name will be passed to the class' constructor.
6697          * @return {Object} instance
6698          */
6699         instantiate: function() {
6700             var name = arguments[0],
6701                 args = slice.call(arguments, 1),
6702                 alias = name,
6703                 possibleName, cls;
6704
6705             if (typeof name !== 'function') {
6706                 if ((typeof name !== 'string' || name.length < 1)) {
6707                     Ext.Error.raise({
6708                         sourceClass: "Ext",
6709                         sourceMethod: "create",
6710                         msg: "Invalid class name or alias '" + name + "' specified, must be a non-empty string"
6711                     });
6712                 }
6713
6714                 cls = this.get(name);
6715             }
6716             else {
6717                 cls = name;
6718             }
6719
6720             // No record of this class name, it's possibly an alias, so look it up
6721             if (!cls) {
6722                 possibleName = this.getNameByAlias(name);
6723
6724                 if (possibleName) {
6725                     name = possibleName;
6726
6727                     cls = this.get(name);
6728                 }
6729             }
6730
6731             // Still no record of this class name, it's possibly an alternate name, so look it up
6732             if (!cls) {
6733                 possibleName = this.getNameByAlternate(name);
6734
6735                 if (possibleName) {
6736                     name = possibleName;
6737
6738                     cls = this.get(name);
6739                 }
6740             }
6741
6742             // Still not existing at this point, try to load it via synchronous mode as the last resort
6743             if (!cls) {
6744                 if (Ext.global.console) {
6745                     Ext.global.console.warn("[Ext.Loader] Synchronously loading '" + name + "'; consider adding " +
6746                          "Ext.require('" + ((possibleName) ? alias : name) + "') above Ext.onReady");
6747                 }
6748
6749                 Ext.syncRequire(name);
6750
6751                 cls = this.get(name);
6752             }
6753
6754             if (!cls) {
6755                 Ext.Error.raise({
6756                     sourceClass: "Ext",
6757                     sourceMethod: "create",
6758                     msg: "Cannot create an instance of unrecognized class name / alias: " + alias
6759                 });
6760             }
6761
6762             if (typeof cls !== 'function') {
6763                 Ext.Error.raise({
6764                     sourceClass: "Ext",
6765                     sourceMethod: "create",
6766                     msg: "'" + name + "' is a singleton and cannot be instantiated"
6767                 });
6768             }
6769
6770             if (!this.instantiationCounts[name]) {
6771                 this.instantiationCounts[name] = 0;
6772             }
6773
6774             this.instantiationCounts[name]++;
6775
6776             return this.getInstantiator(args.length)(cls, args);
6777         },
6778
6779         /**
6780          * @private
6781          * @param name
6782          * @param args
6783          */
6784         dynInstantiate: function(name, args) {
6785             args = Ext.Array.from(args, true);
6786             args.unshift(name);
6787
6788             return this.instantiate.apply(this, args);
6789         },
6790
6791         /**
6792          * @private
6793          * @param length
6794          */
6795         getInstantiator: function(length) {
6796             if (!this.instantiators[length]) {
6797                 var i = length,
6798                     args = [];
6799
6800                 for (i = 0; i < length; i++) {
6801                     args.push('a['+i+']');
6802                 }
6803
6804                 this.instantiators[length] = new Function('c', 'a', 'return new c('+args.join(',')+')');
6805             }
6806
6807             return this.instantiators[length];
6808         },
6809
6810         /**
6811          * @private
6812          */
6813         postprocessors: {},
6814
6815         /**
6816          * @private
6817          */
6818         defaultPostprocessors: [],
6819
6820         /**
6821          * Register a post-processor function.
6822          *
6823          * @param {String} name
6824          * @param {Function} postprocessor
6825          */
6826         registerPostprocessor: function(name, fn, always) {
6827             this.postprocessors[name] = {
6828                 name: name,
6829                 always: always ||  false,
6830                 fn: fn
6831             };
6832
6833             return this;
6834         },
6835
6836         /**
6837          * Set the default post processors array stack which are applied to every class.
6838          *
6839          * @param {String/String[]} The name of a registered post processor or an array of registered names.
6840          * @return {Ext.ClassManager} this
6841          */
6842         setDefaultPostprocessors: function(postprocessors) {
6843             this.defaultPostprocessors = Ext.Array.from(postprocessors);
6844
6845             return this;
6846         },
6847
6848         /**
6849          * Insert this post-processor at a specific position in the stack, optionally relative to
6850          * any existing post-processor
6851          *
6852          * @param {String} name The post-processor name. Note that it needs to be registered with
6853          * {@link Ext.ClassManager#registerPostprocessor} before this
6854          * @param {String} offset The insertion position. Four possible values are:
6855          * 'first', 'last', or: 'before', 'after' (relative to the name provided in the third argument)
6856          * @param {String} relativeName
6857          * @return {Ext.ClassManager} this
6858          */
6859         setDefaultPostprocessorPosition: function(name, offset, relativeName) {
6860             var defaultPostprocessors = this.defaultPostprocessors,
6861                 index;
6862
6863             if (typeof offset === 'string') {
6864                 if (offset === 'first') {
6865                     defaultPostprocessors.unshift(name);
6866
6867                     return this;
6868                 }
6869                 else if (offset === 'last') {
6870                     defaultPostprocessors.push(name);
6871
6872                     return this;
6873                 }
6874
6875                 offset = (offset === 'after') ? 1 : -1;
6876             }
6877
6878             index = Ext.Array.indexOf(defaultPostprocessors, relativeName);
6879
6880             if (index !== -1) {
6881                 Ext.Array.splice(defaultPostprocessors, Math.max(0, index + offset), 0, name);
6882             }
6883
6884             return this;
6885         },
6886
6887         /**
6888          * Converts a string expression to an array of matching class names. An expression can either refers to class aliases
6889          * or class names. Expressions support wildcards:
6890          *
6891          *     // returns ['Ext.window.Window']
6892          *     var window = Ext.ClassManager.getNamesByExpression('widget.window');
6893          *
6894          *     // returns ['widget.panel', 'widget.window', ...]
6895          *     var allWidgets = Ext.ClassManager.getNamesByExpression('widget.*');
6896          *
6897          *     // returns ['Ext.data.Store', 'Ext.data.ArrayProxy', ...]
6898          *     var allData = Ext.ClassManager.getNamesByExpression('Ext.data.*');
6899          *
6900          * @param {String} expression
6901          * @return {String[]} classNames
6902          */
6903         getNamesByExpression: function(expression) {
6904             var nameToAliasesMap = this.maps.nameToAliases,
6905                 names = [],
6906                 name, alias, aliases, possibleName, regex, i, ln;
6907
6908             if (typeof expression !== 'string' || expression.length < 1) {
6909                 Ext.Error.raise({
6910                     sourceClass: "Ext.ClassManager",
6911                     sourceMethod: "getNamesByExpression",
6912                     msg: "Expression " + expression + " is invalid, must be a non-empty string"
6913                 });
6914             }
6915
6916             if (expression.indexOf('*') !== -1) {
6917                 expression = expression.replace(/\*/g, '(.*?)');
6918                 regex = new RegExp('^' + expression + '$');
6919
6920                 for (name in nameToAliasesMap) {
6921                     if (nameToAliasesMap.hasOwnProperty(name)) {
6922                         aliases = nameToAliasesMap[name];
6923
6924                         if (name.search(regex) !== -1) {
6925                             names.push(name);
6926                         }
6927                         else {
6928                             for (i = 0, ln = aliases.length; i < ln; i++) {
6929                                 alias = aliases[i];
6930
6931                                 if (alias.search(regex) !== -1) {
6932                                     names.push(name);
6933                                     break;
6934                                 }
6935                             }
6936                         }
6937                     }
6938                 }
6939
6940             } else {
6941                 possibleName = this.getNameByAlias(expression);
6942
6943                 if (possibleName) {
6944                     names.push(possibleName);
6945                 } else {
6946                     possibleName = this.getNameByAlternate(expression);
6947
6948                     if (possibleName) {
6949                         names.push(possibleName);
6950                     } else {
6951                         names.push(expression);
6952                     }
6953                 }
6954             }
6955
6956             return names;
6957         }
6958     };
6959
6960     var defaultPostprocessors = Manager.defaultPostprocessors;
6961     //<feature classSystem.alias>
6962
6963     /**
6964      * @cfg {String[]} alias
6965      * @member Ext.Class
6966      * List of short aliases for class names.  Most useful for defining xtypes for widgets:
6967      *
6968      *     Ext.define('MyApp.CoolPanel', {
6969      *         extend: 'Ext.panel.Panel',
6970      *         alias: ['widget.coolpanel'],
6971      *         title: 'Yeah!'
6972      *     });
6973      *
6974      *     // Using Ext.create
6975      *     Ext.widget('widget.coolpanel');
6976      *     // Using the shorthand for widgets and in xtypes
6977      *     Ext.widget('panel', {
6978      *         items: [
6979      *             {xtype: 'coolpanel', html: 'Foo'},
6980      *             {xtype: 'coolpanel', html: 'Bar'}
6981      *         ]
6982      *     });
6983      */
6984     Manager.registerPostprocessor('alias', function(name, cls, data) {
6985         var aliases = data.alias,
6986             i, ln;
6987
6988         delete data.alias;
6989
6990         for (i = 0, ln = aliases.length; i < ln; i++) {
6991             alias = aliases[i];
6992
6993             this.setAlias(cls, alias);
6994         }
6995     });
6996
6997     /**
6998      * @cfg {Boolean} singleton
6999      * @member Ext.Class
7000      * When set to true, the class will be instantiated as singleton.  For example:
7001      *
7002      *     Ext.define('Logger', {
7003      *         singleton: true,
7004      *         log: function(msg) {
7005      *             console.log(msg);
7006      *         }
7007      *     });
7008      *
7009      *     Logger.log('Hello');
7010      */
7011     Manager.registerPostprocessor('singleton', function(name, cls, data, fn) {
7012         fn.call(this, name, new cls(), data);
7013         return false;
7014     });
7015
7016     /**
7017      * @cfg {String/String[]} alternateClassName
7018      * @member Ext.Class
7019      * Defines alternate names for this class.  For example:
7020      *
7021      *     Ext.define('Developer', {
7022      *         alternateClassName: ['Coder', 'Hacker'],
7023      *         code: function(msg) {
7024      *             alert('Typing... ' + msg);
7025      *         }
7026      *     });
7027      *
7028      *     var joe = Ext.create('Developer');
7029      *     joe.code('stackoverflow');
7030      *
7031      *     var rms = Ext.create('Hacker');
7032      *     rms.code('hack hack');
7033      */
7034     Manager.registerPostprocessor('alternateClassName', function(name, cls, data) {
7035         var alternates = data.alternateClassName,
7036             i, ln, alternate;
7037
7038         if (!(alternates instanceof Array)) {
7039             alternates = [alternates];
7040         }
7041
7042         for (i = 0, ln = alternates.length; i < ln; i++) {
7043             alternate = alternates[i];
7044
7045             if (typeof alternate !== 'string') {
7046                 Ext.Error.raise({
7047                     sourceClass: "Ext",
7048                     sourceMethod: "define",
7049                     msg: "Invalid alternate of: '" + alternate + "' for class: '" + name + "'; must be a valid string"
7050                 });
7051             }
7052
7053             this.set(alternate, cls);
7054         }
7055     });
7056
7057     Manager.setDefaultPostprocessors(['alias', 'singleton', 'alternateClassName']);
7058
7059     Ext.apply(Ext, {
7060         /**
7061          * @method
7062          * @member Ext
7063          * @alias Ext.ClassManager#instantiate
7064          */
7065         create: alias(Manager, 'instantiate'),
7066
7067         /**
7068          * @private
7069          * API to be stablized
7070          *
7071          * @param {Object} item
7072          * @param {String} namespace
7073          */
7074         factory: function(item, namespace) {
7075             if (item instanceof Array) {
7076                 var i, ln;
7077
7078                 for (i = 0, ln = item.length; i < ln; i++) {
7079                     item[i] = Ext.factory(item[i], namespace);
7080                 }
7081
7082                 return item;
7083             }
7084
7085             var isString = (typeof item === 'string');
7086
7087             if (isString || (item instanceof Object && item.constructor === Object)) {
7088                 var name, config = {};
7089
7090                 if (isString) {
7091                     name = item;
7092                 }
7093                 else {
7094                     name = item.className;
7095                     config = item;
7096                     delete config.className;
7097                 }
7098
7099                 if (namespace !== undefined && name.indexOf(namespace) === -1) {
7100                     name = namespace + '.' + Ext.String.capitalize(name);
7101                 }
7102
7103                 return Ext.create(name, config);
7104             }
7105
7106             if (typeof item === 'function') {
7107                 return Ext.create(item);
7108             }
7109
7110             return item;
7111         },
7112
7113         /**
7114          * Convenient shorthand to create a widget by its xtype, also see {@link Ext.ClassManager#instantiateByAlias}
7115          *
7116          *     var button = Ext.widget('button'); // Equivalent to Ext.create('widget.button')
7117          *     var panel = Ext.widget('panel'); // Equivalent to Ext.create('widget.panel')
7118          *
7119          * @method
7120          * @member Ext
7121          * @param {String} name  xtype of the widget to create.
7122          * @param {Object...} args  arguments for the widget constructor.
7123          * @return {Object} widget instance
7124          */
7125         widget: function(name) {
7126             var args = slice.call(arguments);
7127             args[0] = 'widget.' + name;
7128
7129             return Manager.instantiateByAlias.apply(Manager, args);
7130         },
7131
7132         /**
7133          * @method
7134          * @member Ext
7135          * @alias Ext.ClassManager#instantiateByAlias
7136          */
7137         createByAlias: alias(Manager, 'instantiateByAlias'),
7138
7139         /**
7140          * @cfg {String} override
7141          * @member Ext.Class
7142          * 
7143          * Defines an override applied to a class. Note that **overrides can only be created using
7144          * {@link Ext#define}.** {@link Ext.ClassManager#create} only creates classes.
7145          * 
7146          * To define an override, include the override property. The content of an override is
7147          * aggregated with the specified class in order to extend or modify that class. This can be
7148          * as simple as setting default property values or it can extend and/or replace methods.
7149          * This can also extend the statics of the class.
7150          *
7151          * One use for an override is to break a large class into manageable pieces.
7152          *
7153          *      // File: /src/app/Panel.js
7154          *
7155          *      Ext.define('My.app.Panel', {
7156          *          extend: 'Ext.panel.Panel',
7157          *          requires: [
7158          *              'My.app.PanelPart2',
7159          *              'My.app.PanelPart3'
7160          *          ]
7161          *
7162          *          constructor: function (config) {
7163          *              this.callSuper(arguments); // calls Ext.panel.Panel's constructor
7164          *              //...
7165          *          },
7166          *
7167          *          statics: {
7168          *              method: function () {
7169          *                  return 'abc';
7170          *              }
7171          *          }
7172          *      });
7173          *
7174          *      // File: /src/app/PanelPart2.js
7175          *      Ext.define('My.app.PanelPart2', {
7176          *          override: 'My.app.Panel',
7177          *
7178          *          constructor: function (config) {
7179          *              this.callSuper(arguments); // calls My.app.Panel's constructor
7180          *              //...
7181          *          }
7182          *      });
7183          *
7184          * Another use of overrides is to provide optional parts of classes that can be
7185          * independently required. In this case, the class may even be unaware of the
7186          * override altogether.
7187          *
7188          *      Ext.define('My.ux.CoolTip', {
7189          *          override: 'Ext.tip.ToolTip',
7190          *
7191          *          constructor: function (config) {
7192          *              this.callSuper(arguments); // calls Ext.tip.ToolTip's constructor
7193          *              //...
7194          *          }
7195          *      });
7196          *
7197          * The above override can now be required as normal.
7198          *
7199          *      Ext.define('My.app.App', {
7200          *          requires: [
7201          *              'My.ux.CoolTip'
7202          *          ]
7203          *      });
7204          *
7205          * Overrides can also contain statics:
7206          *
7207          *      Ext.define('My.app.BarMod', {
7208          *          override: 'Ext.foo.Bar',
7209          *
7210          *          statics: {
7211          *              method: function (x) {
7212          *                  return this.callSuper([x * 2]); // call Ext.foo.Bar.method
7213          *              }
7214          *          }
7215          *      });
7216          *
7217          * IMPORTANT: An override is only included in a build if the class it overrides is
7218          * required. Otherwise, the override, like the target class, is not included.
7219          */
7220         
7221         /**
7222          * @method
7223          *
7224          * @member Ext
7225          * @alias Ext.ClassManager#create
7226          */
7227         define: function (className, data, createdFn) {
7228             if (!data.override) {
7229                 return Manager.create.apply(Manager, arguments);
7230             }
7231
7232             var requires = data.requires,
7233                 uses = data.uses,
7234                 overrideName = className;
7235
7236             className = data.override;
7237
7238             // hoist any 'requires' or 'uses' from the body onto the faux class:
7239             data = Ext.apply({}, data);
7240             delete data.requires;
7241             delete data.uses;
7242             delete data.override;
7243
7244             // make sure className is in the requires list:
7245             if (typeof requires == 'string') {
7246                 requires = [ className, requires ];
7247             } else if (requires) {
7248                 requires = requires.slice(0);
7249                 requires.unshift(className);
7250             } else {
7251                 requires = [ className ];
7252             }
7253
7254 // TODO - we need to rework this to allow the override to not require the target class
7255 //  and rather 'wait' for it in such a way that if the target class is not in the build,
7256 //  neither are any of its overrides.
7257 //
7258 //  Also, this should process the overrides for a class ASAP (ideally before any derived
7259 //  classes) if the target class 'requires' the overrides. Without some special handling, the
7260 //  overrides so required will be processed before the class and have to be bufferred even
7261 //  in a build.
7262 //
7263 // TODO - we should probably support the "config" processor on an override (to config new
7264 //  functionaliy like Aria) and maybe inheritableStatics (although static is now supported
7265 //  by callSuper). If inheritableStatics causes those statics to be included on derived class
7266 //  constructors, that probably means "no" to this since an override can come after other
7267 //  classes extend the target.
7268             return Manager.create(overrideName, {
7269                     requires: requires,
7270                     uses: uses,
7271                     isPartial: true,
7272                     constructor: function () {
7273                         throw new Error("Cannot create override '" + overrideName + "'");
7274                     }
7275                 }, function () {
7276                     var cls = Manager.get(className);
7277                     if (cls.override) { // if (normal class)
7278                         cls.override(data);
7279                     } else { // else (singleton)
7280                         cls.self.override(data);
7281                     }
7282
7283                     if (createdFn) {
7284                         // called once the override is applied and with the context of the
7285                         // overridden class (the override itself is a meaningless, name-only
7286                         // thing).
7287                         createdFn.call(cls);
7288                     }
7289                 });
7290         },
7291
7292         /**
7293          * @method
7294          * @member Ext
7295          * @alias Ext.ClassManager#getName
7296          */
7297         getClassName: alias(Manager, 'getName'),
7298
7299         /**
7300          * Returns the displayName property or className or object.
7301          * When all else fails, returns "Anonymous".
7302          * @param {Object} object
7303          * @return {String}
7304          */
7305         getDisplayName: function(object) {
7306             if (object.displayName) {
7307                 return object.displayName;
7308             }
7309
7310             if (object.$name && object.$class) {
7311                 return Ext.getClassName(object.$class) + '#' + object.$name;
7312             }
7313
7314             if (object.$className) {
7315                 return object.$className;
7316             }
7317
7318             return 'Anonymous';
7319         },
7320
7321         /**
7322          * @method
7323          * @member Ext
7324          * @alias Ext.ClassManager#getClass
7325          */
7326         getClass: alias(Manager, 'getClass'),
7327
7328         /**
7329          * Creates namespaces to be used for scoping variables and classes so that they are not global.
7330          * Specifying the last node of a namespace implicitly creates all other nodes. Usage:
7331          *
7332          *     Ext.namespace('Company', 'Company.data');
7333          *
7334          *     // equivalent and preferable to the above syntax
7335          *     Ext.namespace('Company.data');
7336          *
7337          *     Company.Widget = function() { ... };
7338          *
7339          *     Company.data.CustomStore = function(config) { ... };
7340          *
7341          * @method
7342          * @member Ext
7343          * @param {String} namespace1
7344          * @param {String} namespace2
7345          * @param {String} etc
7346          * @return {Object} The namespace object. (If multiple arguments are passed, this will be the last namespace created)
7347          */
7348         namespace: alias(Manager, 'createNamespaces')
7349     });
7350
7351     /**
7352      * Old name for {@link Ext#widget}.
7353      * @deprecated 4.0.0 Use {@link Ext#widget} instead.
7354      * @method
7355      * @member Ext
7356      * @alias Ext#widget
7357      */
7358     Ext.createWidget = Ext.widget;
7359
7360     /**
7361      * Convenient alias for {@link Ext#namespace Ext.namespace}
7362      * @method
7363      * @member Ext
7364      * @alias Ext#namespace
7365      */
7366     Ext.ns = Ext.namespace;
7367
7368     Class.registerPreprocessor('className', function(cls, data) {
7369         if (data.$className) {
7370             cls.$className = data.$className;
7371             cls.displayName = cls.$className;
7372         }
7373     }, true);
7374
7375     Class.setDefaultPreprocessorPosition('className', 'first');
7376
7377     Class.registerPreprocessor('xtype', function(cls, data) {
7378         var xtypes = Ext.Array.from(data.xtype),
7379             widgetPrefix = 'widget.',
7380             aliases = Ext.Array.from(data.alias),
7381             i, ln, xtype;
7382
7383         data.xtype = xtypes[0];
7384         data.xtypes = xtypes;
7385
7386         aliases = data.alias = Ext.Array.from(data.alias);
7387
7388         for (i = 0,ln = xtypes.length; i < ln; i++) {
7389             xtype = xtypes[i];
7390
7391             if (typeof xtype != 'string' || xtype.length < 1) {
7392                 throw new Error("[Ext.define] Invalid xtype of: '" + xtype + "' for class: '" + name + "'; must be a valid non-empty string");
7393             }
7394
7395             aliases.push(widgetPrefix + xtype);
7396         }
7397
7398         data.alias = aliases;
7399     });
7400
7401     Class.setDefaultPreprocessorPosition('xtype', 'last');
7402
7403     Class.registerPreprocessor('alias', function(cls, data) {
7404         var aliases = Ext.Array.from(data.alias),
7405             xtypes = Ext.Array.from(data.xtypes),
7406             widgetPrefix = 'widget.',
7407             widgetPrefixLength = widgetPrefix.length,
7408             i, ln, alias, xtype;
7409
7410         for (i = 0, ln = aliases.length; i < ln; i++) {
7411             alias = aliases[i];
7412
7413             if (typeof alias != 'string') {
7414                 throw new Error("[Ext.define] Invalid alias of: '" + alias + "' for class: '" + name + "'; must be a valid string");
7415             }
7416
7417             if (alias.substring(0, widgetPrefixLength) === widgetPrefix) {
7418                 xtype = alias.substring(widgetPrefixLength);
7419                 Ext.Array.include(xtypes, xtype);
7420
7421                 if (!cls.xtype) {
7422                     cls.xtype = data.xtype = xtype;
7423                 }
7424             }
7425         }
7426
7427         data.alias = aliases;
7428         data.xtypes = xtypes;
7429     });
7430
7431     Class.setDefaultPreprocessorPosition('alias', 'last');
7432
7433 })(Ext.Class, Ext.Function.alias);
7434
7435 /**
7436  * @class Ext.Loader
7437  * @singleton
7438  * @author Jacky Nguyen <jacky@sencha.com>
7439  * @docauthor Jacky Nguyen <jacky@sencha.com>
7440  *
7441  * Ext.Loader is the heart of the new dynamic dependency loading capability in Ext JS 4+. It is most commonly used
7442  * via the {@link Ext#require} shorthand. Ext.Loader supports both asynchronous and synchronous loading
7443  * approaches, and leverage their advantages for the best development flow. We'll discuss about the pros and cons
7444  * of each approach:
7445  *
7446  * # Asynchronous Loading
7447  *
7448  * - Advantages:
7449  *       + Cross-domain
7450  *       + No web server needed: you can run the application via the file system protocol
7451  *     (i.e: `file://path/to/your/index.html`)
7452  *       + Best possible debugging experience: error messages come with the exact file name and line number
7453  *
7454  * - Disadvantages:
7455  *       + Dependencies need to be specified before-hand
7456  *
7457  * ### Method 1: Explicitly include what you need:
7458  *
7459  *     // Syntax
7460  *     Ext.require({String/Array} expressions);
7461  *
7462  *     // Example: Single alias
7463  *     Ext.require('widget.window');
7464  *
7465  *     // Example: Single class name
7466  *     Ext.require('Ext.window.Window');
7467  *
7468  *     // Example: Multiple aliases / class names mix
7469  *     Ext.require(['widget.window', 'layout.border', 'Ext.data.Connection']);
7470  *
7471  *     // Wildcards
7472  *     Ext.require(['widget.*', 'layout.*', 'Ext.data.*']);
7473  *
7474  * ### Method 2: Explicitly exclude what you don't need:
7475  *
7476  *     // Syntax: Note that it must be in this chaining format.
7477  *     Ext.exclude({String/Array} expressions)
7478  *        .require({String/Array} expressions);
7479  *
7480  *     // Include everything except Ext.data.*
7481  *     Ext.exclude('Ext.data.*').require('*'); 
7482  *
7483  *     // Include all widgets except widget.checkbox*,
7484  *     // which will match widget.checkbox, widget.checkboxfield, widget.checkboxgroup, etc.
7485  *     Ext.exclude('widget.checkbox*').require('widget.*');
7486  *
7487  * # Synchronous Loading on Demand
7488  *
7489  * - Advantages:
7490  *       + There's no need to specify dependencies before-hand, which is always the convenience of including
7491  *     ext-all.js before
7492  *
7493  * - Disadvantages:
7494  *       + Not as good debugging experience since file name won't be shown (except in Firebug at the moment)
7495  *       + Must be from the same domain due to XHR restriction
7496  *       + Need a web server, same reason as above
7497  *
7498  * There's one simple rule to follow: Instantiate everything with Ext.create instead of the `new` keyword
7499  *
7500  *     Ext.create('widget.window', { ... }); // Instead of new Ext.window.Window({...});
7501  *
7502  *     Ext.create('Ext.window.Window', {}); // Same as above, using full class name instead of alias
7503  *
7504  *     Ext.widget('window', {}); // Same as above, all you need is the traditional `xtype`
7505  *
7506  * Behind the scene, {@link Ext.ClassManager} will automatically check whether the given class name / alias has already
7507  * existed on the page. If it's not, Ext.Loader will immediately switch itself to synchronous mode and automatic load
7508  * the given class and all its dependencies.
7509  *
7510  * # Hybrid Loading - The Best of Both Worlds
7511  *
7512  * It has all the advantages combined from asynchronous and synchronous loading. The development flow is simple:
7513  *
7514  * ### Step 1: Start writing your application using synchronous approach.
7515  *
7516  * Ext.Loader will automatically fetch all dependencies on demand as they're needed during run-time. For example:
7517  *
7518  *     Ext.onReady(function(){
7519  *         var window = Ext.createWidget('window', {
7520  *             width: 500,
7521  *             height: 300,
7522  *             layout: {
7523  *                 type: 'border',
7524  *                 padding: 5
7525  *             },
7526  *             title: 'Hello Dialog',
7527  *             items: [{
7528  *                 title: 'Navigation',
7529  *                 collapsible: true,
7530  *                 region: 'west',
7531  *                 width: 200,
7532  *                 html: 'Hello',
7533  *                 split: true
7534  *             }, {
7535  *                 title: 'TabPanel',
7536  *                 region: 'center'
7537  *             }]
7538  *         });
7539  *
7540  *         window.show();
7541  *     })
7542  *
7543  * ### Step 2: Along the way, when you need better debugging ability, watch the console for warnings like these:
7544  *
7545  *     [Ext.Loader] Synchronously loading 'Ext.window.Window'; consider adding Ext.require('Ext.window.Window') before your application's code ClassManager.js:432
7546  *     [Ext.Loader] Synchronously loading 'Ext.layout.container.Border'; consider adding Ext.require('Ext.layout.container.Border') before your application's code
7547  *
7548  * Simply copy and paste the suggested code above `Ext.onReady`, e.g.:
7549  *
7550  *     Ext.require('Ext.window.Window');
7551  *     Ext.require('Ext.layout.container.Border');
7552  *
7553  *     Ext.onReady(...);
7554  *
7555  * Everything should now load via asynchronous mode.
7556  *
7557  * # Deployment
7558  *
7559  * It's important to note that dynamic loading should only be used during development on your local machines.
7560  * During production, all dependencies should be combined into one single JavaScript file. Ext.Loader makes
7561  * the whole process of transitioning from / to between development / maintenance and production as easy as
7562  * possible. Internally {@link Ext.Loader#history Ext.Loader.history} maintains the list of all dependencies
7563  * your application needs in the exact loading sequence. It's as simple as concatenating all files in this
7564  * array into one, then include it on top of your application.
7565  *
7566  * This process will be automated with Sencha Command, to be released and documented towards Ext JS 4 Final.
7567  */
7568 (function(Manager, Class, flexSetter, alias) {
7569
7570     var
7571         dependencyProperties = ['extend', 'mixins', 'requires'],
7572         Loader;
7573
7574     Loader = Ext.Loader = {
7575         /**
7576          * @private
7577          */
7578         documentHead: typeof document !== 'undefined' && (document.head || document.getElementsByTagName('head')[0]),
7579
7580         /**
7581          * Flag indicating whether there are still files being loaded
7582          * @private
7583          */
7584         isLoading: false,
7585
7586         /**
7587          * Maintain the queue for all dependencies. Each item in the array is an object of the format:
7588          * {
7589          *      requires: [...], // The required classes for this queue item
7590          *      callback: function() { ... } // The function to execute when all classes specified in requires exist
7591          * }
7592          * @private
7593          */
7594         queue: [],
7595
7596         /**
7597          * Maintain the list of files that have already been handled so that they never get double-loaded
7598          * @private
7599          */
7600         isFileLoaded: {},
7601
7602         /**
7603          * Maintain the list of listeners to execute when all required scripts are fully loaded
7604          * @private
7605          */
7606         readyListeners: [],
7607
7608         /**
7609          * Contains optional dependencies to be loaded last
7610          * @private
7611          */
7612         optionalRequires: [],
7613
7614         /**
7615          * Map of fully qualified class names to an array of dependent classes.
7616          * @private
7617          */
7618         requiresMap: {},
7619
7620         /**
7621          * @private
7622          */
7623         numPendingFiles: 0,
7624
7625         /**
7626          * @private
7627          */
7628         numLoadedFiles: 0,
7629
7630         /** @private */
7631         hasFileLoadError: false,
7632
7633         /**
7634          * @private
7635          */
7636         classNameToFilePathMap: {},
7637
7638         /**
7639          * @property {String[]} history
7640          * An array of class names to keep track of the dependency loading order.
7641          * This is not guaranteed to be the same everytime due to the asynchronous nature of the Loader.
7642          */
7643         history: [],
7644
7645         /**
7646          * Configuration
7647          * @private
7648          */
7649         config: {
7650             /**
7651              * @cfg {Boolean} enabled
7652              * Whether or not to enable the dynamic dependency loading feature.
7653              */
7654             enabled: false,
7655
7656             /**
7657              * @cfg {Boolean} disableCaching
7658              * Appends current timestamp to script files to prevent caching.
7659              */
7660             disableCaching: true,
7661
7662             /**
7663              * @cfg {String} disableCachingParam
7664              * The get parameter name for the cache buster's timestamp.
7665              */
7666             disableCachingParam: '_dc',
7667
7668             /**
7669              * @cfg {Object} paths
7670              * The mapping from namespaces to file paths
7671              *
7672              *     {
7673              *         'Ext': '.', // This is set by default, Ext.layout.container.Container will be
7674              *                     // loaded from ./layout/Container.js
7675              *
7676              *         'My': './src/my_own_folder' // My.layout.Container will be loaded from
7677              *                                     // ./src/my_own_folder/layout/Container.js
7678              *     }
7679              *
7680              * Note that all relative paths are relative to the current HTML document.
7681              * If not being specified, for example, `Other.awesome.Class`
7682              * will simply be loaded from `./Other/awesome/Class.js`
7683              */
7684             paths: {
7685                 'Ext': '.'
7686             }
7687         },
7688
7689         /**
7690          * Set the configuration for the loader. This should be called right after ext-core.js
7691          * (or ext-core-debug.js) is included in the page, e.g.:
7692          *
7693          *     <script type="text/javascript" src="ext-core-debug.js"></script>
7694          *     <script type="text/javascript">
7695          *       Ext.Loader.setConfig({
7696          *           enabled: true,
7697          *           paths: {
7698          *               'My': 'my_own_path'
7699          *           }
7700          *       });
7701          *     <script>
7702          *     <script type="text/javascript">
7703          *       Ext.require(...);
7704          *
7705          *       Ext.onReady(function() {
7706          *           // application code here
7707          *       });
7708          *     </script>
7709          *
7710          * Refer to config options of {@link Ext.Loader} for the list of possible properties.
7711          *
7712          * @param {String/Object} name  Name of the value to override, or a config object to override multiple values.
7713          * @param {Object} value  (optional) The new value to set, needed if first parameter is String.
7714          * @return {Ext.Loader} this
7715          */
7716         setConfig: function(name, value) {
7717             if (Ext.isObject(name) && arguments.length === 1) {
7718                 Ext.Object.merge(this.config, name);
7719             }
7720             else {
7721                 this.config[name] = (Ext.isObject(value)) ? Ext.Object.merge(this.config[name], value) : value;
7722             }
7723
7724             return this;
7725         },
7726
7727         /**
7728          * Get the config value corresponding to the specified name.
7729          * If no name is given, will return the config object.
7730          * @param {String} name The config property name
7731          * @return {Object}
7732          */
7733         getConfig: function(name) {
7734             if (name) {
7735                 return this.config[name];
7736             }
7737
7738             return this.config;
7739         },
7740
7741         /**
7742          * Sets the path of a namespace. For Example:
7743          *
7744          *     Ext.Loader.setPath('Ext', '.');
7745          *
7746          * @param {String/Object} name See {@link Ext.Function#flexSetter flexSetter}
7747          * @param {String} path See {@link Ext.Function#flexSetter flexSetter}
7748          * @return {Ext.Loader} this
7749          * @method
7750          */
7751         setPath: flexSetter(function(name, path) {
7752             this.config.paths[name] = path;
7753
7754             return this;
7755         }),
7756
7757         /**
7758          * Translates a className to a file path by adding the the proper prefix and converting the .'s to /'s.
7759          * For example:
7760          *
7761          *     Ext.Loader.setPath('My', '/path/to/My');
7762          *
7763          *     alert(Ext.Loader.getPath('My.awesome.Class')); // alerts '/path/to/My/awesome/Class.js'
7764          *
7765          * Note that the deeper namespace levels, if explicitly set, are always resolved first. For example:
7766          *
7767          *     Ext.Loader.setPath({
7768          *         'My': '/path/to/lib',
7769          *         'My.awesome': '/other/path/for/awesome/stuff',
7770          *         'My.awesome.more': '/more/awesome/path'
7771          *     });
7772          *
7773          *     alert(Ext.Loader.getPath('My.awesome.Class')); // alerts '/other/path/for/awesome/stuff/Class.js'
7774          *
7775          *     alert(Ext.Loader.getPath('My.awesome.more.Class')); // alerts '/more/awesome/path/Class.js'
7776          *
7777          *     alert(Ext.Loader.getPath('My.cool.Class')); // alerts '/path/to/lib/cool/Class.js'
7778          *
7779          *     alert(Ext.Loader.getPath('Unknown.strange.Stuff')); // alerts 'Unknown/strange/Stuff.js'
7780          *
7781          * @param {String} className
7782          * @return {String} path
7783          */
7784         getPath: function(className) {
7785             var path = '',
7786                 paths = this.config.paths,
7787                 prefix = this.getPrefix(className);
7788
7789             if (prefix.length > 0) {
7790                 if (prefix === className) {
7791                     return paths[prefix];
7792                 }
7793
7794                 path = paths[prefix];
7795                 className = className.substring(prefix.length + 1);
7796             }
7797
7798             if (path.length > 0) {
7799                 path += '/';
7800             }
7801
7802             return path.replace(/\/\.\//g, '/') + className.replace(/\./g, "/") + '.js';
7803         },
7804
7805         /**
7806          * @private
7807          * @param {String} className
7808          */
7809         getPrefix: function(className) {
7810             var paths = this.config.paths,
7811                 prefix, deepestPrefix = '';
7812
7813             if (paths.hasOwnProperty(className)) {
7814                 return className;
7815             }
7816
7817             for (prefix in paths) {
7818                 if (paths.hasOwnProperty(prefix) && prefix + '.' === className.substring(0, prefix.length + 1)) {
7819                     if (prefix.length > deepestPrefix.length) {
7820                         deepestPrefix = prefix;
7821                     }
7822                 }
7823             }
7824
7825             return deepestPrefix;
7826         },
7827
7828         /**
7829          * Refresh all items in the queue. If all dependencies for an item exist during looping,
7830          * it will execute the callback and call refreshQueue again. Triggers onReady when the queue is
7831          * empty
7832          * @private
7833          */
7834         refreshQueue: function() {
7835             var ln = this.queue.length,
7836                 i, item, j, requires;
7837
7838             if (ln === 0) {
7839                 this.triggerReady();
7840                 return;
7841             }
7842
7843             for (i = 0; i < ln; i++) {
7844                 item = this.queue[i];
7845
7846                 if (item) {
7847                     requires = item.requires;
7848
7849                     // Don't bother checking when the number of files loaded
7850                     // is still less than the array length
7851                     if (requires.length > this.numLoadedFiles) {
7852                         continue;
7853                     }
7854
7855                     j = 0;
7856
7857                     do {
7858                         if (Manager.isCreated(requires[j])) {
7859                             // Take out from the queue
7860                             Ext.Array.erase(requires, j, 1);
7861                         }
7862                         else {
7863                             j++;
7864                         }
7865                     } while (j < requires.length);
7866
7867                     if (item.requires.length === 0) {
7868                         Ext.Array.erase(this.queue, i, 1);
7869                         item.callback.call(item.scope);
7870                         this.refreshQueue();
7871                         break;
7872                     }
7873                 }
7874             }
7875
7876             return this;
7877         },
7878
7879         /**
7880          * Inject a script element to document's head, call onLoad and onError accordingly
7881          * @private
7882          */
7883         injectScriptElement: function(url, onLoad, onError, scope) {
7884             var script = document.createElement('script'),
7885                 me = this,
7886                 onLoadFn = function() {
7887                     me.cleanupScriptElement(script);
7888                     onLoad.call(scope);
7889                 },
7890                 onErrorFn = function() {
7891                     me.cleanupScriptElement(script);
7892                     onError.call(scope);
7893                 };
7894
7895             script.type = 'text/javascript';
7896             script.src = url;
7897             script.onload = onLoadFn;
7898             script.onerror = onErrorFn;
7899             script.onreadystatechange = function() {
7900                 if (this.readyState === 'loaded' || this.readyState === 'complete') {
7901                     onLoadFn();
7902                 }
7903             };
7904
7905             this.documentHead.appendChild(script);
7906
7907             return script;
7908         },
7909
7910         /**
7911          * @private
7912          */
7913         cleanupScriptElement: function(script) {
7914             script.onload = null;
7915             script.onreadystatechange = null;
7916             script.onerror = null;
7917
7918             return this;
7919         },
7920
7921         /**
7922          * Load a script file, supports both asynchronous and synchronous approaches
7923          *
7924          * @param {String} url
7925          * @param {Function} onLoad
7926          * @param {Object} scope
7927          * @param {Boolean} synchronous
7928          * @private
7929          */
7930         loadScriptFile: function(url, onLoad, onError, scope, synchronous) {
7931             var me = this,
7932                 noCacheUrl = url + (this.getConfig('disableCaching') ? ('?' + this.getConfig('disableCachingParam') + '=' + Ext.Date.now()) : ''),
7933                 fileName = url.split('/').pop(),
7934                 isCrossOriginRestricted = false,
7935                 xhr, status, onScriptError;
7936
7937             scope = scope || this;
7938
7939             this.isLoading = true;
7940
7941             if (!synchronous) {
7942                 onScriptError = function() {
7943                     onError.call(scope, "Failed loading '" + url + "', please verify that the file exists", synchronous);
7944                 };
7945
7946                 if (!Ext.isReady && Ext.onDocumentReady) {
7947                     Ext.onDocumentReady(function() {
7948                         me.injectScriptElement(noCacheUrl, onLoad, onScriptError, scope);
7949                     });
7950                 }
7951                 else {
7952                     this.injectScriptElement(noCacheUrl, onLoad, onScriptError, scope);
7953                 }
7954             }
7955             else {
7956                 if (typeof XMLHttpRequest !== 'undefined') {
7957                     xhr = new XMLHttpRequest();
7958                 } else {
7959                     xhr = new ActiveXObject('Microsoft.XMLHTTP');
7960                 }
7961
7962                 try {
7963                     xhr.open('GET', noCacheUrl, false);
7964                     xhr.send(null);
7965                 } catch (e) {
7966                     isCrossOriginRestricted = true;
7967                 }
7968
7969                 status = (xhr.status === 1223) ? 204 : xhr.status;
7970
7971                 if (!isCrossOriginRestricted) {
7972                     isCrossOriginRestricted = (status === 0);
7973                 }
7974
7975                 if (isCrossOriginRestricted
7976                 ) {
7977                     onError.call(this, "Failed loading synchronously via XHR: '" + url + "'; It's likely that the file is either " +
7978                                        "being loaded from a different domain or from the local file system whereby cross origin " +
7979                                        "requests are not allowed due to security reasons. Use asynchronous loading with " +
7980                                        "Ext.require instead.", synchronous);
7981                 }
7982                 else if (status >= 200 && status < 300
7983                 ) {
7984                     // Firebug friendly, file names are still shown even though they're eval'ed code
7985                     new Function(xhr.responseText + "\n//@ sourceURL=" + fileName)();
7986
7987                     onLoad.call(scope);
7988                 }
7989                 else {
7990                     onError.call(this, "Failed loading synchronously via XHR: '" + url + "'; please " +
7991                                        "verify that the file exists. " +
7992                                        "XHR status code: " + status, synchronous);
7993                 }
7994
7995                 // Prevent potential IE memory leak
7996                 xhr = null;
7997             }
7998         },
7999
8000         /**
8001          * Explicitly exclude files from being loaded. Useful when used in conjunction with a broad include expression.
8002          * Can be chained with more `require` and `exclude` methods, e.g.:
8003          *
8004          *     Ext.exclude('Ext.data.*').require('*');
8005          *
8006          *     Ext.exclude('widget.button*').require('widget.*');
8007          *
8008          * {@link Ext#exclude Ext.exclude} is alias for {@link Ext.Loader#exclude Ext.Loader.exclude} for convenience.
8009          *
8010          * @param {String/String[]} excludes
8011          * @return {Object} object contains `require` method for chaining
8012          */
8013         exclude: function(excludes) {
8014             var me = this;
8015
8016             return {
8017                 require: function(expressions, fn, scope) {
8018                     return me.require(expressions, fn, scope, excludes);
8019                 },
8020
8021                 syncRequire: function(expressions, fn, scope) {
8022                     return me.syncRequire(expressions, fn, scope, excludes);
8023                 }
8024             };
8025         },
8026
8027         /**
8028          * Synchronously loads all classes by the given names and all their direct dependencies;
8029          * optionally executes the given callback function when finishes, within the optional scope.
8030          *
8031          * {@link Ext#syncRequire Ext.syncRequire} is alias for {@link Ext.Loader#syncRequire Ext.Loader.syncRequire} for convenience.
8032          *
8033          * @param {String/String[]} expressions Can either be a string or an array of string
8034          * @param {Function} fn (Optional) The callback function
8035          * @param {Object} scope (Optional) The execution scope (`this`) of the callback function
8036          * @param {String/String[]} excludes (Optional) Classes to be excluded, useful when being used with expressions
8037          */
8038         syncRequire: function() {
8039             this.syncModeEnabled = true;
8040             this.require.apply(this, arguments);
8041             this.refreshQueue();
8042             this.syncModeEnabled = false;
8043         },
8044
8045         /**
8046          * Loads all classes by the given names and all their direct dependencies;
8047          * optionally executes the given callback function when finishes, within the optional scope.
8048          *
8049          * {@link Ext#require Ext.require} is alias for {@link Ext.Loader#require Ext.Loader.require} for convenience.
8050          *
8051          * @param {String/String[]} expressions Can either be a string or an array of string
8052          * @param {Function} fn (Optional) The callback function
8053          * @param {Object} scope (Optional) The execution scope (`this`) of the callback function
8054          * @param {String/String[]} excludes (Optional) Classes to be excluded, useful when being used with expressions
8055          */
8056         require: function(expressions, fn, scope, excludes) {
8057             var filePath, expression, exclude, className, excluded = {},
8058                 excludedClassNames = [],
8059                 possibleClassNames = [],
8060                 possibleClassName, classNames = [],
8061                 i, j, ln, subLn;
8062
8063             expressions = Ext.Array.from(expressions);
8064             excludes = Ext.Array.from(excludes);
8065
8066             fn = fn || Ext.emptyFn;
8067
8068             scope = scope || Ext.global;
8069
8070             for (i = 0, ln = excludes.length; i < ln; i++) {
8071                 exclude = excludes[i];
8072
8073                 if (typeof exclude === 'string' && exclude.length > 0) {
8074                     excludedClassNames = Manager.getNamesByExpression(exclude);
8075
8076                     for (j = 0, subLn = excludedClassNames.length; j < subLn; j++) {
8077                         excluded[excludedClassNames[j]] = true;
8078                     }
8079                 }
8080             }
8081
8082             for (i = 0, ln = expressions.length; i < ln; i++) {
8083                 expression = expressions[i];
8084
8085                 if (typeof expression === 'string' && expression.length > 0) {
8086                     possibleClassNames = Manager.getNamesByExpression(expression);
8087
8088                     for (j = 0, subLn = possibleClassNames.length; j < subLn; j++) {
8089                         possibleClassName = possibleClassNames[j];
8090
8091                         if (!excluded.hasOwnProperty(possibleClassName) && !Manager.isCreated(possibleClassName)) {
8092                             Ext.Array.include(classNames, possibleClassName);
8093                         }
8094                     }
8095                 }
8096             }
8097
8098             // If the dynamic dependency feature is not being used, throw an error
8099             // if the dependencies are not defined
8100             if (!this.config.enabled) {
8101                 if (classNames.length > 0) {
8102                     Ext.Error.raise({
8103                         sourceClass: "Ext.Loader",
8104                         sourceMethod: "require",
8105                         msg: "Ext.Loader is not enabled, so dependencies cannot be resolved dynamically. " +
8106                              "Missing required class" + ((classNames.length > 1) ? "es" : "") + ": " + classNames.join(', ')
8107                     });
8108                 }
8109             }
8110
8111             if (classNames.length === 0) {
8112                 fn.call(scope);
8113                 return this;
8114             }
8115
8116             this.queue.push({
8117                 requires: classNames,
8118                 callback: fn,
8119                 scope: scope
8120             });
8121
8122             classNames = classNames.slice();
8123
8124             for (i = 0, ln = classNames.length; i < ln; i++) {
8125                 className = classNames[i];
8126
8127                 if (!this.isFileLoaded.hasOwnProperty(className)) {
8128                     this.isFileLoaded[className] = false;
8129
8130                     filePath = this.getPath(className);
8131
8132                     this.classNameToFilePathMap[className] = filePath;
8133
8134                     this.numPendingFiles++;
8135
8136                     this.loadScriptFile(
8137                         filePath,
8138                         Ext.Function.pass(this.onFileLoaded, [className, filePath], this),
8139                         Ext.Function.pass(this.onFileLoadError, [className, filePath]),
8140                         this,
8141                         this.syncModeEnabled
8142                     );
8143                 }
8144             }
8145
8146             return this;
8147         },
8148
8149         /**
8150          * @private
8151          * @param {String} className
8152          * @param {String} filePath
8153          */
8154         onFileLoaded: function(className, filePath) {
8155             this.numLoadedFiles++;
8156
8157             this.isFileLoaded[className] = true;
8158
8159             this.numPendingFiles--;
8160
8161             if (this.numPendingFiles === 0) {
8162                 this.refreshQueue();
8163             }
8164
8165             if (this.numPendingFiles <= 1) {
8166                 window.status = "Finished loading all dependencies, onReady fired!";
8167             }
8168             else {
8169                 window.status = "Loading dependencies, " + this.numPendingFiles + " files left...";
8170             }
8171
8172             if (!this.syncModeEnabled && this.numPendingFiles === 0 && this.isLoading && !this.hasFileLoadError) {
8173                 var queue = this.queue,
8174                     requires,
8175                     i, ln, j, subLn, missingClasses = [], missingPaths = [];
8176
8177                 for (i = 0, ln = queue.length; i < ln; i++) {
8178                     requires = queue[i].requires;
8179
8180                     for (j = 0, subLn = requires.length; j < ln; j++) {
8181                         if (this.isFileLoaded[requires[j]]) {
8182                             missingClasses.push(requires[j]);
8183                         }
8184                     }
8185                 }
8186
8187                 if (missingClasses.length < 1) {
8188                     return;
8189                 }
8190
8191                 missingClasses = Ext.Array.filter(missingClasses, function(item) {
8192                     return !this.requiresMap.hasOwnProperty(item);
8193                 }, this);
8194
8195                 for (i = 0,ln = missingClasses.length; i < ln; i++) {
8196                     missingPaths.push(this.classNameToFilePathMap[missingClasses[i]]);
8197                 }
8198
8199                 Ext.Error.raise({
8200                     sourceClass: "Ext.Loader",
8201                     sourceMethod: "onFileLoaded",
8202                     msg: "The following classes are not declared even if their files have been " +
8203                             "loaded: '" + missingClasses.join("', '") + "'. Please check the source code of their " +
8204                             "corresponding files for possible typos: '" + missingPaths.join("', '") + "'"
8205                 });
8206             }
8207         },
8208
8209         /**
8210          * @private
8211          */
8212         onFileLoadError: function(className, filePath, errorMessage, isSynchronous) {
8213             this.numPendingFiles--;
8214             this.hasFileLoadError = true;
8215
8216             Ext.Error.raise({
8217                 sourceClass: "Ext.Loader",
8218                 classToLoad: className,
8219                 loadPath: filePath,
8220                 loadingType: isSynchronous ? 'synchronous' : 'async',
8221                 msg: errorMessage
8222             });
8223         },
8224
8225         /**
8226          * @private
8227          */
8228         addOptionalRequires: function(requires) {
8229             var optionalRequires = this.optionalRequires,
8230                 i, ln, require;
8231
8232             requires = Ext.Array.from(requires);
8233
8234             for (i = 0, ln = requires.length; i < ln; i++) {
8235                 require = requires[i];
8236
8237                 Ext.Array.include(optionalRequires, require);
8238             }
8239
8240             return this;
8241         },
8242
8243         /**
8244          * @private
8245          */
8246         triggerReady: function(force) {
8247             var readyListeners = this.readyListeners,
8248                 optionalRequires, listener;
8249
8250             if (this.isLoading || force) {
8251                 this.isLoading = false;
8252
8253                 if (this.optionalRequires.length) {
8254                     // Clone then empty the array to eliminate potential recursive loop issue
8255                     optionalRequires = Ext.Array.clone(this.optionalRequires);
8256
8257                     // Empty the original array
8258                     this.optionalRequires.length = 0;
8259
8260                     this.require(optionalRequires, Ext.Function.pass(this.triggerReady, [true], this), this);
8261                     return this;
8262                 }
8263
8264                 while (readyListeners.length) {
8265                     listener = readyListeners.shift();
8266                     listener.fn.call(listener.scope);
8267
8268                     if (this.isLoading) {
8269                         return this;
8270                     }
8271                 }
8272             }
8273
8274             return this;
8275         },
8276
8277         /**
8278          * Adds new listener to be executed when all required scripts are fully loaded.
8279          *
8280          * @param {Function} fn The function callback to be executed
8281          * @param {Object} scope The execution scope (`this`) of the callback function
8282          * @param {Boolean} withDomReady Whether or not to wait for document dom ready as well
8283          */
8284         onReady: function(fn, scope, withDomReady, options) {
8285             var oldFn;
8286
8287             if (withDomReady !== false && Ext.onDocumentReady) {
8288                 oldFn = fn;
8289
8290                 fn = function() {
8291                     Ext.onDocumentReady(oldFn, scope, options);
8292                 };
8293             }
8294
8295             if (!this.isLoading) {
8296                 fn.call(scope);
8297             }
8298             else {
8299                 this.readyListeners.push({
8300                     fn: fn,
8301                     scope: scope
8302                 });
8303             }
8304         },
8305
8306         /**
8307          * @private
8308          * @param {String} className
8309          */
8310         historyPush: function(className) {
8311             if (className && this.isFileLoaded.hasOwnProperty(className)) {
8312                 Ext.Array.include(this.history, className);
8313             }
8314
8315             return this;
8316         }
8317     };
8318
8319     /**
8320      * @member Ext
8321      * @method require
8322      * @alias Ext.Loader#require
8323      */
8324     Ext.require = alias(Loader, 'require');
8325
8326     /**
8327      * @member Ext
8328      * @method syncRequire
8329      * @alias Ext.Loader#syncRequire
8330      */
8331     Ext.syncRequire = alias(Loader, 'syncRequire');
8332
8333     /**
8334      * @member Ext
8335      * @method exclude
8336      * @alias Ext.Loader#exclude
8337      */
8338     Ext.exclude = alias(Loader, 'exclude');
8339
8340     /**
8341      * @member Ext
8342      * @method onReady
8343      * @alias Ext.Loader#onReady
8344      */
8345     Ext.onReady = function(fn, scope, options) {
8346         Loader.onReady(fn, scope, true, options);
8347     };
8348
8349     /**
8350      * @cfg {String[]} requires
8351      * @member Ext.Class
8352      * List of classes that have to be loaded before instantiating this class.
8353      * For example:
8354      *
8355      *     Ext.define('Mother', {
8356      *         requires: ['Child'],
8357      *         giveBirth: function() {
8358      *             // we can be sure that child class is available.
8359      *             return new Child();
8360      *         }
8361      *     });
8362      */
8363     Class.registerPreprocessor('loader', function(cls, data, continueFn) {
8364         var me = this,
8365             dependencies = [],
8366             className = Manager.getName(cls),
8367             i, j, ln, subLn, value, propertyName, propertyValue;
8368
8369         /*
8370         Basically loop through the dependencyProperties, look for string class names and push
8371         them into a stack, regardless of whether the property's value is a string, array or object. For example:
8372         {
8373               extend: 'Ext.MyClass',
8374               requires: ['Ext.some.OtherClass'],
8375               mixins: {
8376                   observable: 'Ext.util.Observable';
8377               }
8378         }
8379         which will later be transformed into:
8380         {
8381               extend: Ext.MyClass,
8382               requires: [Ext.some.OtherClass],
8383               mixins: {
8384                   observable: Ext.util.Observable;
8385               }
8386         }
8387         */
8388
8389         for (i = 0, ln = dependencyProperties.length; i < ln; i++) {
8390             propertyName = dependencyProperties[i];
8391
8392             if (data.hasOwnProperty(propertyName)) {
8393                 propertyValue = data[propertyName];
8394
8395                 if (typeof propertyValue === 'string') {
8396                     dependencies.push(propertyValue);
8397                 }
8398                 else if (propertyValue instanceof Array) {
8399                     for (j = 0, subLn = propertyValue.length; j < subLn; j++) {
8400                         value = propertyValue[j];
8401
8402                         if (typeof value === 'string') {
8403                             dependencies.push(value);
8404                         }
8405                     }
8406                 }
8407                 else if (typeof propertyValue != 'function') {
8408                     for (j in propertyValue) {
8409                         if (propertyValue.hasOwnProperty(j)) {
8410                             value = propertyValue[j];
8411
8412                             if (typeof value === 'string') {
8413                                 dependencies.push(value);
8414                             }
8415                         }
8416                     }
8417                 }
8418             }
8419         }
8420
8421         if (dependencies.length === 0) {
8422 //            Loader.historyPush(className);
8423             return;
8424         }
8425
8426         var deadlockPath = [],
8427             requiresMap = Loader.requiresMap,
8428             detectDeadlock;
8429
8430         /*
8431         Automatically detect deadlocks before-hand,
8432         will throw an error with detailed path for ease of debugging. Examples of deadlock cases:
8433
8434         - A extends B, then B extends A
8435         - A requires B, B requires C, then C requires A
8436
8437         The detectDeadlock function will recursively transverse till the leaf, hence it can detect deadlocks
8438         no matter how deep the path is.
8439         */
8440
8441         if (className) {
8442             requiresMap[className] = dependencies;
8443
8444             detectDeadlock = function(cls) {
8445                 deadlockPath.push(cls);
8446
8447                 if (requiresMap[cls]) {
8448                     if (Ext.Array.contains(requiresMap[cls], className)) {
8449                         Ext.Error.raise({
8450                             sourceClass: "Ext.Loader",
8451                             msg: "Deadlock detected while loading dependencies! '" + className + "' and '" +
8452                                 deadlockPath[1] + "' " + "mutually require each other. Path: " +
8453                                 deadlockPath.join(' -> ') + " -> " + deadlockPath[0]
8454                         });
8455                     }
8456
8457                     for (i = 0, ln = requiresMap[cls].length; i < ln; i++) {
8458                         detectDeadlock(requiresMap[cls][i]);
8459                     }
8460                 }
8461             };
8462
8463             detectDeadlock(className);
8464         }
8465
8466
8467         Loader.require(dependencies, function() {
8468             for (i = 0, ln = dependencyProperties.length; i < ln; i++) {
8469                 propertyName = dependencyProperties[i];
8470
8471                 if (data.hasOwnProperty(propertyName)) {
8472                     propertyValue = data[propertyName];
8473
8474                     if (typeof propertyValue === 'string') {
8475                         data[propertyName] = Manager.get(propertyValue);
8476                     }
8477                     else if (propertyValue instanceof Array) {
8478                         for (j = 0, subLn = propertyValue.length; j < subLn; j++) {
8479                             value = propertyValue[j];
8480
8481                             if (typeof value === 'string') {
8482                                 data[propertyName][j] = Manager.get(value);
8483                             }
8484                         }
8485                     }
8486                     else if (typeof propertyValue != 'function') {
8487                         for (var k in propertyValue) {
8488                             if (propertyValue.hasOwnProperty(k)) {
8489                                 value = propertyValue[k];
8490
8491                                 if (typeof value === 'string') {
8492                                     data[propertyName][k] = Manager.get(value);
8493                                 }
8494                             }
8495                         }
8496                     }
8497                 }
8498             }
8499
8500             continueFn.call(me, cls, data);
8501         });
8502
8503         return false;
8504     }, true);
8505
8506     Class.setDefaultPreprocessorPosition('loader', 'after', 'className');
8507
8508     /**
8509      * @cfg {String[]} uses
8510      * @member Ext.Class
8511      * List of classes to load together with this class.  These aren't neccessarily loaded before
8512      * this class is instantiated. For example:
8513      *
8514      *     Ext.define('Mother', {
8515      *         uses: ['Child'],
8516      *         giveBirth: function() {
8517      *             // This code might, or might not work:
8518      *             // return new Child();
8519      *
8520      *             // Instead use Ext.create() to load the class at the spot if not loaded already:
8521      *             return Ext.create('Child');
8522      *         }
8523      *     });
8524      */
8525     Manager.registerPostprocessor('uses', function(name, cls, data) {
8526         var uses = Ext.Array.from(data.uses),
8527             items = [],
8528             i, ln, item;
8529
8530         for (i = 0, ln = uses.length; i < ln; i++) {
8531             item = uses[i];
8532
8533             if (typeof item === 'string') {
8534                 items.push(item);
8535             }
8536         }
8537
8538         Loader.addOptionalRequires(items);
8539     });
8540
8541     Manager.setDefaultPostprocessorPosition('uses', 'last');
8542
8543 })(Ext.ClassManager, Ext.Class, Ext.Function.flexSetter, Ext.Function.alias);
8544
8545 /**
8546  * @author Brian Moeskau <brian@sencha.com>
8547  * @docauthor Brian Moeskau <brian@sencha.com>
8548  *
8549  * A wrapper class for the native JavaScript Error object that adds a few useful capabilities for handling
8550  * errors in an Ext application. When you use Ext.Error to {@link #raise} an error from within any class that
8551  * uses the Ext 4 class system, the Error class can automatically add the source class and method from which
8552  * the error was raised. It also includes logic to automatically log the eroor to the console, if available,
8553  * with additional metadata about the error. In all cases, the error will always be thrown at the end so that
8554  * execution will halt.
8555  *
8556  * Ext.Error also offers a global error {@link #handle handling} method that can be overridden in order to
8557  * handle application-wide errors in a single spot. You can optionally {@link #ignore} errors altogether,
8558  * although in a real application it's usually a better idea to override the handling function and perform
8559  * logging or some other method of reporting the errors in a way that is meaningful to the application.
8560  *
8561  * At its simplest you can simply raise an error as a simple string from within any code:
8562  *
8563  * Example usage:
8564  *
8565  *     Ext.Error.raise('Something bad happened!');
8566  *
8567  * If raised from plain JavaScript code, the error will be logged to the console (if available) and the message
8568  * displayed. In most cases however you'll be raising errors from within a class, and it may often be useful to add
8569  * additional metadata about the error being raised.  The {@link #raise} method can also take a config object.
8570  * In this form the `msg` attribute becomes the error description, and any other data added to the config gets
8571  * added to the error object and, if the console is available, logged to the console for inspection.
8572  *
8573  * Example usage:
8574  *
8575  *     Ext.define('Ext.Foo', {
8576  *         doSomething: function(option){
8577  *             if (someCondition === false) {
8578  *                 Ext.Error.raise({
8579  *                     msg: 'You cannot do that!',
8580  *                     option: option,   // whatever was passed into the method
8581  *                     'error code': 100 // other arbitrary info
8582  *                 });
8583  *             }
8584  *         }
8585  *     });
8586  *
8587  * If a console is available (that supports the `console.dir` function) you'll see console output like:
8588  *
8589  *     An error was raised with the following data:
8590  *     option:         Object { foo: "bar"}
8591  *         foo:        "bar"
8592  *     error code:     100
8593  *     msg:            "You cannot do that!"
8594  *     sourceClass:   "Ext.Foo"
8595  *     sourceMethod:  "doSomething"
8596  *
8597  *     uncaught exception: You cannot do that!
8598  *
8599  * As you can see, the error will report exactly where it was raised and will include as much information as the
8600  * raising code can usefully provide.
8601  *
8602  * If you want to handle all application errors globally you can simply override the static {@link #handle} method
8603  * and provide whatever handling logic you need. If the method returns true then the error is considered handled
8604  * and will not be thrown to the browser. If anything but true is returned then the error will be thrown normally.
8605  *
8606  * Example usage:
8607  *
8608  *     Ext.Error.handle = function(err) {
8609  *         if (err.someProperty == 'NotReallyAnError') {
8610  *             // maybe log something to the application here if applicable
8611  *             return true;
8612  *         }
8613  *         // any non-true return value (including none) will cause the error to be thrown
8614  *     }
8615  *
8616  */
8617 Ext.Error = Ext.extend(Error, {
8618     statics: {
8619         /**
8620          * @property {Boolean} ignore
8621          * Static flag that can be used to globally disable error reporting to the browser if set to true
8622          * (defaults to false). Note that if you ignore Ext errors it's likely that some other code may fail
8623          * and throw a native JavaScript error thereafter, so use with caution. In most cases it will probably
8624          * be preferable to supply a custom error {@link #handle handling} function instead.
8625          *
8626          * Example usage:
8627          *
8628          *     Ext.Error.ignore = true;
8629          *
8630          * @static
8631          */
8632         ignore: false,
8633
8634         /**
8635          * @property {Boolean} notify
8636          * Static flag that can be used to globally control error notification to the user. Unlike
8637          * Ex.Error.ignore, this does not effect exceptions. They are still thrown. This value can be
8638          * set to false to disable the alert notification (default is true for IE6 and IE7).
8639          *
8640          * Only the first error will generate an alert. Internally this flag is set to false when the
8641          * first error occurs prior to displaying the alert.
8642          *
8643          * This flag is not used in a release build.
8644          *
8645          * Example usage:
8646          *
8647          *     Ext.Error.notify = false;
8648          *
8649          * @static
8650          */
8651         //notify: Ext.isIE6 || Ext.isIE7,
8652
8653         /**
8654          * Raise an error that can include additional data and supports automatic console logging if available.
8655          * You can pass a string error message or an object with the `msg` attribute which will be used as the
8656          * error message. The object can contain any other name-value attributes (or objects) to be logged
8657          * along with the error.
8658          *
8659          * Note that after displaying the error message a JavaScript error will ultimately be thrown so that
8660          * execution will halt.
8661          *
8662          * Example usage:
8663          *
8664          *     Ext.Error.raise('A simple string error message');
8665          *
8666          *     // or...
8667          *
8668          *     Ext.define('Ext.Foo', {
8669          *         doSomething: function(option){
8670          *             if (someCondition === false) {
8671          *                 Ext.Error.raise({
8672          *                     msg: 'You cannot do that!',
8673          *                     option: option,   // whatever was passed into the method
8674          *                     'error code': 100 // other arbitrary info
8675          *                 });
8676          *             }
8677          *         }
8678          *     });
8679          *
8680          * @param {String/Object} err The error message string, or an object containing the attribute "msg" that will be
8681          * used as the error message. Any other data included in the object will also be logged to the browser console,
8682          * if available.
8683          * @static
8684          */
8685         raise: function(err){
8686             err = err || {};
8687             if (Ext.isString(err)) {
8688                 err = { msg: err };
8689             }
8690
8691             var method = this.raise.caller;
8692
8693             if (method) {
8694                 if (method.$name) {
8695                     err.sourceMethod = method.$name;
8696                 }
8697                 if (method.$owner) {
8698                     err.sourceClass = method.$owner.$className;
8699                 }
8700             }
8701
8702             if (Ext.Error.handle(err) !== true) {
8703                 var msg = Ext.Error.prototype.toString.call(err);
8704
8705                 Ext.log({
8706                     msg: msg,
8707                     level: 'error',
8708                     dump: err,
8709                     stack: true
8710                 });
8711
8712                 throw new Ext.Error(err);
8713             }
8714         },
8715
8716         /**
8717          * Globally handle any Ext errors that may be raised, optionally providing custom logic to
8718          * handle different errors individually. Return true from the function to bypass throwing the
8719          * error to the browser, otherwise the error will be thrown and execution will halt.
8720          *
8721          * Example usage:
8722          *
8723          *     Ext.Error.handle = function(err) {
8724          *         if (err.someProperty == 'NotReallyAnError') {
8725          *             // maybe log something to the application here if applicable
8726          *             return true;
8727          *         }
8728          *         // any non-true return value (including none) will cause the error to be thrown
8729          *     }
8730          *
8731          * @param {Ext.Error} err The Ext.Error object being raised. It will contain any attributes that were originally
8732          * raised with it, plus properties about the method and class from which the error originated (if raised from a
8733          * class that uses the Ext 4 class system).
8734          * @static
8735          */
8736         handle: function(){
8737             return Ext.Error.ignore;
8738         }
8739     },
8740
8741     // This is the standard property that is the name of the constructor.
8742     name: 'Ext.Error',
8743
8744     /**
8745      * Creates new Error object.
8746      * @param {String/Object} config The error message string, or an object containing the
8747      * attribute "msg" that will be used as the error message. Any other data included in
8748      * the object will be applied to the error instance and logged to the browser console, if available.
8749      */
8750     constructor: function(config){
8751         if (Ext.isString(config)) {
8752             config = { msg: config };
8753         }
8754
8755         var me = this;
8756
8757         Ext.apply(me, config);
8758
8759         me.message = me.message || me.msg; // 'message' is standard ('msg' is non-standard)
8760         // note: the above does not work in old WebKit (me.message is readonly) (Safari 4)
8761     },
8762
8763     /**
8764      * Provides a custom string representation of the error object. This is an override of the base JavaScript
8765      * `Object.toString` method, which is useful so that when logged to the browser console, an error object will
8766      * be displayed with a useful message instead of `[object Object]`, the default `toString` result.
8767      *
8768      * The default implementation will include the error message along with the raising class and method, if available,
8769      * but this can be overridden with a custom implementation either at the prototype level (for all errors) or on
8770      * a particular error instance, if you want to provide a custom description that will show up in the console.
8771      * @return {String} The error message. If raised from within the Ext 4 class system, the error message will also
8772      * include the raising class and method names, if available.
8773      */
8774     toString: function(){
8775         var me = this,
8776             className = me.className ? me.className  : '',
8777             methodName = me.methodName ? '.' + me.methodName + '(): ' : '',
8778             msg = me.msg || '(No description provided)';
8779
8780         return className + methodName + msg;
8781     }
8782 });
8783
8784 /*
8785  * This mechanism is used to notify the user of the first error encountered on the page. This
8786  * was previously internal to Ext.Error.raise and is a desirable feature since errors often
8787  * slip silently under the radar. It cannot live in Ext.Error.raise since there are times
8788  * where exceptions are handled in a try/catch.
8789  */
8790 (function () {
8791     var prevOnError, timer, errors = 0,
8792         extraordinarilyBad = /(out of stack)|(too much recursion)|(stack overflow)|(out of memory)/i,
8793         win = Ext.global;
8794
8795     if (typeof window === 'undefined') {
8796         return; // build system or some such environment...
8797     }
8798
8799     // This method is called to notify the user of the current error status.
8800     function notify () {
8801         var counters = Ext.log.counters,
8802             supports = Ext.supports,
8803             hasOnError = supports && supports.WindowOnError; // TODO - timing
8804
8805         // Put log counters to the status bar (for most browsers):
8806         if (counters && (counters.error + counters.warn + counters.info + counters.log)) {
8807             var msg = [ 'Logged Errors:',counters.error, 'Warnings:',counters.warn,
8808                         'Info:',counters.info, 'Log:',counters.log].join(' ');
8809             if (errors) {
8810                 msg = '*** Errors: ' + errors + ' - ' + msg;
8811             } else if (counters.error) {
8812                 msg = '*** ' + msg;
8813             }
8814             win.status = msg;
8815         }
8816
8817         // Display an alert on the first error:
8818         if (!Ext.isDefined(Ext.Error.notify)) {
8819             Ext.Error.notify = Ext.isIE6 || Ext.isIE7; // TODO - timing
8820         }
8821         if (Ext.Error.notify && (hasOnError ? errors : (counters && counters.error))) {
8822             Ext.Error.notify = false;
8823
8824             if (timer) {
8825                 win.clearInterval(timer); // ticks can queue up so stop...
8826                 timer = null;
8827             }
8828
8829             alert('Unhandled error on page: See console or log');
8830             poll();
8831         }
8832     }
8833
8834     // Sets up polling loop. This is the only way to know about errors in some browsers
8835     // (Opera/Safari) and is the only way to update the status bar for warnings and other
8836     // non-errors.
8837     function poll () {
8838         timer = win.setInterval(notify, 1000);
8839     }
8840
8841     // window.onerror sounds ideal but it prevents the built-in error dialog from doing
8842     // its (better) thing.
8843     poll();
8844 })();
8845
8846
8847
8848