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