/**
 * @class Ext.Class
 *
 * This is a low level factory that is used by {@link Ext#define Ext.define} and should not be used
 * directly in application code.
 * 
 * The configs of this class are intended to be used in `Ext.define` calls to describe the class you
 * are declaring. For example:
 * 
 *     Ext.define('App.util.Thing', {
 *         extend: 'App.util.Other',
 * 
 *         alias: 'util.thing',
 * 
 *         config: {
 *             foo: 42
 *         }
 *     });
 *
 * Ext.Class is the factory and **not** the superclass of everything. For the base class that **all**
 * classes inherit from, see {@link Ext.Base}.
 */
(function() {
// @tag class 
// @define Ext.Class 
// @require Ext.Base 
// @require Ext.Util 
// @require Ext.util.Cache 
    var ExtClass,
        Base = Ext.Base,
        baseStaticMembers = Base.$staticMembers,
        ruleKeySortFn = function (a, b) {
            // longest to shortest, by text if names are equal 
            return (a.length - b.length) || ((< b) ? -1 : ((> b) ? 1 : 0));
        };
 
    // Creates a constructor that has nothing extra in its scope chain. 
    function makeCtor (className) {
        function constructor () {
            // Opera has some problems returning from a constructor when Dragonfly isn't running. The || null seems to 
            // be sufficient to stop it misbehaving. Known to be required against 10.53, 11.51 and 11.61. 
            return this.constructor.apply(this, arguments) || null;
        }
        //<debug> 
        if (className) {
            constructor.name = className;
        }
        //</debug> 
        return constructor;
    }
 
    /**
     * @method constructor
     * Create a new anonymous class.
     *
     * @param {Object} data An object represent the properties of this class
     * @param {Function} onCreated Optional, the callback function to be executed when this class is fully created.
     * Note that the creation process can be asynchronous depending on the pre-processors used.
     *
     * @return {Ext.Base} The newly created class
     */
    Ext.Class = ExtClass = function(Class, data, onCreated) {
        if (typeof Class != 'function') {
            onCreated = data;
            data = Class;
            Class = null;
        }
 
        if (!data) {
            data = {};
        }
 
        Class = ExtClass.create(Class, data);
 
        ExtClass.process(Class, data, onCreated);
 
        return Class;
    };
 
    Ext.apply(ExtClass, {
        
        makeCtor: makeCtor,
        
        /**
         * @private
         */
        onBeforeCreated: function(Class, data, hooks) {
            //<debug> 
            Ext.classSystemMonitor && Ext.classSystemMonitor(Class, '>> Ext.Class#onBeforeCreated', arguments);
            //</debug> 
        
            Class.addMembers(data);
 
            hooks.onCreated.call(Class, Class);
 
            //<debug> 
            Ext.classSystemMonitor && Ext.classSystemMonitor(Class, '<< Ext.Class#onBeforeCreated', arguments);
            //</debug> 
        },
 
        /**
         * @private
         */
        create: function (Class, data) {
            var i = baseStaticMembers.length,
                name;
 
            if (!Class) {
                Class = makeCtor(
                    //<debug> 
                    data.$className
                    //</debug> 
                );
            }
 
            while (i--) {
                name = baseStaticMembers[i];
                Class[name] = Base[name];
            }
 
            return Class;
        },
 
        /**
         * @private
         */
        process: function(Class, data, onCreated) {
            var preprocessorStack = data.preprocessors || ExtClass.defaultPreprocessors,
                registeredPreprocessors = this.preprocessors,
                hooks = {
                    onBeforeCreated: this.onBeforeCreated
                },
                preprocessors = [],
                preprocessor, preprocessorsProperties,
                i, ln, j, subLn, preprocessorProperty;
 
            delete data.preprocessors;
            Class._classHooks = hooks;
 
            for (= 0,ln = preprocessorStack.length; i < ln; i++) {
                preprocessor = preprocessorStack[i];
 
                if (typeof preprocessor == 'string') {
                    preprocessor = registeredPreprocessors[preprocessor];
                    preprocessorsProperties = preprocessor.properties;
 
                    if (preprocessorsProperties === true) {
                        preprocessors.push(preprocessor.fn);
                    }
                    else if (preprocessorsProperties) {
                        for (= 0,subLn = preprocessorsProperties.length; j < subLn; j++) {
                            preprocessorProperty = preprocessorsProperties[j];
 
                            if (data.hasOwnProperty(preprocessorProperty)) {
                                preprocessors.push(preprocessor.fn);
                                break;
                            }
                        }
                    }
                }
                else {
                    preprocessors.push(preprocessor);
                }
            }
 
            hooks.onCreated = onCreated ? onCreated : Ext.emptyFn;
            hooks.preprocessors = preprocessors;
 
            this.doProcess(Class, data, hooks);
        },
        
        doProcess: function(Class, data, hooks) {
            var me = this,
                preprocessors = hooks.preprocessors,
                preprocessor = preprocessors.shift(),
                doProcess = me.doProcess;
 
            for ( ; preprocessor ; preprocessor = preprocessors.shift()) {
                // Returning false signifies an asynchronous preprocessor - it will call doProcess when we can continue 
                if (preprocessor.call(me, Class, data, hooks, doProcess) === false) {
                    return;
                }
            }
            hooks.onBeforeCreated.apply(me, arguments);
        },
 
        /**
         * @private
         * */
        preprocessors: {},
 
        /**
         * Register a new pre-processor to be used during the class creation process
         *
         * @param {String} name The pre-processor's name
         * @param {Function} fn The callback function to be executed. Typical format:
         *
         *     function(cls, data, fn) {
         *         // Your code here
         *
         *         // Execute this when the processing is finished.
         *         // Asynchronous processing is perfectly ok
         *         if (fn) {
         *             fn.call(this, cls, data);
         *         }
         *     });
         *
         * @param {Function} fn.cls The created class
         * @param {Object} fn.data The set of properties passed in {@link Ext.Class} constructor
         * @param {Function} fn.fn The callback function that **must** to be executed when this
         * pre-processor finishes, regardless of whether the processing is synchronous or asynchronous.
         * @return {Ext.Class} this
         * @private
         * @static
         */
        registerPreprocessor: function(name, fn, properties, position, relativeTo) {
            if (!position) {
                position = 'last';
            }
 
            if (!properties) {
                properties = [name];
            }
 
            this.preprocessors[name] = {
                name: name,
                properties: properties || false,
                fn: fn
            };
 
            this.setDefaultPreprocessorPosition(name, position, relativeTo);
 
            return this;
        },
 
        /**
         * Retrieve a pre-processor callback function by its name, which has been registered before
         *
         * @param {String} name 
         * @return {Function} preprocessor 
         * @private
         * @static
         */
        getPreprocessor: function(name) {
            return this.preprocessors[name];
        },
 
        /**
         * @private
         */
        getPreprocessors: function() {
            return this.preprocessors;
        },
 
        /**
         * @private
         */
        defaultPreprocessors: [],
 
        /**
         * Retrieve the array stack of default pre-processors
         * @return {Function[]} defaultPreprocessors
         * @private
         * @static
         */
        getDefaultPreprocessors: function() {
            return this.defaultPreprocessors;
        },
 
        /**
         * Set the default array stack of default pre-processors
         *
         * @private
         * @param {Array} preprocessors 
         * @return {Ext.Class} this
         * @static
         */
        setDefaultPreprocessors: function(preprocessors) {
            this.defaultPreprocessors = Ext.Array.from(preprocessors);
 
            return this;
        },
 
        /**
         * Insert this pre-processor at a specific position in the stack, optionally relative to
         * any existing pre-processor. For example:
         *
         *     Ext.Class.registerPreprocessor('debug', function(cls, data, fn) {
         *         // Your code here
         *
         *         if (fn) {
         *             fn.call(this, cls, data);
         *         }
         *     }).setDefaultPreprocessorPosition('debug', 'last');
         *
         * @private
         * @param {String} name The pre-processor name. Note that it needs to be registered with
         * {@link Ext.Class#registerPreprocessor registerPreprocessor} before this
         * @param {String} offset The insertion position. Four possible values are:
         * 'first', 'last', or: 'before', 'after' (relative to the name provided in the third argument)
         * @param {String} relativeName 
         * @return {Ext.Class} this
         * @static
         */
        setDefaultPreprocessorPosition: function(name, offset, relativeName) {
            var defaultPreprocessors = this.defaultPreprocessors,
                index;
 
            if (typeof offset == 'string') {
                if (offset === 'first') {
                    defaultPreprocessors.unshift(name);
 
                    return this;
                }
                else if (offset === 'last') {
                    defaultPreprocessors.push(name);
 
                    return this;
                }
 
                offset = (offset === 'after') ? 1 : -1;
            }
 
            index = Ext.Array.indexOf(defaultPreprocessors, relativeName);
 
            if (index !== -1) {
                Ext.Array.splice(defaultPreprocessors, Math.max(0, index + offset), 0, name);
            }
 
            return this;
        }
    });
 
    /**
     * @cfg {String} extend 
     * The parent class that this class extends. For example:
     *
     *     Ext.define('Person', {
     *         say: function(text) { alert(text); }
     *     });
     *
     *     Ext.define('Developer', {
     *         extend: 'Person',
     *         say: function(text) { this.callParent(["print "+text]); }
     *     });
     */
    ExtClass.registerPreprocessor('extend', function(Class, data, hooks) {
        //<debug> 
        Ext.classSystemMonitor && Ext.classSystemMonitor(Class, 'Ext.Class#extendPreProcessor', arguments);
        //</debug> 
        
        var Base = Ext.Base,
            basePrototype = Base.prototype,
            extend = data.extend,
            Parent, parentPrototype, i;
 
        delete data.extend;
 
        if (extend && extend !== Object) {
            Parent = extend;
        }
        else {
            Parent = Base;
        }
 
        parentPrototype = Parent.prototype;
 
        if (!Parent.$isClass) {
            for (in basePrototype) {
                if (!parentPrototype[i]) {
                    parentPrototype[i] = basePrototype[i];
                }
            }
        }
 
        Class.extend(Parent);
 
        Class.triggerExtended.apply(Class, arguments);
 
        if (data.onClassExtended) {
            Class.onExtended(data.onClassExtended, Class);
            delete data.onClassExtended;
        }
 
    }, true); // true to always run this preprocessor even w/o "extend" keyword 
 
    /**
     * @cfg {Object} privates 
     * The `privates` config is a list of methods intended to be used internally by the 
     * framework.  Methods are placed in a `privates` block to prevent developers from 
     * accidentally overriding framework methods in custom classes.
     *
     *     Ext.define('Computer', {
     *         privates: {
     *             runFactory: function(brand) {
     *                 // internal only processing of brand passed to factory
     *                 this.factory(brand);
     *             }
     *         },
     *     
     *         factory: function (brand) {}
     *     });
     * 
     * In order to override a method from a `privates` block, the overridden method must 
     * also be placed in a `privates` block within the override class.
     * 
     *     Ext.define('Override.Computer', {
     *         override: 'Computer',
     *         privates: {
     *             runFactory: function() {
     *                 // overriding logic
     *             }
     *         }
     *     });
     */
    ExtClass.registerPreprocessor('privates', function(Class, data) {
        //<debug> 
        Ext.classSystemMonitor && Ext.classSystemMonitor(Class, 'Ext.Class#privatePreprocessor', arguments);
        //</debug> 
 
        var privates = data.privates,
            statics = privates.statics,
            privacy = privates.privacy || true;
 
        delete data.privates;
        delete privates.statics;
 
        // We have to add this preprocessor so that private getters/setters are picked up 
        // by the config system. This also catches duplication in the public part of the 
        // class since it is an error to override a private method with a public one. 
        Class.addMembers(privates, false, privacy);
        if (statics) {
            Class.addMembers(statics, true, privacy);
        }
    });
 
    //<feature classSystem.statics> 
    /**
     * @cfg {Object} statics 
     * List of static methods for this class. For example:
     *
     *     Ext.define('Computer', {
     *          statics: {
     *              factory: function(brand) {
     *                  // 'this' in static methods refer to the class itself
     *                  return new this(brand);
     *              }
     *          },
     *
     *          constructor: function() { ... }
     *     });
     *
     *     var dellComputer = Computer.factory('Dell');
     */
    ExtClass.registerPreprocessor('statics', function(Class, data) {
        //<debug> 
        Ext.classSystemMonitor && Ext.classSystemMonitor(Class, 'Ext.Class#staticsPreprocessor', arguments);
        //</debug> 
        
        Class.addStatics(data.statics);
 
        delete data.statics;
    });
    //</feature> 
 
    //<feature classSystem.inheritableStatics> 
    /**
     * @cfg {Object} inheritableStatics 
     * List of inheritable static methods for this class.
     * Otherwise just like {@link #statics} but subclasses inherit these methods.
     */
    ExtClass.registerPreprocessor('inheritableStatics', function(Class, data) {
        //<debug> 
        Ext.classSystemMonitor && Ext.classSystemMonitor(Class, 'Ext.Class#inheritableStaticsPreprocessor', arguments);
        //</debug> 
        
        Class.addInheritableStatics(data.inheritableStatics);
 
        delete data.inheritableStatics;
    });
    //</feature> 
 
    Ext.createRuleFn = function (code) {
        return new Function('$c', 'with($c) { return (' + code + '); }');
    };
    Ext.expressionCache = new Ext.util.Cache({
        miss: Ext.createRuleFn
    });
 
    Ext.ruleKeySortFn = ruleKeySortFn;
    Ext.getPlatformConfigKeys = function (platformConfig) {
        var ret = [],
            platform, rule;
 
        for (platform in platformConfig) {
            rule = Ext.expressionCache.get(platform);
            if (rule(Ext.platformTags)) {
                ret.push(platform);
            }
        }
 
        ret.sort(ruleKeySortFn);
        return ret;
    };
 
    //<feature classSystem.platformConfig> 
    /**
     * @cfg {Object} platformConfig 
     * Allows setting config values for a class based on specific platforms. The value
     * of this config is an object whose properties are "rules" and whose values are
     * objects containing config values.
     *
     * For example:
     *
     *      Ext.define('App.view.Foo', {
     *          extend: 'Ext.panel.Panel',
     *
     *          platformConfig: {
     *              desktop: {
     *                  title: 'Some Rather Descriptive Title'
     *              },
     *
     *              '!desktop': {
     *                  title: 'Short Title'
     *              }
     *          }
     *      });
     *
     * In the above, "desktop" and "!desktop" are (mutually exclusive) rules. Whichever
     * evaluates to `true` will have its configs applied to the class. In this case, only
     * the "title" property, but the object can contain any number of config properties.
     * In this case, the `platformConfig` is evaluated as part of the class and there is
     * not cost for each instance created.
     *
     * The rules are evaluated expressions in the context of the platform tags contained
     * in `{@link Ext#platformTags Ext.platformTags}`. Any properties of that object are
     * implicitly usable (as shown above).
     *
     * If a `platformConfig` specifies a config value, it will replace any values declared
     * on the class itself.
     *
     * Use of `platformConfig` on instances is handled by the config system when classes
     * call `{@link Ext.Base#initConfig initConfig}`. For example:
     *
     *      Ext.create({
     *          xtype: 'panel',
     *
     *          platformConfig: {
     *              desktop: {
     *                  title: 'Some Rather Descriptive Title'
     *              },
     *
     *              '!desktop': {
     *                  title: 'Short Title'
     *              }
     *          }
     *      });
     *
     * The following is equivalent to the above:
     *
     *      if (Ext.platformTags.desktop) {
     *          Ext.create({
     *              xtype: 'panel',
     *              title: 'Some Rather Descriptive Title'
     *          });
     *      } else {
     *          Ext.create({
     *              xtype: 'panel',
     *              title: 'Short Title'
     *          });
     *      }
     *
     * To adjust configs based on dynamic conditions, see `{@link Ext.mixin.Responsive}`.
     */
    ExtClass.registerPreprocessor('platformConfig', function(Class, data, hooks) {
        var platformConfigs = data.platformConfig,
            config = data.config,
            added, classConfigs, configs, configurator, hoisted, keys, name, value,
            i, ln;
 
        delete data.platformConfig;
 
        
        //<debug> 
        if (platformConfigs instanceof Array) {
            throw new Error('platformConfigs must be specified as an object.');
        }
        //</debug> 
 
        configurator = Class.getConfigurator();
        classConfigs = configurator.configs;
 
        // Get the keys shortest to longest (ish). 
        keys = Ext.getPlatformConfigKeys(platformConfigs);
 
        // To leverage the Configurator#add method, we want to generate potentially 
        // two objects to pass in: "added" and "hoisted". For any properties in an 
        // active platformConfig rule that set proper Configs in the base class, we 
        // need to put them in "added". If instead of the proper Config coming from 
        // a base class, it comes from this class's config block, we still need to 
        // put that config in "added" but we also need move the class-level config 
        // out of "config" and into "hoisted". 
        // 
        // This will ensure that the config defined at the class level is added to 
        // the Configurator first. 
        for (= 0, ln = keys.length; i < ln; ++i) {
            configs = platformConfigs[keys[i]];
            hoisted = added = null;
 
            for (name in configs) {
                value = configs[name];
 
                // We have a few possibilities for each config name: 
 
                if (config && name in config) {
                    //  It is a proper Config defined by this class. 
 
                    (added || (added = {}))[name] = value;
                    (hoisted || (hoisted = {}))[name] = config[name];
                    delete config[name];
                } else if (name in classConfigs) {
                    //  It is a proper Config defined by a base class. 
 
                    (added || (added = {}))[name] = value;
                } else {
                    //  It is just a property to put on the prototype. 
 
                    data[name] = value;
                }
            }
 
            if (hoisted) {
                configurator.add(hoisted);
            }
            if (added) {
                configurator.add(added);
            }
        }
    });
    //</feature> 
 
    //<feature classSystem.config> 
    /**
     * @cfg {Object} config 
     *
     * List of configuration options with their default values.
     *
     * __Note:__ You need to make sure {@link Ext.Base#initConfig} is called from your constructor if you are defining
     * your own class or singleton, unless you are extending a Component. Otherwise the generated getter and setter
     * methods will not be initialized.
     *
     * Each config item will have its own setter and getter method automatically generated inside the class prototype
     * during class creation time, if the class does not have those methods explicitly defined.
     *
     * As an example, let's convert the name property of a Person class to be a config item, then add extra age and
     * gender items.
     *
     *     Ext.define('My.sample.Person', {
     *         config: {
     *             name: 'Mr. Unknown',
     *             age: 0,
     *             gender: 'Male'
     *         },
     *
     *         constructor: function(config) {
     *             this.initConfig(config);
     *
     *             return this;
     *         }
     *
     *         // ...
     *     });
     *
     * Within the class, this.name still has the default value of "Mr. Unknown". However, it's now publicly accessible
     * without sacrificing encapsulation, via setter and getter methods.
     *
     *     var jacky = new Person({
     *         name: "Jacky",
     *         age: 35
     *     });
     *
     *     alert(jacky.getAge());      // alerts 35
     *     alert(jacky.getGender());   // alerts "Male"
     *
     *     jacky.walk(10);             // alerts "Jacky is walking 10 steps"
     *
     *     jacky.setName("Mr. Nguyen");
     *     alert(jacky.getName());     // alerts "Mr. Nguyen"
     *
     *     jacky.walk(10);             // alerts "Mr. Nguyen is walking 10 steps"
     *
     * Notice that we changed the class constructor to invoke this.initConfig() and pass in the provided config object.
     * Two key things happened:
     *
     *  - The provided config object when the class is instantiated is recursively merged with the default config object.
     *  - All corresponding setter methods are called with the merged values.
     *
     * Beside storing the given values, throughout the frameworks, setters generally have two key responsibilities:
     *
     *  - Filtering / validation / transformation of the given value before it's actually stored within the instance.
     *  - Notification (such as firing events) / post-processing after the value has been set, or changed from a
     *    previous value.
     *
     * By standardize this common pattern, the default generated setters provide two extra template methods that you
     * can put your own custom logics into, i.e: an "applyFoo" and "updateFoo" method for a "foo" config item, which are
     * executed before and after the value is actually set, respectively. Back to the example class, let's validate that
     * age must be a valid positive number, and fire an 'agechange' if the value is modified.
     *
     *     Ext.define('My.sample.Person', {
     *         config: {
     *             // ...
     *         },
     *
     *         constructor: {
     *             // ...
     *         },
     *
     *         applyAge: function(age) {
     *             if (typeof age !== 'number' || age < 0) {
     *                 console.warn("Invalid age, must be a positive number");
     *                 return;
     *             }
     *
     *             return age;
     *         },
     *
     *         updateAge: function(newAge, oldAge) {
     *             // age has changed from "oldAge" to "newAge"
     *             this.fireEvent('agechange', this, newAge, oldAge);
     *         }
     *
     *         // ...
     *     });
     *
     *     var jacky = new Person({
     *         name: "Jacky",
     *         age: 'invalid'
     *     });
     *
     *     alert(jacky.getAge());      // alerts 0
     *
     *     alert(jacky.setAge(-100));  // alerts 0
     *     alert(jacky.getAge());      // alerts 0
     *
     *     alert(jacky.setAge(35));    // alerts 0
     *     alert(jacky.getAge());      // alerts 35
     *
     * In other words, when leveraging the config feature, you mostly never need to define setter and getter methods
     * explicitly. Instead, "apply*" and "update*" methods should be implemented where necessary. Your code will be
     * consistent throughout and only contain the minimal logic that you actually care about.
     *
     * When it comes to inheritance, the default config of the parent class is automatically, recursively merged with
     * the child's default config. The same applies for mixins.
     */
    ExtClass.registerPreprocessor('config', function(Class, data) {
        // Need to copy to the prototype here because that happens after preprocessors 
        if (data.hasOwnProperty('$configPrefixed')) {
            Class.prototype.$configPrefixed = data.$configPrefixed;
        }
        Class.addConfig(data.config);
 
        // We need to remove this or it will be applied by addMembers and smash the 
        // "config" placed on the prototype by Configurator (which includes *all* configs 
        // such as cachedConfigs). 
        delete data.config;
    });
    //</feature> 
    
    //<feature classSystem.cachedConfig> 
    /**
     * @cfg {Object} cachedConfig 
     * 
     * This configuration works in a very similar manner to the {@link #config} option.
     * The difference is that the configurations are only ever processed when the first instance
     * of that class is created. The processed value is then stored on the class prototype and
     * will not be processed on subsequent instances of the class. Getters/setters will be generated
     * in exactly the same way as {@link #config}.
     * 
     * This option is useful for expensive objects that can be shared across class instances. 
     * The class itself ensures that the creation only occurs once.
     */
    ExtClass.registerPreprocessor('cachedConfig', function(Class, data) {
        // Need to copy to the prototype here because that happens after preprocessors 
        if (data.hasOwnProperty('$configPrefixed')) {
            Class.prototype.$configPrefixed = data.$configPrefixed;
        }
        Class.addCachedConfig(data.cachedConfig);
 
        // Remove this so it won't be placed on the prototype. 
        delete data.cachedConfig;
    });
    //</feature> 
 
    //<feature classSystem.mixins> 
    /**
     * @cfg {String[]/Object} mixins
     * List of classes to mix into this class. For example:
     *
     *     Ext.define('CanSing', {
     *          sing: function() {
     *              alert("For he's a jolly good fellow...")
     *          }
     *     });
     *
     *     Ext.define('Musician', {
     *          mixins: ['CanSing']
     *     })
     *
     * In this case the Musician class will get a `sing` method from CanSing mixin.
     *
     * But what if the Musician already has a `sing` method? Or you want to mix
     * in two classes, both of which define `sing`?  In such a cases it's good
     * to define mixins as an object, where you assign a name to each mixin:
     *
     *     Ext.define('Musician', {
     *          mixins: {
     *              canSing: 'CanSing'
     *          },
     * 
     *          sing: function() {
     *              // delegate singing operation to mixin
     *              this.mixins.canSing.sing.call(this);
     *          }
     *     })
     *
     * In this case the `sing` method of Musician will overwrite the
     * mixed in `sing` method. But you can access the original mixed in method
     * through special `mixins` property.
     */
    ExtClass.registerPreprocessor('mixins', function(Class, data, hooks) {
        //<debug> 
        Ext.classSystemMonitor && Ext.classSystemMonitor(Class, 'Ext.Class#mixinsPreprocessor', arguments);
        //</debug> 
        
        var mixins = data.mixins,
            onCreated = hooks.onCreated;
 
        delete data.mixins;
 
        hooks.onCreated = function() {
            //<debug> 
            Ext.classSystemMonitor && Ext.classSystemMonitor(Class, 'Ext.Class#mixinsPreprocessor#beforeCreated', arguments);
            //</debug> 
 
            // Put back the original onCreated before processing mixins. This allows a 
            // mixin to hook onCreated by access Class._classHooks. 
            hooks.onCreated = onCreated;
 
            Class.mixin(mixins);
 
            // We must go back to hooks.onCreated here because it may have changed during 
            // calls to onClassMixedIn. 
            return hooks.onCreated.apply(this, arguments);
        };
    });
    //</feature> 
 
 
    //<feature classSystem.backwardsCompatible> 
    // Backwards compatible 
    Ext.extend = function(Class, Parent, members) {
        //<debug> 
        Ext.classSystemMonitor && Ext.classSystemMonitor(Class, 'Ext.Class#extend-backwards-compatible', arguments);
        //</debug> 
            
        if (arguments.length === 2 && Ext.isObject(Parent)) {
            members = Parent;
            Parent = Class;
            Class = null;
        }
 
        var cls;
 
        if (!Parent) {
            throw new Error("[Ext.extend] Attempting to extend from a class which has not been loaded on the page.");
        }
 
        members.extend = Parent;
        members.preprocessors = [
            'extend'
            //<feature classSystem.statics> 
            ,'statics'
            //</feature> 
            //<feature classSystem.inheritableStatics> 
            ,'inheritableStatics'
            //</feature> 
            //<feature classSystem.mixins> 
            ,'mixins'
            //</feature> 
            //<feature classSystem.platformConfig> 
            ,'platformConfig'
            //</feature> 
            //<feature classSystem.config> 
            ,'config'
            //</feature> 
        ];
 
        if (Class) {
            cls = new ExtClass(Class, members);
            // The 'constructor' is given as 'Class' but also needs to be on prototype 
            cls.prototype.constructor = Class;
        } else {
            cls = new ExtClass(members);
        }
 
        cls.prototype.override = function(o) {
            for (var m in o) {
                if (o.hasOwnProperty(m)) {
                    this[m] = o[m];
                }
            }
        };
 
        return cls;
    };
    //</feature> 
 
    /**
     * This object contains properties that describe the current device or platform. These
     * values can be used in `{@link Ext.Class#platformConfig platformConfig}` as well as
     * `{@link Ext.mixin.Responsive#responsiveConfig responsiveConfig}` statements.
     *
     * This object can be modified to include tags that are useful for the application. To
     * add custom properties, it is advisable to use a sub-object. For example:
     *
     *      Ext.platformTags.app = {
     *          mobile: true
     *      };
     *
     * @property {Object} platformTags 
     * @property {Boolean} platformTags.phone
     * @property {Boolean} platformTags.tablet
     * @property {Boolean} platformTags.desktop
     * @property {Boolean} platformTags.touch Indicates touch inputs are available.
     * @property {Boolean} platformTags.safari
     * @property {Boolean} platformTags.chrome
     * @property {Boolean} platformTags.windows
     * @property {Boolean} platformTags.firefox
     * @property {Boolean} platformTags.ios True for iPad, iPhone and iPod.
     * @property {Boolean} platformTags.android
     * @property {Boolean} platformTags.blackberry
     * @property {Boolean} platformTags.tizen
     * @member Ext
     */
}());