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