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